Differences between // and /descendant in XPath selecting multiple children
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:
- go to all descendants (children, children of children and so on) of the
div
s with that "popupContent" class, - then look for
<input>
children - 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:
- go to all descendants of the
div
s with that class, - selecting only
<input>
elements, and build a node-set out of them - 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;
The only difference between //X
and /descendant::X
is when X contains a positional predicate, for example //x[1]
vs /descendant::x[1]
. In this situation //x[1]
selects every x
element that is the first x
child of its parent element, whereas /descendant::x[1]
selects the first descendant x overall. You can work this out by remembering that //x[1]
is short for /descendant-or-self::node()/child::x[1]