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

這不會拋出異常和代碼將工作得很好。