2010-04-07 20 views
0

(第一次發帖,請溫柔!)強大的LINQ to XML查詢兄弟鍵值對

我只是學習LINQ在其所有的榮耀和脆弱XML,試圖破解它做什麼,我想做的事:

給定一個XML文件中像這樣 - 在一個強大的時尚

<list> 
<!-- random data, keys, values, etc.--> 

    <key>FIRST_WANTED_KEY</key> 
    <value>FIRST_WANTED_VALUE</value> 

    <key>SECOND_WANTED_KEY</key> 
    <value>SECOND_WANTED_VALUE</value> <!-- wanted because it's first --> 

    <key>SECOND_WANTED_KEY</key> 
    <value>UNWANTED_VALUE</value> <!-- not wanted because it's second --> 

    <!-- nonexistent <key>THIRD_WANTED_KEY</key> --> 
    <!-- nonexistent <value>THIRD_WANTED_VALUE</value> --> 

<!-- more stuff--> 
</list> 

我想提取一組已知的值「通緝鍵」,也就是說,如果SECOND_WANTED_KEY出現了兩次,我只想要SECOND_WANTED_VALUE,而不是UNWANTED_VALUE。此外,THIRD_WANTED_KEY可能會或可能不會出現,所以查詢應該也能夠處理。我可以假設FIRST_WANTED_KEY會出現在其他鍵之前,但不能假定其他鍵的順序 - 如果鍵出現兩次,其值不重要,我只想要第一個鍵。由字符串組成的匿名數據類型很好。

我嘗試周圍的東西沿着這些線路中心:

var z = from y in x.Descendants() 
     where y.Value == "FIRST_WANTED_KEY" 
     select new 
     { 
      first_wanted_value = ((XElement)y.NextNode).Value, 
     //... 
     } 

我的問題是什麼應該是...是什麼?我試過,例如,(醜,我知道)

second_wanted_value = ((XElement)y.ElementsAfterSelf() 
         .Where(w => w.Value=="SECOND_WANTED_KEY") 
         .FirstOrDefault().NextNode).Value 

應該希望允許的關鍵,在任何地方,或不存在的,但是這並沒有對空XElement制定出來的,因爲.NextNode似乎沒有工作。

我也試圖在

.Select(t => { 
    if (t==null) 
     return new XElement("SECOND_WANTED_KEY",""); 
    else return t; 
}) 

子句添加在其中之後,但是這並沒有任何工作。

我接受建議,(建設性的)批評,鏈接,引用或建議的短語谷歌等我已經做了公平的份額谷歌搜索和檢查所以所以任何幫助將不勝感激。

謝謝!

編輯: 讓我爲此添加一層複雜性 - 我應該把它包括在第一位。假設XML文檔如下所示:

<lists> 
    <list> 
     <!-- as above --> 
    </list> 
    <list> 
     <!-- as above --> 
    </list> 
</lists> 

我想提取多組這些鍵值對。 Question/Caution:如果SECOND_WANTED_KEY沒有出現在第一個<list>元素中,但出現在第二個元素中,我不想意外地拿起第二個列表元素的SECOND_WANTED_KEY

編輯#2:

作爲另一個想法,我嘗試創建我要找的和做的鍵的HashSet這樣的:

HashSet<string> wantedKeys = new HashSet<string>(); 
wantedKeys.Add("FIRST_WANTED_KEY"); 
//...add more keys here 
var kvp = from a in x.Descendants().Where(a => wantedKeys.Contains(a.Value)) 
      select new KeyValuePair<string,string>(a.value, 
      ((XElement)a.NextNode).Value); 

這得到的我的一切鍵值對,但我不確定它是否能保證我將這些對「關聯」到它們的父元素。這兩種方法之間的任何想法或比較都會有所幫助。

狀態更新10年4月9日

至於現在,我仍然主要思想散集的方法是最好的。似乎.NET所做的大部分XML處理都是按照文檔順序完成的 - 到目前爲止,我的所有測試用例都已經完成。

我會提供一個賞金和/或upvote的答案,但沒有足夠的代表點。我今天會決定一個答案,所以讓他們進來吧!謝謝。

回答

0

這得到第一<value>元素的值含有"SECOND_WANTED_KEY"第一<key>元件之後:

XDocument doc; 

string result = (string)doc.Root 
          .Elements("key") 
          .First(node => (string)node == "SECOND_WANTED_KEY") 
          .ElementsAfterSelf("value") 
          .First(); 

根據需要添加null檢查。

+0

感謝您的回覆 - 有道理 - 我可以爲每個鍵添加多個類似的語句。有關我上面添加/澄清的任何想法? – awshepard 2010-04-07 17:06:42

+0

我認爲這與我所尋找的是最接近的,但如果有任何人有更多的建議,我就會全神貫注。謝謝。 – awshepard 2010-04-12 13:48:05

0
XDocument doc = ... 

var wantedKeyValuePairs = 
    from keyElement in doc.Root.Elements("key") 
    let valueElement = keyElement.ElementsAfterSelf("value").First() 
    select new { Key = keyElement.Value, Value = valueElement.Value } into kvp 
    group kvp by kvp.Key into g 
    select g.First(); 

說明:這個查詢需要每個<key>元素及其以下<value>元件,並且使得一個鍵 - 值對與這些元件。然後按鍵對鍵值對進行分組,每個鍵只使用第一個鍵值對

+0

謝謝 - 這是否支持「過濾」,可能有一些我不想要的鍵值對?舉例來說,如果 UNWANTED_KEY UNWANTED_VALUE 出現了,這會不會能夠把它撿起來? – awshepard 2010-04-07 17:01:14

+0

你只需要在第一個'select'之後添加一個額外的'where'子句:'其中kvp.Key!=「UNWANTED_KEY」' – 2010-04-07 18:54:25