为什么以下两个变量定义的行为应该有所不同?
第一个定义使用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>
样式会导致不同的结果。
答案 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:param
,xsl:with-param
或as
元素时,会隐式创建文档节点即可。 [...]变量的值是单节点,即临时树的文档节点。文档节点的内容由评估序列构造函数
如果您做提供as="node()*"
,那么序列构造函数生成的节点(即xsl:variable
元素的内容)将按原样使用,而不是形成内容一个新的隐式文档节点。