2010-07-12 52 views
4

当我运行此:“需要XsltContext此查询,因为未知功能的”如何使用FN:最大的的SelectSingleNode

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

我得到一个异常在最后一行。我正在尝试选择具有最高NUMBER属性的ITEM元素。这可能使用XPATH吗?

我正在使用.Net 2.0和Linq不是一个选项。

感谢

+0

问得好(+1 )。请参阅我的回答,以获取有关该问题的解释以及正确的XPath 1.0和XPath 2.0单线解决方案。 – 2010-07-12 13:39:13

回答

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表达式不与最大NUMBER属性选择ITEM。使用max()一个正确的XPath 2.0表达式来选择是这样的:

/*/ITEM[xs:integer(@NUMBER) eq max(../@NUMBER/xs:string(.))] 

这是因为参数max()必须是我们需要确定最大的元素项的顺序。取而代之的是,在从问题的XPath表达式:

//ITEM[fn:max(@NUMBER)] 

max仅具有单个参数 - 上下文节点的NUMBER属性。因此,上述等效于:

//ITEM[@NUMBER] 

,其选择具有一个NUMBER属性的所有ITEM元素。

+0

+1很好的解释。 – 2010-07-12 13:48:40

2

您可以使用下面的机制来找到任何给定的属性值最高的节点:

XmlNode xmlNode = xmlResponse.SelectSingleNode("//ITEM[not(preceding-sibling::ITEM/@NUMBER > @NUMBER or following-sibling::ITEM/@NUMBER > @NUMBER)]", nsmgr); 

在XPath,你可以实现你自己的XsltContext,并把它传递给XPathExpression.SetContext () 方法。 这个XstlContext在每次XPath捕获未知函数时被调用,这是用自定义函数和变量扩展XPath的方法。

+0

所以不可能使用这里描述的最大功能? http://www.w3schools.com/Xpath/xpath_functions.asp – Polyfun 2010-07-12 12:46:58

+1

XPath支持可用的xslt函数的子集。以下链接详细信息支持:http://www.w3.org/TR/xpath/ – 2010-07-12 13:19:25

1

如上所述,Microsoft .NET Framework XML API(如XmlDocument和XPathDocument/XPathNavigator)仅支持XPath 1.0,而您要使用的最大功能是XPath 2.0。 要找到一个最大值的元素但有另一种解决方案可以与微软的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);