2009-02-02 10 views
5

मुझे XElements के दो सेटों को एक एकल, अद्वितीय तत्वों में सेट करने की आवश्यकता है। .Union() एक्सटेंशन विधि का उपयोग करके, मुझे बस एक संघ के बजाय "यूनियन सब" मिलता है। क्या मैं कुछ भूल रहा हूँ?यूनियन के साथ LINQ से XML

var elements = xDocument.Descendants(w + "sdt") 
        .Union(otherDocument.Descendants(w + "sdt") 
        .Select(sdt => 
         new XElement(
          sdt.Element(w + "sdtPr") 
           .Element(w + "tag") 
           .Attribute(w + "val").Value, 
          GetTextFromContentControl(sdt).Trim()) 
        ) 
       ); 

उत्तर

4

आपका पहला आवेग लगभग सही था। :) प्रति डेविड B के रूप में, यदि आप LINQ नहीं बताया कि वास्तव में आप कैसे समानता को परिभाषित करने और फिर इसे XElements का एक समूह देना, यह उन्हें संदर्भ से तुलना करेंगे। सौभाग्य से, आप इसे एक IEqualityComparer निर्दिष्ट करके विभिन्न मानदंडों का उपयोग करने के लिए कह सकते हैं (मूल रूप से, एक ऑब्जेक्ट जिसमें एक समान विधि है जो सत्य लौटाती है यदि दो XElements आपकी परिभाषा के अनुसार बराबर हैं और अन्यथा और गेटहैशकोड विधि जो XElement लेती है और आपके समानता मानदंडों के आधार पर एक हैश कोड देता है)।

उदाहरण के लिए

:

var elements = xDocument.Descendants(w + "sdt") 
       .Union(otherDocument.Descendants(w + "sdt", new XElementComparer()) 
       .RestOfYourCode 

...

अपनी परियोजना में कहीं और

public class XElementComparer : IEqualityComparer‹XElement› { 
    public bool Equals(XElement x, XElement y) { 
    return ‹X and Y are equal according to your standards›; 
} 


public int GetHashCode(XElement obj) { 
    return ‹hash code based on whatever parameters you used to determine   
      Equals. For example, if you determine equality based on the ID 
      attribute, return the hash code of the ID attribute.›; 

} 

} 

नोट: इतना सटीक कोड नहीं है मैं घर पर ढांचे की जरूरत नहीं है परीक्षण और IEqualityComparer कोड here से है (दूसरी पोस्ट तक स्क्रॉल करें)।

+0

यह सही था। धन्यवाद! –

0

यह वास्तव में देखकर यह क्या आपको लगता है कि निष्कर्ष पर आने के उपयोग कर रहे हैं के बिना अपने "बाएं में शामिल होने के" अवलोकन निवारण करने के लिए मुश्किल है। अंधेरे में मेरा शॉट यहाँ है।

XDocument doc1 = XDocument.Parse(@"<XML><A/><C/></XML>"); 
XDocument doc2 = XDocument.Parse(@"<XML><B/><C/></XML>"); 
// 
var query1 = doc1.Descendants().Union(doc2.Descendants()); 
Console.WriteLine(query1.Count()); 
foreach (XElement e in query1) Console.WriteLine("--{0}",e.Name); 

6 
--XML 
--A 
--C 
--XML 
--B 
--C 
// 
var query2 = doc1.Descendants().Concat(doc2.Descendants()) 
    .GroupBy(x => x.Name) 
    .Select(g => g.First()); 
Console.WriteLine(query2.Count()); 
foreach (XElement e in query2) Console.WriteLine("--{0}", e.Name); 

4 
--XML 
--A 
--C 
--B 
वस्तुओं के लिए

LINQ में (जो एक्सएमएल के लिए क्या LINQ वास्तव में है), संदर्भ प्रकार के खिलाफ संघ डुप्लिकेट के लिए परीक्षण करने के लिए संदर्भ समानता का उपयोग करता है। XElement एक संदर्भ प्रकार है।

+0

बाहर निकलता है कि मैं अपने "बाएं शामिल" मुद्दे के बारे में गलत था। वह मेरी गलती थी। हालांकि, यूनियन ऑपरेटर "यूनियन ऑल" लौटाता है (इसे प्रतिबिंबित करने के लिए मेरे मूल प्रश्न को संपादित किया गया है)। मैं तुम्हारा समाधान आज़माउंगा। –

+0

यह मेरे लिए काम नहीं कर रहा है क्योंकि तत्वों में अंतर पोते तत्वों का गुण मूल्य है (नीचे मेरी प्रतिक्रिया देखें)। –

0

मैं काम करने के लिए निम्न प्राप्त करने में सक्षम था, लेकिन यह काफी बदसूरत है:

var elements = xDocument.Descendants(w + "sdt") 
        .Concat(otherDocument.Descendants(w + "sdt") 
           .Where(e => !xDocument.Descendants(w + "sdt") 
               .Any(x => x.Element(w + "sdtPr") 
                  .Element(w + "tag") 
                  .Attribute(w + "val").Value == 
                 e.Element(w + "sdtPr") 
                  .Element(w + "tag") 
                  .Attribute(w + "val").Value))) 
        .Select(sdt => 
         new XElement(
          sdt.Element(w + "sdtPr") 
           .Element(w + "tag") 
           .Attribute(w + "val").Value, 
          GetTextFromContentControl(sdt).Trim()) 
        ) 
       ); 

निश्चित रूप से वहाँ एक बेहतर तरीका होना चाहिए।

0

इस तरह कुछ के बारे में क्या?

var xDoc = from f in xDocument.Descendants(w + "sdt") 
    select new {xNode = f, MatchOn = f.Element(w + "sdtPr").Element(w + "tag").Attribute(w + "val").Value }; 

var oDoc = from o in otherDocument.Descendants(w + "sdt") 
    select new {MatchOn = o.Element(w + "sdtPr").Element(w + "tag").Attribute(w + "val").Value }; 

var elements = from x in xDoc.Where(f => !oDoc.Any(o => o.MatchOn == f.MatchOn)) 
    select new XElement(x.MatchOn, GetTextFromContentControl(x.xNode).Trim()); 
संबंधित मुद्दे