在 XSLT 1.0 中,我正在创建一个其中包含 select 语句的变量。这样做的目的是在变量中处理一次逻辑。然后使用该变量作为布尔下游一次或多次来控制逻辑流程。问题在于,无论变量内的逻辑计算结果为 true() 还是 false(),该变量在测试构造中始终计算结果为 true()。
那么,我可以通过这种方式创建一个布尔变量吗?如果是这样,我应该如何做并在下游使用它?
我的输入 XML 如下:
<root>
<box id="435" type="A">keep</box>
<box id="872" type="A"></box>
<box id="903" type="B">keep</box>
<box id="1051" type="A">keep</box>
</root>
我的预期结果是一样的:
<root>
<box id="435" type="A">keep</box>
<box id="872" type="A"></box>
<box id="903" type="B">keep</box>
<box id="1051" type="A">keep</box>
</root>
但我的实际结果是:
<root>
<box id="435" type="A">keep</box>
<box id="903" type="B">keep</box>
<box id="1051" type="A">keep</box>
</root>
我的编程尝试是:
<xsl:key name = "myKey" match="box" use="local-name()"/>
<xsl:variable name="allMustMatch" select="'true'"/>
<xsl:variable name="processFlag">
<xsl:choose>
<xsl:when test="$allMustMatch = 'true'">
<xsl:variable name="allCount" select="count(key('myKey', 'box'))"/>
<xsl:variable name="typeCount" select="count(key('myKey', 'box')[not(@type = preceding::box/@type)]) + 1"/>
<xsl:value-of select="$allCount = $typeCount"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="true()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:template match="box">
<xsl:choose>
<!-- When $processFlag is false(), the following test evaluates to true().
Also, when boolean($processFlag) is false(), the test evaluates to true().
And when $processFlag is true() the test evaluates to true().
How can I use $processFlag as a boolean? Or can I? -->
<xsl:when test="boolean($processFlag)">
<xsl:if test="normalize-space(.) != ''">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Identity template. -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
考虑这个简单的例子:
<xsl:template match="/">
<xsl:variable name="test">
<xsl:value-of select="1=2"/>
</xsl:variable>
<xsl:value-of select="boolean($test)"/>
</xsl:template>
这里的结果将是
true
。为什么?因为根据定义,该变量包含一个字符串值为 "true"
的文本节点 - 并且任何长度非零的字符串都会被评估为 true
。
如果,OTOH,您将变量定义为:
<xsl:variable name="test" select="1=2"/>
那么变量会直接指向布尔值,结果会不同。
注意将变量定义为:
<xsl:variable name="allMustMatch" select="'true'"/>
还将变量绑定到字符串,并且这两个:
<xsl:variable name="allMustMatch" select="'false'"/>
将在布尔测试中评估为
true
。将变量绑定到布尔值的正确方法是:
<xsl:variable name="allMustMatch" select="true()"/>
或:
<xsl:variable name="allMustMatch" select="false()"/>
现在的问题是,当需要导出值时,如何将变量绑定到布尔值,例如通过使用
xsl:choose
。答案是不可能(在 XSLT 1.0 中)。你最多能做的就是:
<xsl:variable name="test">
<xsl:choose>
<xsl:when test="1=2">1</xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
然后,当您需要评估变量时,请执行以下操作:
<xsl:if test="number($test)">
但是,我不相信您的示例中需要如此复杂的构造。我不确定我是否遵循此处所需的逻辑,但您可能可以执行类似的操作(未经测试):
<xsl:variable name="allCount" select="count(key('myKey', 'box'))"/>
<xsl:variable name="typeCount" select="count(key('myKey', 'box')[not(@type = preceding::box/@type)]) + 1"/>
<xsl:variable name="processFlag" select="$allCount = $typeCount[$allMustMatch] + not($allMustMatch)">
这里的变量绑定到一个数字,在布尔测试中,如果为零,则计算结果为
false
,否则为 true
。