2011-08-16 58 views
1

如何爲此做一個Linq查詢?查找Linq中兩個集合中不同的子元素

我有兩個xml文檔doc1.xml和doc2.xml。如何找到doc1中的每個「文件」元素,其中doc2具有完全相同的「路徑」屬性的「文件」元素,但doc1中此「文件」的任何「鏈接」子元素都具有「絕對路徑」屬性與doc2中相應的「file」元素中的一個或多個「絕對路徑」屬性不同?

簡單的例子:

DOC1:

<doc> 
    <file path="c:\temp\A.xml"> 
    <link absolutepath="c:\temp\B.xml"/> 
    <link absolutepath="c:\temp\C.xml"/> 
    </file> 
    <file path="c:\temp\C.xml"> <!--This should match, because it's child link absolutepath is not the same as child link absolutepath of the corresponding file with the same path in doc2--> 
    <link absolutepath="c:\temp\D.xml"/> 
    <link absolutepath="c:\temp\F.xml"/> 
    </file> 
</doc> 

DOC2:

<doc> 
    <file path="c:\temp\A.xml"> 
    <link absolutepath="c:\temp\B.xml"/> 
    <link absolutepath="c:\temp\C.xml"/> 
    </file> 
    <file path="c:\temp\C.xml"> 
    <link absolutepath="c:\temp\D.xml"/> 
    <link absolutepath="c:\temp\E.xml"/> 
    </file> 
</doc> 

任何想法?

編輯:編輯示例xml以顯示我的意思是每個文件元素的多個鏈接。所以我想要的是doc1中的每個文件都有一個鏈接元素,其絕對路徑在doc2中的鏈接元素中找不到。因此,實際上鍊接的鏈接數量相同,但絕對路徑有時可能有所不同,這就是我想要查找並提取鏈接元素中存在差異的文件。

這是我嘗試修改由Jon建議,提取多個環節的查詢,但我覺得我做錯了,因爲我沒有從得到正確的結果除了查詢算賬:

var files = from file in doc1.Descendants("file") 

       select new 
       { 
        file = file.Attribute("path").Value, 
        link = file.Elements("link").Attributes("absolutepath") 
       }; 
    var oldfiles = from file in doc2.Descendants("file") 
       from link in file.Elements("link") 
       select new 
       { 
        file = file.Attribute("path").Value, 
        link = file.Elements("link").Attributes("absolutepath") 
       }; 
    //Get the ones that are different between them 
    var missing = files.Except(oldfiles); 

回答

2

那麼,我會從XML部分開始。我最初用這種複雜得多,它需要的,但我認爲你可以使用:

var files = from file in document.Descendants("file") 
      from link in file.Elements("link") 
      select new { file = file.Attribute("path").Value, 
         link = link.Attribute("absolutepath").Value }; 

然後,如果你有files1files2(適用於每個文檔上面的查詢),你可以這樣做:

var extraFiles = files1.Except(files2); 

編輯:爲了找回這些文件的鏈接元素,你可以使用:

var linkElements = from link in file.Descendants("link") 
        join extra in extraFiles on 
         new { file = link.Parent.Attribute("path").Value, 
           link = link.Attribute("absolutepath").Value } 
         equals extra 
        select link; 

這是有點遺憾的再次查詢該文檔,但我們去...

(我選擇的鏈接元素,而不是文件中的元素,讓你可以準確的右位 - 你可以隨時選擇父元素去的文件。)

編輯:好吧,如果有多個鏈接元素,你只是想找到缺少的元素文件,這其實從我們已經有了相當簡單:

var justFiles = new HashSet<string>(extraFiles.Select(x => x.file).Distinct()); 
var fileElements = from element in file.Descendants("file") 
        where justFiles.Contains((string) element.Attribute("path") 
        select element; 
+0

謝謝你,這是偉大的!但是有沒有什麼辦法可以將XElement中的文件元素從查詢中移出?這就是我在代碼中使用的下一步在每個XElement上做的東西...... – Anders

+0

@Anders:由於'Except'的工作方式,這樣做很微妙*。你可以把元素放到投影中,然後使用MoreLINQ中的'ExceptBy' ... –

+0

好吧,但有沒有簡單的方法來做另一個查詢,從doc1獲取文件XElements,其路徑屬性值與字符串文件匹配你的查詢結果? – Anders

相關問題