Question

Je dois réunir deux ensembles d’éléments XElements en un seul et même ensemble d’éléments. En utilisant la méthode d’extension .Union (), je viens d’obtenir une & Quot; union all & Quot; au lieu d'un syndicat. Est-ce que je manque quelque chose?

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())
                   )
               );
Était-ce utile?

La solution

Votre première impulsion était presque correcte. :) Selon David B , si vous ne dites pas à LINQ comment vous définissez l'égalité, puis lui donnez un lot de XElements, il les comparera par référence. . Heureusement, vous pouvez lui indiquer d’utiliser différents critères en spécifiant un IEqualityComparer & # 8249; XElement & # 8250; (En gros, un objet ayant une méthode Equals qui retourne true si deux XElements sont égaux selon votre définition et false sinon, et une méthode GetHashCode qui prend un XElement et renvoie un code de hachage basé sur vos critères d’égalité.)

Par exemple:

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

...

Quelque part ailleurs dans votre projet

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

 }

 }

Remarque: je n'ai pas le cadre chez moi. Le code exact n'est donc pas testé et le code IEqualityComparer provient de ici (faites défiler jusqu'au deuxième message).

Autres conseils

Il est très difficile de dépanner votre & "gauche jointure &"; observation sans voir ce que vous utilisez pour arriver à cette conclusion. Voici ma photo dans le noir.

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

Dans linq to objects (c'est ce que linq to xml est réellement), Union par rapport aux types de référence utilise l'égalité de référence pour tester les doublons. XElement est un type de référence.

J'ai pu obtenir les éléments suivants au travail, mais c'est assez moche:

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

Il doit sûrement y avoir un meilleur moyen.

Qu'en est-il de quelque chose comme ça?

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());
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top