XPath 中选择多个子项的 // 和 /descendant 之间的区别

Posted

技术标签:

【中文标题】XPath 中选择多个子项的 // 和 /descendant 之间的区别【英文标题】:Differences between // and /descendant in XPath selecting multiple children 【发布时间】:2016-02-28 07:57:39 【问题描述】:

在 XPath 中选择基本元素的多个子元素时,我无法清楚地理解使用 //element/descendant::element 之间的区别。

鉴于这个 html sn-p

<html>
<body>
<div class="popupContent">
  <table>
    <tr class="aclass"><td> Hello </td> <td> <input type="text" value="FIRST" /> </td></tr>
    <tr class="aclass"><td> Goodbye </td> <td> <input type="text" value="SECOND" /> </td></tr>
  </table>
</div>
</body>
</html>

我需要根据其在表格中的位置选择每个input//div[@class='popupContent']//input[1] 选择第一个输入 //div[@class='popupContent']//input[2] 这给出了 错误 //div[@class='popupContent']/descendant::input[1] 这再次选择第一个输入 //div[@class='popupContent']/descendant::input[2]这个选择第二个输入

使用/descendant::input 可以满足我的需要:获取所有输入并让我按位置进行选择。// 有何不同?为什么它只返回第一个元素而不返回后面的元素?

我知道this other question,但答案基本上说它们是别名并指向文档,我无法理解并且缺乏具体示例。与那个问题的不同之处在于我需要选择多个子元素,而// 不允许这样做。

【问题讨论】:

第一个表达式 //div[@class='popupContent']//input[1] 返回两个输入。 What's the difference between //node and /descendant::node in xpath?的可能重复 @RobertColumbia 正如我在问题本身中提到的,我要求做出不同的澄清。 【参考方案1】:

根据XPath 1.0, §2.5 Abbreviated Syntax:

///descendant-or-self::node()/ 的缩写

所以div[@class='popupContent']//input[1](与div[@class='popupContent']/descendant-or-self::node()/child::input[1]相同)将:

    使用该“popupContent”类访问divs 的所有后代(孩子、孩子的孩子等), 然后寻找&lt;input&gt;children 最后选择其父级的第一个子级([1] 谓词)

div[@class='popupContent']//input[2] 非常相似,除了最后一件事是选择第二个孩子。 并且没有一个&lt;input&gt;s 是他们父母的第二个孩子。

另一方面,div[@class='popupContent']/descendant::input[2] 会:

    转到divs 的所有后代与该类, 只选择&lt;input&gt; 元素,并从中构建一个节点集 最后按文档顺序选择该节点集中的第二个元素

您可以在§2.4 Predicates 中阅读有关谓词和轴的信息。相关文章:

(...) 祖先、祖先或自我、前面和前面的兄弟轴是反向轴; 所有其他轴都是正向轴

[因此descendant 是一个正向轴。]

节点集成员的接近位置相对于轴被定义为节点在节点集中按文档顺序排序的位置如果轴是一个正轴 (...)。第一个位置是 1。

谓词过滤一个关于轴的节点集以产生一个新的节点集。对于要过滤的节点集中的每个节点,以该节点作为上下文节点评估PredicateExpr,以节点集中的节点数作为上下文大小,并以的接近位置为节点集中的节点相对于轴作为上下文位置;

【讨论】:

【参考方案2】:

//X/descendant::X 之间的唯一区别是 X 包含位置谓词时,例如 //x[1]/descendant::x[1]。在这种情况下,//x[1] 选择作为其父元素的第一个 x 子元素的每个 x 元素,而 /descendant::x[1] 选择整体上的第一个后代 x。你可以通过记住//x[1]/descendant-or-self::node()/child::x[1] 的缩写来解决这个问题

【讨论】:

以上是关于XPath 中选择多个子项的 // 和 /descendant 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

通过 XPath Sales Navigator 访问元素列表中的子项

使用 XPath 和 WebBrowser 控件选择多个节点

xpath

如何使用 XPath 选择以下同级/XML 标记

xpath选择兄弟节点返回上一级和选择多个属性

在 C# 中使用 xpath 选择具有不同类的多个 div 节点