Is there a way to query an XML document to return the maximum of a given attribute using Xpath 1.0 ?
For example is there a way to get the max id ?
&
XPath 1.0
/library/book[not(@id < /library/book/@id)]
This query style is more generic and works even if books are grouped i.e.
<?xml version="1.0" encoding="utf-8"?>
<library>
<genre id="1">
<book id="2" name="Dragon Tatoo"/>
<book id="7" name="Ender's Game"/>
</genre>
<genre id="2">
<book id="3" name="Catch 22"/>
<book id="1" name="Lord of the rings"/>
</genre>
</library>
Same query still works (the path should be modified)
/library/genre/book[not(@id < /library/genre/book/@id)]
or even
//book[not(@id < //book/@id)]
To avoid performance troubles use XPath 2 max()
instead
If you're willing to use external tooling - which depends on your implementation featuring implementations of these tools - try the EXSLT:Math function highest()
.
The fact that EXSLT implements this implies that such a feature isn't directly available in plain xpath, of course. If you're not using Transforms, or want to stick purely with standards-compliant markup, other posters' suggestions would be a better choice.
This example can be used to find the max.
XmlDocument doc = new XmlDocument();
doc.Load("../../Employees.xml");
XmlNode node = doc.SelectSingleNode("//Employees/Employee/@Id[not(. <=../preceding-sibling::Employee/@id) and not(. <=../following-sibling::Employee/@Id)]");
int maxId = Convert.ToInt32(node.Value);
For other similar topics on xpath and linq check out http://rmanimaran.wordpress.com/2011/03/20/xml-find-max-and-min-value-in-a-attribute-using-xpath-and-linq/
The following XPath selects the book with highest id:
/library/book[not(@id <= preceding-sibling::book/@id) and not(@id <=following-sibling::book/@id)]
In XPath 2.0, use the max
function. To find the book with the highest id
, do
/library/book[@id = max(/library/book/@id)]
I've found that answers like the lwburk's or timbooo's work fine for attributes representing numbers having just one digit. However, if the attribute is a number having more than one digit, extrange things seem to happen when comparing between attributes' values. For example, try changing the original XML data with something like this:
<?xml version="1.0" encoding="utf-8"?>
<library>
<book id="250" name="Dragon Tatoo"/>
<book id="700123" name="Ender's Game"/>
<book id="305" name="Catch 22"/>
<book id="1070" name="Lord of the rings"/>
</library>
Running the suggested snippets won't work. I got a solution using the casting operator xs:int() applied on id attribute, like in:
/library/book[not(xs:int(@id) <= preceding-sibling::book/@id) and not(xs:int(@id) <=following-sibling::book/@id)]
That will give the correct answer!