XSLT:测试当前元素是否匹配变量 xpath
XSLT: Test if current element matches variable xpath
我有一个提供给模板的动态 xpath 字符串,我想测试当前元素是否与模板中的 xpath 匹配。
我试过使用 <xsl:evaluate/>
,但我不确定它的具体使用方式,或者它是否适合这项工作。
XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:functx="http://www.functx.com"
version="2.0">
<!-- HTML output -->
<xsl:output
method="text"
encoding="UTF-8"
omit-xml-declaration="yes"
standalone="yes"
indent="no"
media-type="string"/>
<xsl:template match="*">
<!-- This xpathMatches variable will be dynamically generated -->
<xsl:variable name="xpathMatches" select="'s4|s2[@class=''class1'']|d3'"/>
<xsl:apply-templates mode="test">
<xsl:with-param name="xpathMatches" select="$xpathMatches" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="test">
<xsl:param name="xpathMatches"/>
<xsl:variable name="xpathEval">
<xsl:evaluate xpath="$xpathMatches" context-item="."/>
</xsl:variable>
<!-- This doesn't work-->
<xsl:if test="$xpathEval">
<xsl:value-of select="name()"/>
</xsl:if>
</xsl:template>
</xsl:transform>
输入:
<div>
<s1 />
<s2 class="class1"/>
<s4 class="class7"/>
</div>
期望的输出:
s2
s4
由于 s2 和 s4 与 xpath 匹配,因此应该只返回那些元素名称。
但目前测试对所有元素都返回 true。
首先,xsl:evaluate是3.0新增的。您的样式表指定 2.0。这不会使其失败,但会造成混淆。
XSLT 1.0 和 2.0 不提供评估动态构造为字符串的 XPath 表达式的标准方法,尽管一些处理器为此目的提供了扩展函数。
这里使用xsl:evaluate
是正确的,错误的是你使用xsl:variable
。没有as
属性,xsl:variable
构造文档节点,文档节点的有效布尔值始终为真。您需要做的唯一更改是将 as="node()*"
添加到 xsl:variable
声明中。
== 稍后 ==
虽然代码现在可以做一些事情,但它并没有按照您所描述的要求进行:“测试当前元素是否与模板中的 xpath 匹配”。您的 XPath 表达式从上下文项向下 select 离子,因此它永远不会 select 上下文项本身。我想您真正想要的是将此表达式视为 XSLT 模式,并根据此模式测试上下文项。但是 XSLT 3.0 中没有工具可以匹配作为字符串动态提供的模式。
您在这里可以做的是测试上下文项 C 是否有某个祖先 A,当用作评估表达式的上下文项时,其结果中包含 C。为此,将表达式 $xpathMatches
:
换行
<xsl:evaluate xpath="'exists(ancestor-or-self::*!('
|| $xpathMatches ||
') intersect .)'"/>
如果您在匹配 div
的模板中处理事情,您需要
<xsl:template match="div">
<xsl:variable name="xpathMatches" select="'s4|s2[@class=''class1'']|d3'"/>
<xsl:variable name="matched-nodes" as="node()*">
<xsl:evaluate context-item="." xpath="$xpathMatches"/>
</xsl:variable>
<xsl:value-of select="$matched-nodes/name()" separator=" "/>
</xsl:template>
请注意,xsl:evaluate
是一项可选功能,您会发现它在 Saxon 10 所有版本、Saxon 9.8 和 9.9 PE 和 EE、Saxon-JS 2 和 Altova XML 2017 R3 和以后如果回忆对我有用的话。
在有限的情况下,当您想要 运行 样式表并且可以在编译 XSLT 之前使用和设置静态参数时,使用影子属性和静态参数可能就足够了:
<xsl:param name="xpathMatches" select="'s4|s2[@class=''class1'']|d3'" static="yes" as="xs:string"/>
<xsl:template match="div">
<xsl:value-of _select="({$xpathMatches})/name()" separator=" "/>
</xsl:template>
我有一个提供给模板的动态 xpath 字符串,我想测试当前元素是否与模板中的 xpath 匹配。
我试过使用 <xsl:evaluate/>
,但我不确定它的具体使用方式,或者它是否适合这项工作。
XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:functx="http://www.functx.com"
version="2.0">
<!-- HTML output -->
<xsl:output
method="text"
encoding="UTF-8"
omit-xml-declaration="yes"
standalone="yes"
indent="no"
media-type="string"/>
<xsl:template match="*">
<!-- This xpathMatches variable will be dynamically generated -->
<xsl:variable name="xpathMatches" select="'s4|s2[@class=''class1'']|d3'"/>
<xsl:apply-templates mode="test">
<xsl:with-param name="xpathMatches" select="$xpathMatches" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="test">
<xsl:param name="xpathMatches"/>
<xsl:variable name="xpathEval">
<xsl:evaluate xpath="$xpathMatches" context-item="."/>
</xsl:variable>
<!-- This doesn't work-->
<xsl:if test="$xpathEval">
<xsl:value-of select="name()"/>
</xsl:if>
</xsl:template>
</xsl:transform>
输入:
<div>
<s1 />
<s2 class="class1"/>
<s4 class="class7"/>
</div>
期望的输出:
s2
s4
由于 s2 和 s4 与 xpath 匹配,因此应该只返回那些元素名称。 但目前测试对所有元素都返回 true。
首先,xsl:evaluate是3.0新增的。您的样式表指定 2.0。这不会使其失败,但会造成混淆。
XSLT 1.0 和 2.0 不提供评估动态构造为字符串的 XPath 表达式的标准方法,尽管一些处理器为此目的提供了扩展函数。
这里使用xsl:evaluate
是正确的,错误的是你使用xsl:variable
。没有as
属性,xsl:variable
构造文档节点,文档节点的有效布尔值始终为真。您需要做的唯一更改是将 as="node()*"
添加到 xsl:variable
声明中。
== 稍后 ==
虽然代码现在可以做一些事情,但它并没有按照您所描述的要求进行:“测试当前元素是否与模板中的 xpath 匹配”。您的 XPath 表达式从上下文项向下 select 离子,因此它永远不会 select 上下文项本身。我想您真正想要的是将此表达式视为 XSLT 模式,并根据此模式测试上下文项。但是 XSLT 3.0 中没有工具可以匹配作为字符串动态提供的模式。
您在这里可以做的是测试上下文项 C 是否有某个祖先 A,当用作评估表达式的上下文项时,其结果中包含 C。为此,将表达式 $xpathMatches
:
<xsl:evaluate xpath="'exists(ancestor-or-self::*!('
|| $xpathMatches ||
') intersect .)'"/>
如果您在匹配 div
的模板中处理事情,您需要
<xsl:template match="div">
<xsl:variable name="xpathMatches" select="'s4|s2[@class=''class1'']|d3'"/>
<xsl:variable name="matched-nodes" as="node()*">
<xsl:evaluate context-item="." xpath="$xpathMatches"/>
</xsl:variable>
<xsl:value-of select="$matched-nodes/name()" separator=" "/>
</xsl:template>
请注意,xsl:evaluate
是一项可选功能,您会发现它在 Saxon 10 所有版本、Saxon 9.8 和 9.9 PE 和 EE、Saxon-JS 2 和 Altova XML 2017 R3 和以后如果回忆对我有用的话。
在有限的情况下,当您想要 运行 样式表并且可以在编译 XSLT 之前使用和设置静态参数时,使用影子属性和静态参数可能就足够了:
<xsl:param name="xpathMatches" select="'s4|s2[@class=''class1'']|d3'" static="yes" as="xs:string"/>
<xsl:template match="div">
<xsl:value-of _select="({$xpathMatches})/name()" separator=" "/>
</xsl:template>