开发者

How to use fn:max in SelectSingleNode

开发者 https://www.devze.com 2023-01-07 10:41 出处:网络
When I run this: XmlDocument xmlResponse = new XmlDocument(); XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlRespons开发者_StackOverflowe.NameTable);

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);
0

精彩评论

暂无评论...
验证码 换一张
取 消