@select与if和嵌套<xsl:choice>之间的区别?</xsl:choice>

时间:2014-03-21 14:02:11

标签: xml xslt xpath xslt-2.0 xpath-2.0

为什么以下两个变量定义的行为应该有所不同?

第一个定义使用XPath 2和if语句:

<xsl:variable name="content" select="if ($next-divm)
    then (./following-sibling::node() intersect $next-divm/preceding-sibling::node())
    else (./following-sibling::node())"/>

第二个定义使用<xsl:choose>来达到相同的结果(或者我认为):

<xsl:variable name="content1">
    <xsl:choose>
        <xsl:when test="$next-divm">
            <xsl:copy-of select="./following-sibling::node() intersect $next-divm/preceding-sibling::node()"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="./following-sibling::node()"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

但是,当使用

输出$content时,这两种技术会导致两种不同的结果
<xsl:apply-templates select="$content" mode="keep"/>

在第一种情况下,所有内容都被正确复制(即保留所有元素和文本节点),而在后者中仅保留文本节点。这种奇怪的行为可能与以下其他两个模板相关联。

<xsl:template match="node()[not(self::divm)][./preceding-sibling::divm]"/>

<xsl:template match="node()[not(self::divm)][./preceding-sibling::divm]" mode="keep">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" mode="keep"/>
    </xsl:copy>
</xsl:template>

无论我的具体模板如何,我都想知道为什么这两种<xsl:variable>样式会导致不同的结果。

1 个答案:

答案 0 :(得分:5)

XPath if从输入返回原始节点,仍然附加到输入树中的原始上下文。 choose版本返回节点,这些节点是输入节点的副本,当您从这些节点导航preceding-sibling::轴时,您就是只查看变量中的临时树,而不是源XML中节点的原始上下文。

如果要捕获原始节点而不是xsl:choose变体中的副本,请使用xsl:sequence代替xsl:copy-of。您还需要通过添加as="node()*"之类的内容来输入变量。 Section 9.4 of the XSLT 2.0 spec解释了为什么(我的大胆):

  

在评估具有非空内容且没有xsl:variable属性的xsl:paramxsl:with-paramas元素时,会隐式创建文档节点即可。 [...]变量的值是单节点,即临时树的文档节点。文档节点的内容由评估序列构造函数

的结果形成

如果您提供as="node()*",那么序列构造函数生成的节点(即xsl:variable元素的内容)将按原样使用,而不是形成内容一个新的隐式文档节点。