Frage

Ich muß Union zwei Sätze von XElements in einen einzigen, einzigartigen Satz von Elementen. Mit Hilfe der .Union () Erweiterungsmethode, bekomme ich nur eine „union all“ statt eine Gewerkschaft. Bin ich etwas fehlt?

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())
                   )
               );
War es hilfreich?

Lösung

Ihr erster Impuls war fast richtig. :) Wie pro David B , wenn Sie LINQ nicht genau sagen, wie Sie Gleichheit definieren und dann eine Reihe von XElements geben, wird er sich durch Bezugnahme vergleichen . Zum Glück, können Sie es sagen können verschiedene Kriterien zu verwenden, indem Angabe eines IEqualityComparer (im Grunde, ein Objekt, das ein Gleichheits Methode, die true zurückgibt, genau dann, wenn zwei XElements gleich nach Ihrer Definition und andernfalls false und eine GetHashCode-Methode, die eine XElement nimmt und gibt einen Hash-Code auf der Grundlage Ihrer Gleichheit Kriterien).

Zum Beispiel:

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

...

Irgendwo anders in Ihrem Projekt

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.›;

 }

 }

Hinweis: Ich habe nicht den Rahmen zu Hause habe, so der genaue Code nicht getestet und der IEqualityComparer-Code ist von hier (scrollen auf den zweiten Pfosten nach unten).

Andere Tipps

Es ist wirklich hart, um Ihre „LEFT JOIN“ Beobachtung zu beheben, ohne zu sehen, was Sie zu diesem Schluss zu kommen, verwenden. Hier ist mein Schuss im Dunkeln.

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

In Linq zu Objekten (das ist, was LINQ to XML ist wirklich), Union gegen Referenztypen verwendet Verweisgleichheit auf Dubletten zu prüfen. XElement ist ein Referenztyp.

Ich war in der Lage den folgenden zur Arbeit zu kommen, aber es ist ziemlich hässlich:

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())
                   )
               );

Es muss doch einen besseren Weg geben.

Was ist so etwas wie das?

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());
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top