5

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

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

4 回答 4

4

你的第一个冲动几乎是正确的。:) 根据David B,如果你不告诉 LINQ 你是如何定义相等的,然后给它一堆 XElement,它会通过引用来比较它们。幸运的是,您可以通过指定 IEqualityComparer‹XElement› 来告诉它使用不同的标准(基本上,一个对象具有一个 Equals 方法,如果两个 XElement 根据您的定义返回 true,否则返回 false,以及一个 GetHashCode 方法,该方法采用 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 代码来自这里(向下滚动到第二篇文章)。

于 2009-02-03T03:45:26.333 回答
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 to objects(实际上是 linq to xml)中,针对引用类型的 Union 使用引用相等来测试重复项。XElement 是一种引用类型。

于 2009-02-02T20:21:53.220 回答
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())
                   )
               );

肯定有更好的方法。

于 2009-02-02T21:26:00.827 回答
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());
于 2009-02-02T23:06:42.403 回答