Pergunta

Eu preciso união de dois conjuntos de XElements em um único conjunto, única de elementos. Usando o método de extensão .Union (), eu apenas obter uma "união tudo" em vez de uma união. Estou faltando alguma coisa?

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())
                   )
               );
Foi útil?

Solução

Seu primeiro impulso foi quase correta. :) Como por David B , se você não contar LINQ exatamente como você define a igualdade e, em seguida, dar-lhe um monte de XElements, vai compará-los por referência . Felizmente, você pode dizer que a utilização de critérios diferentes, especificando uma IEqualityComparer (basicamente, um objeto que tem um método que retorna verdadeira sse dois XElements são iguais de acordo com sua definição e falso caso contrário e um método GetHashCode que leva um XElement Igual e retorna um código de hash com base em seus critérios de igualdade).

Por exemplo:

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

...

Em outro lugar no seu projeto

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

 }

 }

Nota: Eu não tenho o quadro em casa, então o código exato não é testado eo código IEqualityComparer é de aqui (rolagem para baixo para o segundo post).

Outras dicas

É muito difícil para solucionar o seu "esquerda juntar-se" observação sem ver o que é que você está usando para chegar a essa conclusão. Aqui está o meu tiro no escuro.

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

Em LINQ to Objects (que é o LINQ to XML realmente é), União contra a referência igualdade de referência tipos usos para teste de duplicatas. XElement é um tipo de referência.

Eu era capaz de obter o seguinte para o trabalho, mas é muito feio:

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

Com certeza deve haver uma maneira melhor.

O que sobre algo assim?

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());
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top