2

XSLT 1.0で文字列をトークン化し、空の文字列がトークンとして認識されないようにしようとしています。XSLTクックブックに基づく関数全体は次のとおりです。

<xsl:template name="tokenize">
    <xsl:param name="string" select="''" />
    <xsl:param name="delimiters" select="';#'" />
    <xsl:param name="tokensplitter" select="','" />
    <xsl:choose>
        <!-- Nothing to do if empty string -->
        <xsl:when test="not($string)" />

        <!-- No delimiters signals character level tokenization -->
        <xsl:when test="not($delimiters)">
            <xsl:call-template name="_tokenize-characters">
                <xsl:with-param name="string" select="$string" />
                <xsl:with-param name="tokensplitter" select="$tokensplitter" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:call-template name="_tokenize-delimiters">
                <xsl:with-param name="string" select="$string" />
                <xsl:with-param name="delimiters" select="$delimiters" />
                <xsl:with-param name="tokensplitter" select="$tokensplitter" />
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template name="_tokenize-characters">
    <xsl:param name="string" />
    <xsl:param name="tokensplitter" />
    <xsl:if test="$string">
        <token><xsl:value-of select="substring($string, 1, 1)"/></token>
        <xsl:call-template name="_tokenize-characters">
            <xsl:with-param name="string" select="substring($string, 2)" />
        </xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template name="_tokenize-delimiters">
    <xsl:param name="string" />
    <xsl:param name="delimiters" />
    <xsl:param name="tokensplitter" />

    <!-- Extract a delimiter -->
    <xsl:variable name="delimiter" select="substring($delimiters, 1, 1)"/>
    <xsl:choose>
        <!-- If the delimiter is empty we have a token -->
        <xsl:when test="not($delimiter) and $string != ''">
            <xsl:text>£</xsl:text>
            <token><xsl:value-of select="$string"/></token>
            <xsl:text>$</xsl:text>
            <xsl:value-of select="$tokensplitter"/>
        </xsl:when>
        <!-- If the string contains at least one delimiter we must split it -->
        <xsl:when test="contains($string, $delimiter)">
            <!-- If it starts with the delimiter we don't need to handle the before part -->
            <xsl:if test="not(starts-with($string, $delimiter))">
                <!-- Handle the part that comes before the current delimiter with the next delimiter. -->
                <!-- If there is no next the first test in this template will detect the token. -->
                <xsl:call-template name="_tokenize-delimiters">
                    <xsl:with-param name="string" select="substring-before($string, $delimiter)" />
                    <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
                    <xsl:with-param name="tokensplitter" select="$tokensplitter" />
                </xsl:call-template>
            </xsl:if>
            <!-- Handle the part that comes after the delimiter using the current delimiter -->
            <xsl:call-template name="_tokenize-delimiters">
                <xsl:with-param name="string" select="substring-after($string, $delimiter)" />
                <xsl:with-param name="delimiters" select="$delimiters" />
                <xsl:with-param name="tokensplitter" select="$tokensplitter" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <!-- No occurrences of current delimiter so move on to next -->
            <xsl:call-template name="_tokenize-delimiters">
                <xsl:with-param name="string" select="$string" />
                <xsl:with-param name="delimiters" select="substring($delimiters, 2)" />
                <xsl:with-param name="tokensplitter" select="$tokensplitter" />
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

string私が渡しているその値は次のとおりです。

ヨーロッパ;#6; #Global;#3; #Middle East、Africa and Caucasus; 2; #Europe;#6; #Global;#3; #Middle East、Africa and Caucasus

£$インジケーターはそこにあるので、空の文字列が出力されていないことがわかります。これはSharePoint内にあるため、デバッグが困難です。)

このコードは、XSLTの処理をハングさせます。問題の原因となっている行は<xsl:when test="not($delimiter) and $string != ''">です。2番目のテストを削除するとすぐに、and再び機能します。私もand string($string)成功せずに試しました。

なぜこれが起こっているのか、そしてそれを解決する方法を知っている人はいますか?

4

2 に答える 2

4

私の疑惑は正しかったと思います。あなたが言うように、あなたは値を持っている<xsl:otherwise>ときにあなたの条項に陥っていますが、そうではなく、無限ループを引き起こしています。$string$delimiter

<xsl:when>最初の句の後に次の新しい句を追加します。

    <xsl:when test="not($delimiter) and $string = ''" />

<xsl:otherwise>これにより、実行がブロックに入るのを防ぐことができます。


何が起こっているのか、なぜループしているのかについてのより詳細な説明:

ブロックには3つのブランチがあり<xsl:choose>ます。

    <xsl:when test="not($delimiter) and $string != ''">
    <xsl:when test="contains($string, $delimiter)">
    <xsl:otherwise>

したがって、値$string$delimiter含まれていない場合、最初の条件は失敗します($string != ''falseであるため)。2番目の条件は合格し(contains(nil,nil)常にtrueを返すため(Visual Studioで確認済み))、同じパラメーターを使用してテンプレートを再度呼び出します(substring-before空の区切り文字が含まれていないため、は空の文字列を返すため)。エルゴ、無限ループ。

修正は、新しい空の条件を追加することです。

    <xsl:when test="not($delimiter) and $string != ''">
    <xsl:when test="not($delimiter) and $string = ''" />
    <xsl:when test="contains($string, $delimiter)">
    <xsl:otherwise>

編集:私はざっと見てcontains、2番目のパラメーターが空またはnilのときの定義された動作への参照を見つけることができません。trueテストによると、2番目のパラメーターが空またはnilの場合、MicrosoftVisualStudioのXSLTエンジンが返されます。それが定義された動作なのか、それとも実装者が決定するのかはわかりません。誰かがこれに対する決定的な答えを持っていますか?トマラック、私はあなたを見ています。

于 2009-11-16T17:09:01.173 に答える
0

string予約語ではありませんか?その名前を他の名前に置き換えてみてください。

編集:提供されたコードはここで問題なく実行されました:XSLT Tryit Editor v1.0使用:

<xsl:call-template name="tokenize">
   <xsl:with-param name="string">Europe;#6;#Global...</xsl:with-param>
</xsl:call-template>
于 2009-11-16T16:44:22.143 に答える