XPath方括号[1]运算符返回意外结果,求解析其工作逻辑
XPath中
[1]谓词的工作机制解析 测试场景1:嵌套结构XML
<foo> <bar id="aaa"/> <jam> <bar id="bbb"/> </jam> </foo>
尝试查找文档中的第一个<bar>元素,测试结果如下:
| Test# | XPath表达式 | 求值表达式 | 结果 |
|---|---|---|---|
| 1 | //bar | @id | aaa, bbb |
| 2 | //bar[1] | @id | aaa, bbb |
| 3 | (//bar)[1] | @id | aaa |
我无法理解Test#2为何返回aaa和bbb而非仅aaa,仿佛[1]运算符未生效。我原以为//bar找到所有节点后,[1]会选中第一个,显然我遗漏了某些细节。Test#3的表达式(//bar)[1]才符合预期结果。
测试场景2:同层级结构XML
<foo> <bar id="aaa"/> <bar id="bbb"/> </foo>
测试结果则符合预期:
| Test# | XPath表达式 | 求值表达式 | 结果 |
|---|---|---|---|
| 1 | //bar | @id | aaa, bbb |
| 2 | //bar[1] | @id | aaa |
| 3 | (//bar)[1] | @id | aaa |
核心细节解析
问题的关键在于XPath谓词([])的作用范围,以及//的实际执行逻辑:
//bar[1]的执行逻辑//等价于/descendant-or-self::node()/,会遍历文档中所有节点,然后筛选出bar元素。但[1]是作用在每个父节点的子节点集合上,而不是全局所有bar的集合。
在第一个嵌套XML中:<foo>节点下的第一个bar是id="aaa"的元素,满足bar[1];<jam>节点下的第一个(也是唯一)bar是id="bbb"的元素,同样满足bar[1];
因此//bar[1]会同时匹配这两个元素,返回两个结果。
(//bar)[1]的执行逻辑
括号改变了运算优先级,先执行//bar获取全局所有bar元素的完整集合,之后[1]作用在这个全局集合上,直接选中集合中的第一个元素,也就是id="aaa"的bar,所以只返回一个结果。同层级XML的特殊情况
第二个XML中两个bar同属<foo>节点的子节点,此时//bar[1]只会筛选出<foo>下的第一个bar(id="aaa"),因此和(//bar)[1]的结果一致。
内容的提问来源于stack exchange,提问作者Archie
相关产品推荐
相关产品推荐

