無限のループでテスト垂れ下がっているとき
-
20-09-2019 - |
質問
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、アフリカ、コーカサス
( £
と $
インジケーターがそこにあるので、空の文字列が出力されないことがわかります。これはSharePoint内にあるので、デバッグするのは困難です。)
このコードは、XSLTの処理をハングアップします。問題を引き起こす線は次のとおりです <xsl:when test="not($delimiter) and $string != ''">
. 。 2番目を削除するとすぐに and
テストは再度動作します。私も試しました and string($string)
成功せずに。
なぜこれが起こっているのか、そしてそれを解決する方法を知っていますか?
解決
私の疑いは正しかったと信じています:あなたはあなたに落ちています <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 != ''
偽です)。 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の場合。テストでは、Microsoft Visual StudioのXSLTエンジンが戻ってきたことが示されています true
2番目のパラメーターが空またはnilの場合。それが定義された動作なのか、それとも決定するのが実装者次第かどうかはわかりません。誰かがこれに対して決定的な答えを持っていますか?トマラク、私はあなたを見ています。
他のヒント
そうではありません 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>