XPath 选择多个 children 中 // 和 /descendant 之间的差异

Differences between // and /descendant in XPath selecting multiple children

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

鉴于此 HTML 片段

<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>

我需要 select 每个 input 基于其在 table 中的定位。 //div[@class='popupContent']//input[1] 这是第一个输入 select //div[@class='popupContent']//input[2] 这给出了 错误 //div[@class='popupContent']/descendant::input[1] 这又是第一个输入 select //div[@class='popupContent']/descendant::input[2]这个select第二个输入

使用 /descendant::input 做我需要的:获取所有输入并让我按位置 select。
// 有何不同?为什么它 return 只有第一个元素而不是后面的元素?

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

根据XPath 1.0, §2.5 Abbreviated Syntax

// is short for /descendant-or-self::node()/

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

  1. 转到具有该“popupContent”的 divs 的所有后代(children,children 的 children 等等)class,
  2. 然后寻找<input> children
  3. 最后 select 其 parent 的第一个 child ([1] 谓词)

div[@class='popupContent']//input[2] 非常相似,除了最后一件事是 select 第二个 child。 <input> 中的 none 是他们 parent 中的第二个 child。

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

  1. 使用 class、
  2. 转到 div 的所有后代
  3. select仅包含 <input> 个元素,并从中构建一个 node-set
  4. 最后 select node-set 中的第二个元素,按文档顺序

您可以在 §2.4 Predicates 中阅读有关谓词和轴的内容。相关作品:

(...) the ancestor, ancestor-or-self, preceding, and preceding-sibling axes are reverse axes; all other axes are forward axes.

[因此descendant是前轴。]

The proximity position of a member of a node-set with respect to an axis is defined to be the position of the node in the node-set ordered in document order if the axis is a forward axis (...). The first position is 1.

A predicate filters a node-set with respect to an axis to produce a new node-set. For each node in the node-set to be filtered, the PredicateExpr is evaluated with that node as the context node, with the number of nodes in the node-set as the context size, and with the proximity position of the node in the node-set with respect to the axis as the context position;

//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]

的缩写来解决这个问题