我需要将两组 XElement 合并为一组唯一的元素。使用 .Union() 扩展方法,我只得到一个“union all”而不是联合。我错过了什么吗?

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())
                   )
               );
有帮助吗?

解决方案

你的第一个冲动几乎是正确的。:) 根据 大卫·B, ,如果您没有准确地告诉 LINQ 如何定义相等性,然后给它一堆 XElement,它会通过引用来比较它们。幸运的是,您可以通过指定 IEqualityComparer<XElement>(基本上,一个具有 Equals 方法的对象,当两个 XElement 根据您的定义相等时返回 true,否则返回 false,以及采用 XElement 的 GetHashCode 方法来告诉它使用不同的条件并根据您的相等标准返回哈希码)。

例如:

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代码来自 这里 (向下滚动到第二篇文章)。

其他提示

这真的很难解决你的“左连接”观察没有看到什么是你正在使用,以得出这个结论。这是我在黑暗中拍摄。

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到XML真的是),联合针对引用类型使用参考平等来测试重复。的XElement是引用类型。

我能够得到以下工作,但它是相当难看:

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

当然,必须有更好的方法。

关于这样的事情是什么?

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());
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top