我正在用XSLT 1.0标记字符串,并试图阻止空字符串被识别为标记。这是整个函数,基于XSLT Cookbook:
<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, 非洲和 高加索; 2; #Europe;#6; #Global;#3; #Middle 东部,非洲和高加索
(£
和$
指标就在那里,所以我看不到输出空字符串。这在SharePoint中很难调试。)
此代码挂起XSLT的处理。导致问题的一行是<xsl:when test="not($delimiter) and $string != ''">
。一旦我删除第二个and
测试,它就会再次运行。我也试过and string($string)
但没有成功。
任何人都知道为什么会这样,以及如何解决它?
答案 0 :(得分:4)
我相信我的怀疑是正确的:当<xsl:otherwise>
有值时,你会落入$string
子句,但$delimiter
没有,导致无限循环,如你所说
在第一个之后添加以下新<xsl:when>
子句:
<xsl:when test="not($delimiter) and $string = ''" />
这将阻止执行进入<xsl:otherwise>
块时不应该。
更详细地解释发生了什么以及为什么循环:
<xsl:choose>
块中有三个分支。
<xsl:when test="not($delimiter) and $string != ''">
<xsl:when test="contains($string, $delimiter)">
<xsl:otherwise>
因此,当$string
和$delimiter
都不包含值时,第一个条件失败(因为$string != ''
为false)。第二个条件通过(因为contains(nil,nil)
总是返回true(在Visual Studio中确认)),它使用相同的参数再次调用模板(因为substring-before
返回空字符串,因为它不包含空分隔符)。 Ergo,一个无限循环。
修复是添加一个新的空条件:
<xsl:when test="not($delimiter) and $string != ''">
<xsl:when test="not($delimiter) and $string = ''" />
<xsl:when test="contains($string, $delimiter)">
<xsl:otherwise>
contains
的已定义行为的引用。测试表明,当第二个参数为空或为零时,Microsoft Visual Studio的XSLT引擎返回true
。我不确定这是定义的行为还是由实施者来决定。有没有人对此有明确的答案?托马拉克,我在看着你。
答案 1 :(得分: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>