Categories
XML

Abbreviating the descendant axis in XSLT

Say we have the following XML:

[sourcecode language=’xml’]
p1 p2 p3

[/sourcecode]

The question is, what does the XPath expression //para[1] return? I originally expected it to select all the para elements and then return just the first one. In fact, what it returns is

[sourcecode language=’xml’]
p1
p3
[/sourcecode]

This is because what the expression actually means is, “return all the para elements that are the first child of any element”.

Why is that?  According to the XPath specification, // is actually the abbreviation for /descendant-or-self::node()/, so that //para is actually /descendant-or-self::node()/child::para.

Since p1 and p3 are the first children of their parents, and p2 is the second child* of its parent, the nodes returned are p1 and p3.

*Assuming we’re ignoring whitespace, of course, which is always a bit of an adventure.

If I really want the first instance of all the para elements, then I need the expression /descendant::para[1]. That collects all the para elements and returns the first one.

A side benefit to this approach is that it forced me to learn how to spell “descendant” correctly. 🙂