The main strength of the XPath language lies in the axes that allow you to get to any element in the original document. Consider the use of such rarely used axes as
ancestor ,
descendant, and
self .
ancestor
Task: get the id attribute of the element “great-grandfather” foo.
Usually in such cases, the stairs begin to draw:
')
../../../@id
Such a record is bad in that it is obscure without knowing the source xml. The author recommends in such cases to use a more informative expression:
ancestor::foo[1]/@id
This record not only gives an idea of ​​the item you are looking for, but also continues to work even if the current item has changed its position in the tree.
descendant
Task: find the first descendant of foo in the current element.
When a similar question was
asked on StackOverflow.com, two people immediately answered
.//foo[1]
and were supported by other participants. The author had to intervene and warn about the incorrectness of this expression. The correct answer:
descendant::foo[1]
, and here's why.
.//foo
is a short form of the following expression:
self::node()/descendant-or-self::node()/child::foo
The entry
.//foo[1]
means
all descendants of foo, each of which is the first foo of its parent . Such an expression will return
two elements in the following document:
<list>
<item> <foo /> </ item>
<item> <foo /> </ item>
</ list>
descendant::foo[1]
returns exactly one item.
This distinction is described in the documentation, but for some reason many people read it inattentively. To avoid mistakes, the author recommends that you always write
descendant::foo
instead of
.//foo
, since in most cases this is what is meant.
self
It would seem, why do you need self, if there is a shorter version:. (point). However, this axis also found its application.
Task: get the next element if it is called foo.
The obvious solution:
following-sibling::*[1][name() = 'foo']
More elegant, in the opinion of the author, the expression:
following-sibling::*[1]/self::foo
Comments and additions are welcome.