Assume we have this simple xml ...
<books>
<book>
<author/>
<title/>
</book>
<book>
<author/>
<title/>
</book>
</books>
I'm using this xpath to get the elements of the first book instance.
//books[1]/*
Returns
<author/>
<title/>
And that works fine, but I have to get it working using local-name(). I've tried the following but none of these work...
//*[local-name()='books']/*
this returns repeating author and title elements, not good, I only need them from the first child
//*[local-name()='books'][0]/*
this does not return anything
Basically, I want to create a CSV file, so the first line in the output will be a header listing the book attribute names followed by the arbitrary data values. I only need to get the header part working.
author,title
john,The End is Near
sally,Looking for Answers
This is a FAQ -- the XPath []
operator has higher precedence (priority) than the //
pseudo-operator.
So:
//someElemName[1]
selects every element named someElemName
that is the first child of its parent -- and, depending on the XML document, there can be more than one such elements.
To change this, one must use brackets.
Use:
(//*[local-name() = 'book'])[1]/*
Also note: In XPath positions are 1-based, not 0-based.
XSLT-based verification:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select=
"(//*[local-name() = 'book'])[1]/*"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<books>
<book num="1">
<author num="1"/>
<title num="1"/>
</book>
<book num="2">
<author num="2"/>
<title num="2"/>
</book>
</books>
the wanted nodes are selected and copied to the output:
<author num="1"/>
<title num="1"/>