当前选择的答案是错误的。
事实上,//someExpression[2]
可以选择多个节点。
例如,如果我们有以下 XML 文档:
<lib:library xmlns:lib="UNDEFINED!!!">
<topic name="XML">
<lib:book> XML </lib:book>
</topic>
<topic name="XPath">
<lib:book> XPath </lib:book>
</topic>
<topic name="XSLT">
<lib:book> XSLT1 </lib:book>
<lib:book> XSLT2 </lib:book>
</topic>
<topic name="Imperative PLs">
<lib:book> Java </lib:book>
<lib:book> C++ </lib:book>
</topic>
</lib:library>
当表达式为:
//*[local-name() = "book"][2]
在与上面的文档进行比较时,选择了两个节点(但它们都不是文档中具有所需属性的第二个节点):
<lib:book xmlns:lib="UNDEFINED!!!"> XSLT2 </lib:book>
<lib:book xmlns:lib="UNDEFINED!!!"> C++ </lib:book>
解决方案:选择整个文档中第N(例如第二个)个节点(例如lib:book
)的一种方法是:
(//*[local-name() = "book"])[2]
当对上述文档进行此表达式评估时,将选择正确的单个节点:
<lib:book xmlns:lib="UNDEFINED!!!"> XPath </lib:book>
说明: 根据
W3C XPath建议的定义:
//
缩写为/descendant-or-self::node()/
因此:
//someName[2]
是以下内容的简写:
/descendant-or-self::node()/someName[2]
这会选择文档中名称为someName
并且是其父级的第二个someName
子元素的任何元素。
换句话说,[]
操作符比//
伪操作符绑定得更强(优先级更高)。这就是为什么我们需要使用方括号来覆盖默认操作符优先级。