How to use fn:max in SelectSingleNode
When I run this:
XmlDocument xmlResponse = new XmlDocument();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlRespons开发者_StackOverflowe.NameTable);
nsmgr.AddNamespace("fn", " http://www.w3.org/2005/xpath-functions");
xmlResponse.LoadXml(
"<LIST>" +
"<ITEM NUMBER='3' TEXT='C'/>" +
"<ITEM NUMBER='2' TEXT='B'/>" +
"<ITEM NUMBER='1' TEXT='A'/>" +
"</LIST>");
XmlNode xmlNode = xmlResponse.SelectSingleNode("//ITEM[fn:max(@NUMBER)]", nsmgr);
I get an exception "XsltContext is needed for this query because of an unknown function." on the final line. I am trying to select the ITEM element with the highest NUMBER attribute. Is this possible using XPATH?
I am using .Net 2.0 and Linq is not an option.
Thanks
XmlNode xmlNode = xmlResponse.SelectSingleNode("//ITEM[fn:max(@NUMBER)]", nsmgr);
max()
is an XPath 2.0 function. .NET only supports XPath1.0.
In XPath 1.0 you can use:
/*/ITEM[not(@NUMBER > ../@NUMBER)]
Even if .NET had implemented XPath 2.0, the XPath expression from the question does not select the ITEM
with the maximum NUMBER
attribute. A correct XPath 2.0 expression that uses max()
to select this is:
/*/ITEM[xs:integer(@NUMBER) eq max(../@NUMBER/xs:string(.))]
This is because the argument to max()
must be the sequence of items in which we need to determine the maximum element. Instead, in the XPath expression from the question:
//ITEM[fn:max(@NUMBER)]
max
has only a single argument -- the NUMBER
attribute of the context node. Therefore the above is equivalent to:
//ITEM[@NUMBER]
which selects all ITEM
elements that have a NUMBER
attribute.
you can use the following mechanism to find the node with the highest value for any given attribute:
XmlNode xmlNode = xmlResponse.SelectSingleNode( "//ITEM[not(preceding-sibling::ITEM/@NUMBER > @NUMBER or following-sibling::ITEM/@NUMBER > @NUMBER)]", nsmgr );
In XPath you can implements your own XsltContext and pass it to XPathExpression.SetContext() method. This XstlContext is called each time XPath meats unknown function and this is the way to extend XPath with custom functions and variables.
As explained, the Microsoft .NET framework XML APIs like XmlDocument and XPathDocument/XPathNavigator only support XPath 1.0 while the max function you want to use is XPath 2.0. To find an element with a maximum value there is however another solution possible with the Microsoft APIs, namely sorting (for the maximum in descending order) and accessing the first item in sorted order:
XmlDocument xmlResponse = new XmlDocument();
xmlResponse.LoadXml(
"<LIST>" +
"<ITEM NUMBER='3' TEXT='C'/>" +
"<ITEM NUMBER='2' TEXT='B'/>" +
"<ITEM NUMBER='1' TEXT='A'/>" +
"</LIST>");
XPathNavigator nav = xmlResponse.CreateNavigator();
XPathExpression exp = nav.Compile("LIST/ITEM");
exp.AddSort("@NUMBER", XmlSortOrder.Descending, XmlCaseOrder.None, "", XmlDataType.Number);
XmlNode item = nav.SelectSingleNode(exp).UnderlyingObject as XmlNode;
Console.WriteLine(item.OuterXml);
精彩评论