2010-08-18 48 views
1

我想解析C#中網站的XML響應。響應的格式類似於以下內容:在C#XML中解析特定內容的XML

<Company> 
    <Owner>Bob</Owner> 
    <Contact> 
     <address> -1 Infinite Loop </address> 
     <phone> 
      <LandLine>(000) 555-5555</LandLine> 
      <Fax> (000) 555-5556 </Fax> 
     </phone> 
     <email> [email protected] </email> 
    </Contact> 
</Company> 

我想要的唯一信息是LandLine和傳真號碼。然而,我目前的做法似乎真的很差質量。本質上它是一堆嵌套的while循環,並檢查元素名稱,然後在找到正確的元素時讀取內容。我正在使用類似下面的清單:

XmlReader xml = XmlReader.Create(websiteResultStream, xmlSettings); 

while(xml.Read()){ 
    if(xml.NodeType == XmlNodeType.Element){ 
     if(xml.Name.ToString() == "Phone"){ 
      while(xml.Read()) { 
       if(xml.NodeType == XmlNodeType.Element) { 
        if(xml.Name.ToString() == "LandLine"){ 
          xml.MoveToContent(); 
          xml.ReadContentAsString(); 
        } 
        if(xml.Name.ToString() == "Fax"){ 
          xml.MoveToContent(); 
          xml.ReadContentAsString(); 
        } 
       } 
      } 
     } 
    } 
} 

我是較新的XML/C#,但上述方法只是尖叫壞代碼!我想確保如果結構發生變化(即,有另外的電話號碼類型,如「移動」),代碼是健壯的(因此,額外的while循環)

注意:上述C#代碼不準確,缺乏一些檢查等,但它展示了我目前令人厭惡的方法

如果簡單地從這兩個元素中提取內容,如果它們存在,最好/最乾淨的方法是什麼?

回答

8

進行只讀訪問特定節點的XML文檔中的最輕質的方法是通過使用XPathDocument以及XPath表達式:

XPathDocument xdoc = new XPathDocument(@"C:\sample\document.xml"); 
XPathNavigator node = xdoc.CreateNavigator() 
    .SelectSingleNode("/Company/Contact/phone/LandLine"); 
if (node != null) 
{ 
    string landline = node.Value; 
} 
8

var doc = XDocument.Parse(@"<Company> 
    <Owner>Bob</Owner> 
    <Contact> 
     <address> -1 Infinite Loop </address> 
     <phone> 
      <LandLine>(000) 555-5555</LandLine> 
      <Fax> (000) 555-5556 </Fax> 
     </phone> 
     <email> [email protected] </email> 
    </Contact> 
</Company>"); 

var phone = doc.Root.Element("Contact").Element("phone"); 

Console.WriteLine((string)phone.Element("LandLine")); 
Console.WriteLine((string)phone.Element("Fax")); 

輸出:

 
(000) 555-5555 
(000) 555-5556 
+3

請注意,如果聯繫人丟失,您將在'var phone = ...'行中收到異常。我喜歡做'var contactNode = doc.Root.Element(「Contact」)之類的東西?新的XElement(「Contact」);'所以我總是有一個節點返回,然後當我做'var phone = contact.Element(「phone」)?新的XElement(「電話」);'我不會得到null對象錯誤。最後,我最終得出了變量的空白值。或者在解析之前使用xsd來驗證文檔,以確保您想要的節點存在。 – CaffGeek 2010-08-18 14:48:56

+3

請注意,'XDocument'類還帶有在內存中構建DOM樹的開銷;通常不是您需要對文檔中的節點進行只讀隨機訪問,特別是在處理大型文檔時。 – 2010-08-18 15:12:08

2

我不認爲你太遙遠了。有更方便的方法(很多不同的方法)。假設你想,你在這裏做採取相同的基本方法(這是一種有效的,如果詳細的一個),我會做:

bool inPhone = false; 
string landLine = null; 
string fax = null; 

using(xml = XmlReader.Create(websiteResultStream, xmlSettings) 
while(xml.Read()) 
{ 
    switch(xml.NodeType) 
    { 
    case XmlNodeType.Element: 
     switch(xml.LocalName) 
     { 
     case "phone": 
      inPhone = true; 
      break; 
     case "LandLine": 
      if(inPhone) 
      { 
      landLine = xml.ReadElementContentAsString(); 
      if(fax != null) 
      { 
       DoWhatWeWantToDoWithTheseValues(landline, fax); 
       return; 
      } 
      } 
      break; 
     case "Fax": 
      if(inPhone) 
      { 
      fax = xml.ReadElementContentAsString(); 
      if(landLine != null) 
      { 
       DoWhatWeWantToDoWithTheseValues(landline, fax); 
       return; 
      } 
      } 
      break; 
     } 
     break; 
    case XmlNodeType.EndElement: 
     if(xml.LocalName == "phone") 
     inPhone = false; 
     break; 
    } 
} 

請注意,此跟蹤它是否是「內部」 phone元素如該您將重新檢查後面元素中的LandLine,這似乎是您試圖避免的。

另請注意,我們清理XmlReader,並在我們獲得所有我們想要的信息後立即返回。