2010-11-29 68 views
11

这看起来不像应该很困难,但我目前陷入困境。我试图从与给定XPath查询字符串匹配的节点获取特定属性的属性值。这是我到目前为止有:使用XPath查询从匹配的XML节点获取属性值

public static IEnumerable<string> GetAttributes(this XmlDocument xml, 
     string xpathQuery, string attributeName) 
    { 
     var doc = new XPathDocument(new XmlNodeReader(xml)); 
     XPathNavigator nav = doc.CreateNavigator(); 
     XPathExpression expr = nav.Compile(xpathQuery); 
     XPathNodeIterator iterator = nav.Select(expr); 
     while (iterator.MoveNext()) 
     { 
      XPathNavigator curNav = iterator.Current; 
      if (curNav.HasAttributes) 
      { 
       XmlNode curNode = ((IHasXmlNode)curNav).GetNode(); 
       if (null != curNode) 
       { 
        XmlAttribute attrib = curNode.Attributes[attributeName]; 
        if (null != attrib) 
        { 
         yield return attrib.Value; 
        } 
       } 
      } 
     } 
    } 

这目前抛出异常:

System.InvalidCastException:无法投类型的对象MS.Internal.Xml.Cache.XPathDocumentNavigator为键入' System.Xml.IHasXmlNode”。

我该说这个错吗?有没有更简单的方法从匹配节点获取属性值?

+1

为什么不使用LinqToXml?这会大大减少噪音,除非我错过了Linq无法做到这一点的一些原因? – 2010-11-29 21:15:19

回答

31

对于以下XML:

<root> 
    <elem att='the value' /> 
</root> 

你可以使用此C#代码

XmlDocument xdoc = new XmlDocument(); 
    xdoc.LoadXml(text); 
    Console.WriteLine(xdoc.SelectSingleNode("/root/elem/@att").Value); 
+0

Derp。我曾经见过`SelectNodes`是`XmlElement`上的一个方法,就像`xmlDoc.DocumentElement`一样,但没有想到检查`XmlDocument`。使用你的例子,但使用`SelectNodes`适用于我。 – 2010-11-29 21:35:39

+0

+1好答案。 – 2010-11-29 21:44:31

4

的 “值” 文本如果你使用.NET 3.5或更高版本,你可以使用LINQ以XML

对于一个给定的XML文档

<?xml version="1.0" encoding="utf-8" ?> 
<root> 
    <storedProcedures> 
    <storedProcedure name="usp_GET_HOME_PAGE_DATA"> 
     <resultSet name="Features"/> 
     <resultSet name="Highlights"/> 
    </storedProcedure> 
    <storedProcedure name="usp_GET_FEATURES" /> 
    <storedProcedure name="usp_GET_FEATURE" /> 
    <storedProcedure name="usp_UPDATE_FEATURE" /> 
    <storedProcedure name="usp_GET_FEATURE_FOR_DISPLAY"> 
     <resultSet name="CurrentFeature"/> 
     <resultSet name="OtherFeatures"/> 
    </storedProcedure> 
    <storedProcedure name="usp_GET_HIGHLIGHT_TITLES"> 
     <resultSet name="Highlights"/> 
    </storedProcedure> 
    </storedProcedures> 
</root> 

下面的LINQ表达式会得到你的“名称”属性的值,所有的StoredProcedure节点

XDocument xDcoument = XDocument.Load(xmlStoredProcSchemeFile); 

    var storedProcedureNames = from doc in xDcoument.Descendants("storedProcedure") 
          select doc.Attribute("name").Value; 

你也可以使用普通的XPath语法。在下面的代码中,变量节点保存由“usp_GET_HOME_PAGE_DATA”名称标识的节点,然后attributes变量保存所选节点的所有子节点(属性),并且它是子节点。

XmlDocument xmlDocument = new XmlDocument(); 
    xmlDocument.Load(@"C:\inetpub\wwwroot\ASPNETBuilder\BusinessLayer\DataAccessCodeGenerationSchema.xml"); 
    var node = xmlDocument.DocumentElement.SelectSingleNode("./storedProcedures/storedProcedure[@name='usp_GET_HOME_PAGE_DATA']"); 
    var attributes = node.SelectNodes("./resultSet/@name"); 
1

解决异常被抛出最初的问题...

var doc = new XPathDocument(new XmlNodeReader(xml)); 

应改为...

var doc = new XmlDocument(); 
doc.load(*you can either specify the path to the file, the string out of which the xml document is to be generated or specify an xmlreader, look for more overloads*); 

这不会抛出异常和代码将工作得很好。

相关问题