Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
167 views
in Technique[技术] by (71.8m points)

parent child - Differences between // and /descendant in XPath selecting multiple children

I can't clearly understand the differences between using //element and /descendant::element when selecting multiple children of a base element in XPath.

Given this HTML snippet

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

I need to select each input based on its positioning in the table. //div[@class='popupContent']//input[1] this selects the first input //div[@class='popupContent']//input[2] this gives error //div[@class='popupContent']/descendant::input[1] this again selects the first input //div[@class='popupContent']/descendant::input[2] this select the second input

Using /descendant::input does what I need: grab all inputs and let me select by position.
How does // differ? Why does it return only the first element and not the ones after?

I'm aware of this other question but the answer basically says they're aliases and point to the documentation, which I cannot understand and lacks a concrete example. Difference with that question is that my need is to select multiple children elements, and // doesn't allow it.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

According to XPath 1.0, §2.5 Abbreviated Syntax:

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

So div[@class='popupContent']//input[1] (same as div[@class='popupContent']/descendant-or-self::node()/child::input[1]) will:

  1. go to all descendants (children, children of children and so on) of the divs with that "popupContent" class,
  2. then look for <input> children
  3. and finally select the first child of its parent ([1] predicate)

div[@class='popupContent']//input[2] is very similar except the last thing is to select the 2nd child. And none of the <input>s are 2nd child of their parent.

div[@class='popupContent']/descendant::input[2] on the other hand will:

  1. go to all descendants of the divs with that class,
  2. selecting only <input> elements, and build a node-set out of them
  3. finally select the 2nd element in that node-set, in document order

You can read about predicates and axes in §2.4 Predicates. Relevant pieces:

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

[Thus descendant is a forward axis.]

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;


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...