2012-07-27 70 views
0

我是LINQ to XML的新手,想知道是否有人可以幫助我構建以下查詢。LINQ to XML不包含後代包含值的元素的示例

我想返回所有<response>元素,它們不包含含有「404」的後代<status>元素。

我的XML如下所示。在這種情況下,只應返回第一個<response>元素(和後代)。

<multistatus xmlns="DAV:"> 
    <response> 
    <href>/principals/users/test/</href> 
    <propstat> 
     <prop> 
     <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav"> 
      <href xmlns="DAV:">/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9</href> 
     </calendar-home-set> 
     </prop> 
     <status>HTTP/1.1 200 OK</status> 
    </propstat> 
    </response> 
    <response> 
    <href>/principals/users/test/calendar-proxy-write/</href> 
    <propstat> 
     <prop> 
     <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav" /> 
     </prop> 
     <status>HTTP/1.1 404 Not Found</status> 
    </propstat> 
    </response> 
    <response> 
    <href>/principals/users/test/calendar-proxy-read/</href> 
    <propstat> 
     <prop> 
     <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav" /> 
     </prop> 
     <status>HTTP/1.1 404 Not Found</status> 
    </propstat> 
    </response> 
</multistatus> 

回答

3

假設你的XML存儲在字符串變量xml

XDocument document = XDocument.Parse(xml); 
XNamespace ns = document.Root.GetDefaultNamespace(); 

var responsesExcept404s = document 
    .Descendants(ns + "response") 
    .Where(x => !x.Descendants(ns + "status") 
        .Single() 
        .Value.Contains("404")); 

通知ns變量的用法 - 因爲你的XML有默認命名空間集通過xmlns屬性,有必要在使用LINQ to XML時指定該名稱空間(例如在Descendants()方法中)。

然後,你可以簡單地遍歷結果,使這個超有用,它們輸出到控制檯:

responsesExcept404s.ToList().ForEach(Console.WriteLine); 
+0

嗯......你測試過了嗎?對我來說,我得到空的結果。對於命名空間,我使用「DAV:」。 – 2012-07-27 21:36:58

+0

@JonathanWood是的,我做到了。我完全使用了你的問題中的XML。我的整個程序是一個簡單的.NET 4.0 C#控制檯應用程序,它包含將XML存儲到字符串變量以及我的答案中的代碼,僅此而已。你應該得到一個'迴應'回來。 – 2012-07-27 21:41:28

+0

Doh!看起來我的名字空間錯了。您的代碼與廣告一樣工作! – 2012-07-27 22:28:14

0

試試這個:

Document doc = XDocument.Load(path); 
     XNamespace nsd = doc.Root.GetDefaultNamespace(); 
     var res = doc.Descendants(nsd +"response");     

     var filteredEle = new List<XElement>(); 

        foreach (var ele in res) 
        { 
         if (CheckEle(ele,nsd)) 
         { 
          filteredEle.Add(ele); 
         } 
        }  


    private bool CheckEle(XElement ele, XNamespace nsd) 
     { 
      return ele.Element(nsd + "propstat").Element(nsd + "status").Value != "HTTP/1.1 404 Not Found"; 
     } 
+0

謝謝,但正如我的問題所示,我的XML內容不是這樣的。我比較的不是一個屬性,它是一個子元素。 – 2012-07-27 21:11:16

+0

我已經編輯了答案,你現在可以試試。 – 2012-07-27 21:20:36

+0

謝謝,但這仍然不同。在這裏,''是來自''的直接孩子。在我的XML中,事實並非如此。這就是爲什麼我將XML包含在問題中的原因。 – 2012-07-27 21:25:17

0

你可以使用LINQ語句如下圖所示

XDocument doc = XDocument.Parse(xml); 
List<XElement> responseWithOut404 = 
    (from element in doc.Descendants("response") 
    let xElement = element.Descendants("status").First() 
    where !xElement.Value.Contains("404") 
    select element) 
    .ToList(); 
1

這裏亞去:(使用XPath作弊)

 XDocument xdoc = XDocument.Load(new FileStream("XMLFile2.xml", FileMode.Open, FileAccess.Read)); 
     XPathNavigator nav = xdoc.CreateNavigator(); 
     var nsm = new XmlNamespaceManager(nav.NameTable);    
     nsm.AddNamespace("s", "DAV:"); 
     var nodes = xdoc.XPathSelectElements("s:multistatus/s:response[.//*[name(.)='status' and .='HTTP/1.1 404 Not Found']]", nsm); 
+0

謝謝。看起來「毛茸茸」。 :)不會直接在我的情況下工作,因爲我有'XElement'而不是'XDocument'。 – 2012-07-27 22:30:22

2
XDocument xDoc = XDocument.Parse(xml); 
XNamespace ns = XNamespace.Get("DAV:"); 
var responses = xDoc.Descendants(ns + "status") 
        .Where(s => !s.Value.Contains(" 404 ")) 
        .Select(s => s.Parent.Parent);