Saxon HE下generate-id()在节点集变量赋值后失效问题求助
问题原因
当你用<xsl:variable>的内容体(而非select属性)包裹模板调用时,模板输出的节点会被构造为**临时树(temporary tree)**的节点——这些是原文档节点的副本,而非原节点本身的引用。因此,副本节点的generate-id()会和原节点完全不同,导致匹配条件不成立,输出空结果。
而第一个示例中,变量通过select直接选取原文档节点,保存的是原节点的引用,generate-id()一致,所以匹配成功。
解决方案
以下是几种更简洁的解决方法:
1. 给变量指定节点序列类型,保留原节点引用
修改变量定义,添加as="element()*"(或更具体的类型),确保变量保存原节点的序列而非临时树副本:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.0"> <xsl:output indent="true"/> <xsl:template match="/"> <!-- 指定变量类型为元素序列,保留原节点引用 --> <xsl:variable name="foo" as="element()*"> <xsl:call-template name="getA"/> </xsl:variable> <root> <!-- 直接用is运算符判断节点同一性,比generate-id更可靠 --> <xsl:sequence select="root/a[. is $foo]"/> </root> </xsl:template> <xsl:template name="getA"> <xsl:sequence select="root/a[1]"/> </xsl:template> </xsl:stylesheet>
2. 使用XSLT 3.0函数替代模板,直接获取原节点
将模板改为函数,可直接在变量的select属性中调用,避免临时树的创建:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="http://example.com/my" exclude-result-prefixes="xs my" version="3.0"> <xsl:output indent="true"/> <xsl:function name="my:getA" as="element()*"> <xsl:sequence select="root/a[1]"/> </xsl:function> <xsl:template match="/"> <xsl:variable name="foo" select="my:getA()"/> <root> <xsl:sequence select="root/a[. is $foo]"/> </root> </xsl:template> </xsl:stylesheet>
3. 直接使用is运算符判断节点同一性
无论哪种方式,都推荐用is运算符替代generate-id()来判断节点是否为同一实例——这是XSLT原生的节点同一性判断方式,比依赖generate-id()更准确、高效。
验证结果
修改后的代码会正确输出原节点:
<root> <a oid="1" title="foo"/> </root>
内容的提问来源于stack exchange,提问作者MrD at KookerellaLtd
相关产品推荐
相关产品推荐

