I am using Java and Selenium to write a test. I need to get the last element inside another element, so I used last()
function, but the problem is that it doesn't always bring me the last one when I apply :
//a//b[last()]
to
<a>
<l>
<b>asas</b>
</l>
<b>as</b>
</a>
to get <b>as</b>
,it brings me:
<b>asas</b>
<b>as</b>
but when I apply it to:
<a>
<b>asas</b>
<b>as</b>
</a>
it brings me:
<b>as</b>
I think it's easiest to understand the behaviour if you remember that "//" is an abbreviation for "/descendant-or-self::node()/", and that the step "b" is an abbreviation for "child::b". So
is an abbreviation for
Which means "Select every node in the document (except attributes and namespaces). For each of these nodes, form a list of the child elements named "b", and select the last element in this list".
You ask for sources of information. @kjhughes recommends reading the XPath 1.0 recommendation, and indeed, it is a lot more readable than many specs. But it can be a bit terse at times; it occasionally feels like solving a crossword puzzle. My "XSLT 2.0 Programmer's Reference" (which also includes a lot of material on XPath) was written for people who want a deep understanding of how the language works, but explained in plainer English. This particular topic is on page 627, and it's easy enough to find a pirated copy on the web if you want to see how it's covered. But I'd recommend buying a legal copy, because scrolling through 1300 pages of scanned PDF is not much fun.
This is a common source of XPath confusion. First the straightforward parts:
//a
selects alla
elements in the document.//a//b
selects allb
elements in the document that are descendants ofa
elements.Normal stuff so far. Next is the tricky part:
To select the last
b
elements among siblings (beneatha
elements):Here, the filtering is a part of the
b
selection criteria because[]
has a higher precedence than//
.To select the last
b
element in the document (beneatha
elements):Here, the
last()
is an index on the list of all selectedb
elements because()
is used to override the default precedence.