XSLT 3.0如何在apply-templates中用变量动态选择节点?
解决动态构造
xsl:apply-templates的select路径问题 这个问题我之前也碰到过,你原来的写法foo/bar/$x之所以无效,是因为XPath语法里不能直接把字符串变量当作节点名使用——$x在这里是字符串值,不是合法的节点测试。针对Saxon-HE 9.8,这里有几个可行的解决方案:
方案1:用节点名称匹配(最稳妥,兼容XSLT 2.0)
如果你的变量$x只是节点的本地名称,直接用local-name()函数匹配即可,这是兼容性最好的方法,不需要依赖扩展或高版本特性:
<xsl:variable name="x" select="'baz'"/> <!-- 匹配foo/bar下本地名称等于$x的所有节点 --> <xsl:apply-templates select="foo/bar/*[local-name() = $x]"/>
如果你的XML涉及命名空间,还可以加上namespace-uri()的判断来精准匹配:
<xsl:variable name="x" select="'baz'"/> <xsl:variable name="target-namespace" select="'http://your-target-namespace.com'"/> <xsl:apply-templates select="foo/bar/*[local-name() = $x and namespace-uri() = $target-namespace]"/>
方案2:用XSLT 3.0的xsl:evaluate(动态构造完整XPath)
Saxon-HE 9.8已经支持XSLT 3.0的核心特性,如果你需要构造更复杂的动态路径(比如变量是路径的多个部分),可以用xsl:evaluate函数来动态执行XPath表达式:
首先确保样式表声明为3.0版本:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:variable name="x" select="'baz'"/> <!-- 动态拼接XPath并执行 --> <xsl:apply-templates select="xsl:evaluate(concat('foo/bar/', $x))"/> </xsl:stylesheet>
注意:使用xsl:evaluate时要注意XPath注入风险,如果$x的内容来自不可信源,需要做校验。
方案3:Saxon扩展函数(仅PE/EE版本可用)
如果你的环境是Saxon PE或EE版本(HE版本不支持),可以用Saxon的扩展函数saxon:evaluate来实现动态XPath:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" exclude-result-prefixes="saxon"> <xsl:variable name="x" select="'baz'"/> <xsl:apply-templates select="saxon:evaluate(concat('foo/bar/', $x))"/> </xsl:stylesheet>
但因为你用的是HE版本,这个方案就不适用了,优先考虑前两种。
内容的提问来源于stack exchange,提问作者shawn
相关产品推荐
相关产品推荐

