Find position of a node using XPath
Solution 1
Try:
count(a/b[.='tsr']/preceding-sibling::*)+1.
Solution 2
You can do this with XSLT but I'm not sure about straight XPath.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"
omit-xml-declaration="yes"/>
<xsl:template match="a/*[text()='tsr']">
<xsl:number value-of="position()"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Solution 3
I realize that the post is ancient.. but..
replace'ing the asterisk with the nodename would give you better results
count(a/b[.='tsr']/preceding::a)+1.
instead of
count(a/b[.='tsr']/preceding::*)+1.
Solution 4
If you ever upgrade to XPath 2.0, note that it provides function index-of, it solves problem this way:
index-of(//b, //b[.='tsr'])
Where:
- 1st parameter is sequence for searching
- 2nd is what to search
Solution 5
Unlike stated previously 'preceding-sibling' is really the axis to use, not 'preceding' which does something completely different, it selects everything in the document that is before the start tag of the current node. (see http://www.w3schools.com/xpath/xpath_axes.asp)
![Wilfred Knievel](https://i.stack.imgur.com/MXg7q.jpg?s=256&g=1)
Comments
-
Wilfred Knievel over 3 years
Anyone know how to get the position of a node using XPath?
Say I have the following xml:
<a> <b>zyx</b> <b>wvu</b> <b>tsr</b> <b>qpo</b> </a>
I can use the following xpath query to select the third <b> node (<b>tsr</b>):
a/b[.='tsr']
Which is all well and good but I want to return the ordinal position of that node, something like:
a/b[.='tsr']/position()
(but a bit more working!)
Is it even possible?
edit: Forgot to mention am using .net 2 so it's xpath 1.0!
Update: Ended up using James Sulak's excellent answer. For those that are interested here's my implementation in C#:
int position = doc.SelectNodes("a/b[.='tsr']/preceding-sibling::b").Count + 1; // Check the node actually exists if (position > 1 || doc.SelectSingleNode("a/b[.='tsr']") != null) { Console.WriteLine("Found at position = {0}", position); }
-
Wilfred Knievel over 15 years'Coz I'm using .net & either it or I can't handle the power I went with: int position = doc.SelectNodes("a/b[.='tsr']/preceding-Sibling::b").Count + 1; if (position > 1 || doc.SelectSingleNode("a/b[.='tsr']") != null) // Check the node actually exists { // Do magic here }
-
Ishyc over 15 yearsSo not really an XPath finder now, but a C# finder.
-
LarsH almost 14 yearsNot including ancestor nodes. Don't trust w3schools on the details! But I agree... although preceding:: works in this case, because there are no elements before the relevant b elements other than the a ancestor, it's more fragile than preceding-sibling. OTOH, the OP didn't tell us what context he wanted to know the position within, so potentially preceding:: could be right.
-
Dan Atkinson over 8 yearsIt should be noted that this will only work with XPath 2+. Anything below that will have to use the 'weird' count function.
-
CroWell over 8 years@Dan, it was noted in the link to original docs, added explicit notice, thanks!
-
JonnyRaa over 6 yearsin zero indexed languages you don't need the +1
-
Onyr over 3 yearsA little example in-situ (get the position of the element France in a XML doc) : index-of(//country_name/common_name, //country_name/common_name[text()="France"])