通过动态求值的XPath测试表达式选择XML文档的一部分



我的一项看似简单的任务失败了。

我有一个定义不同场景的配置文件。每个场景都有一个测试表达式。其思想是,场景中的指令应应用于与测试表达式匹配的输入文档。例如:

<config>
<scenario test="/input/@id eq 'X'">
...
</scenario>
<scenario test="/input/@id eq 'Y'">
...
</scenario>
</config>

我的问题是:对于给定的输入文件,如何识别匹配的场景?

让$d是一个带有某个文档节点的变量。我可以通过写$d[P]来检查它是否与模式P匹配。所以我尝试了之类的东西

let $p:=doc("config.xml")/config/scenario/@test,
$d:=doc("input.xml")
return $d[$p] 

当且仅当输入Document$I与测试模式$p匹配时,我期望一个非空序列。但是,无论@test属性是什么,表达式的结果都不会为空。即使只有一个场景的测试表达式与确定性不匹配。

提前感谢,Frank

在您的示例中,变量$p是一系列属性,当您在谓词中使用该$p时,它会被转换为布尔值,就像通过boolean()函数一样。XPath规范说:

如果其操作数是第一项为节点的序列,则fn:boolean返回true。

因此,如果您的配置文件有任何测试场景,那么谓词将返回true。

您需要做的是评估该表达式。

XPath评估可以在XSLT3.0中使用xsl:evaluate:完成

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all"
version="3.0">
<xsl:function name="mf:evaluate-predicate" as="item()*">
<xsl:param name="context-item" as="item()"/>
<xsl:param name="predicate" as="xs:string"/>
<xsl:evaluate context-item="$context-item" xpath="'.[' || $predicate || ']'"/>
</xsl:function>

<xsl:template match="/input[some $pred in $config/config/scenario/@test satisfies mf:evaluate-predicate(., $pred)]">
<xsl:copy-of select="."/>
</xsl:template>

<xsl:param name="config" select="doc('config.xml')"/>
</xsl:stylesheet>

xsl:evaluate是一个可选功能,它在早期的XSLT3 Saxon HE版本(即9.8和9.9(中不受支持,但在Saxon HE10和11中受支持(当然,从9.8开始在PE/EE中也受支持(。它在SaxonJS 2中也受支持。

最新更新