Get first child node in XSLT using local-name()
Solution 1
The path expression you say works for you
//books[1]/*
generates a list of all child nodes of the first (and only in this case) occurrence of any <books> node. Because, in your data, the only occurrence of <books> is at the root, it is the same as
/books/*
which returns two <book> nodes, and so you are wrong to say that it returns only one node.
It is hard to know what you need, as if you are always applying local-name
to the root node then you do not need to know its name and can access it with just /*
, so you would want simply
/*/*[1]
However to access the first child node of a <books> node anywhere in the document you would write
//*[local-name()='books']/*[1]
You should be careful to confine your context as much as possible, as starting the XPath expression with //
will force a search of the entire document, which is pointless and time-consuming if the node in question is always at the root.
Solution 2
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"/>
raffian
Applications architect and code slinger since 2000, my background is full stack Java. Reach me at 72616666692e6970616440676d61696c2e636f6d My other passion is landscape photography, check it out if you're interested!
Updated on October 11, 2020Comments
-
raffian over 3 years
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