具有多个谓词等价的 xpath
xpath with multiple predicates equivalence
有人告诉我以下内容不一样:
a[1][@attr="foo"]
a[@attr="foo"][1]
有人可以解释为什么会这样吗?
将 XPath 表达式视为定义 结果集1 - 满足 XPath 表达式中规定的所有要求的一组节点. XPath 表达式的谓词([]
内的部分)要么对结果集没有影响,要么逐渐缩小结果集。
换句话说,在下面的表达式中:
//xyz[@abc="yes"]
[@abc="yes"]
减少定义在它左边的结果集,//xyz
。
请注意,正如 Michael Kay 所建议的,下面所说的所有内容仅适用于具有至少一个 positional 谓词的 XPath 表达式。位置谓词可以是一个数字:[1]
或评估为一个数字,或者包含 position()
或 last()
.
如果不存在位置谓词,则 XPath 表达式中的谓词顺序并不重要。
考虑以下简单的输入文档:
<root>
<a attr="other"/>
<a attr="foo"/>
<a attr="other"/>
<a attr="foo"/>
</root>
如您所见,a[@attr = 'foo']
不是 root
的第一个子元素。如果我们申请
//a[1]
本文档,这当然会导致
<a attr="other"/>
现在,至关重要的是,如果我们向表达式添加另一个谓词,如下所示:
//a[1][@attr="foo"]
那么,[@attr="foo"]
只能影响//a[1]
已经定义的结果集。在这个结果集中,没有a[@attr="foo"]
——最终结果为空
另一方面,如果我们从
开始
//a[@attr="foo"]
结果会是
<a attr="foo"/>
-----------------------
<a attr="foo"/>
在这种情况下,如果我们添加第二个谓词:
//a[@attr="foo"][1]
第二个谓词[1]
可以将//a[@attr="foo"]
的结果集缩小到只包含那些节点的第一个。
如果您了解 XSLT,您可能会发现这方面的 XSLT(和 XPath 2.0)证明很有帮助:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<result1>
<xsl:copy-of select="//a[1][@attr='foo']"/>
</result1>
<result2>
<xsl:copy-of select="//a[@attr='foo'][1]"/>
</result2>
</xsl:template>
</xsl:transform>
结果将是
<result1/>
<result2>
<a attr="foo"/>
</result2>
1 从技术上讲,只有 XPath 1.0 将此结果称为 node-set。在 XPath 2.0 中,所有集合都变成了 sequences 个节点。
有人告诉我以下内容不一样:
a[1][@attr="foo"]
a[@attr="foo"][1]
有人可以解释为什么会这样吗?
将 XPath 表达式视为定义 结果集1 - 满足 XPath 表达式中规定的所有要求的一组节点. XPath 表达式的谓词([]
内的部分)要么对结果集没有影响,要么逐渐缩小结果集。
换句话说,在下面的表达式中:
//xyz[@abc="yes"]
[@abc="yes"]
减少定义在它左边的结果集,//xyz
。
请注意,正如 Michael Kay 所建议的,下面所说的所有内容仅适用于具有至少一个 positional 谓词的 XPath 表达式。位置谓词可以是一个数字:[1]
或评估为一个数字,或者包含 position()
或 last()
.
如果不存在位置谓词,则 XPath 表达式中的谓词顺序并不重要。
考虑以下简单的输入文档:
<root>
<a attr="other"/>
<a attr="foo"/>
<a attr="other"/>
<a attr="foo"/>
</root>
如您所见,a[@attr = 'foo']
不是 root
的第一个子元素。如果我们申请
//a[1]
本文档,这当然会导致
<a attr="other"/>
现在,至关重要的是,如果我们向表达式添加另一个谓词,如下所示:
//a[1][@attr="foo"]
那么,[@attr="foo"]
只能影响//a[1]
已经定义的结果集。在这个结果集中,没有a[@attr="foo"]
——最终结果为空
另一方面,如果我们从
开始//a[@attr="foo"]
结果会是
<a attr="foo"/>
-----------------------
<a attr="foo"/>
在这种情况下,如果我们添加第二个谓词:
//a[@attr="foo"][1]
第二个谓词[1]
可以将//a[@attr="foo"]
的结果集缩小到只包含那些节点的第一个。
如果您了解 XSLT,您可能会发现这方面的 XSLT(和 XPath 2.0)证明很有帮助:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<result1>
<xsl:copy-of select="//a[1][@attr='foo']"/>
</result1>
<result2>
<xsl:copy-of select="//a[@attr='foo'][1]"/>
</result2>
</xsl:template>
</xsl:transform>
结果将是
<result1/>
<result2>
<a attr="foo"/>
</result2>
1 从技术上讲,只有 XPath 1.0 将此结果称为 node-set。在 XPath 2.0 中,所有集合都变成了 sequences 个节点。