当我运行时:
XmlDocument xmlResponse = new XmlDocument();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlResponse.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);
我得到一个异常“由于函数未知,此查询需要XsltContext。”在最后一行。我正在尝试选择具有最高NUMBER属性的ITEM元素。这可能使用XPATH吗?
我使用的是.Net 2.0,Linq不是一个选项。
由于
答案 0 :(得分:4)
XmlNode xmlNode = xmlResponse.SelectSingleNode("//ITEM[fn:max(@NUMBER)]", nsmgr);
max()
是一个XPath 2.0函数。 .NET仅支持XPath1.0。
在XPath 1.0中,您可以使用:
/*/ITEM[not(@NUMBER > ../@NUMBER)]
即使.NET已经实现了XPath 2.0,问题中的XPath表达式也不会选择具有最大ITEM
属性的NUMBER
。使用max()
选择它的正确XPath 2.0表达式是:
/*/ITEM[xs:integer(@NUMBER) eq max(../@NUMBER/xs:string(.))]
这是因为max()
的参数必须是我们需要确定最大元素的项目序列。相反,在问题的XPath表达式中:
//ITEM[fn:max(@NUMBER)]
max
只有一个参数 - 上下文节点的NUMBER
属性。因此,上述内容相当于:
//ITEM[@NUMBER]
选择具有ITEM
属性的所有NUMBER
元素。
答案 1 :(得分:2)
您可以使用以下机制查找具有任何给定属性的最高值的节点:
XmlNode xmlNode = xmlResponse.SelectSingleNode( "//ITEM[not(preceding-sibling::ITEM/@NUMBER > @NUMBER or following-sibling::ITEM/@NUMBER > @NUMBER)]", nsmgr );
在XPath中,您可以实现自己的XsltContext并将其传递给XPathExpression.SetContext()方法。 每次XPath都会使用未知函数时调用此XstlContext,这是使用自定义函数和变量扩展XPath的方法。
答案 2 :(得分:1)
如上所述,Microsoft .NET框架XML API(如XmlDocument和XPathDocument / XPathNavigator)仅支持XPath 1.0,而您要使用的max函数是XPath 2.0。 要查找具有最大值的元素,可以使用Microsoft API进行另一种解决方案,即排序(按降序排列最大值)和按排序顺序访问第一项:
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);