与 LINQ to XML 联合

问题描述 投票:0回答:4

我需要将两组 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())
                   )
               );
c# linq linq-to-xml union openxml-sdk
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

注意:我家里没有框架,因此未测试确切的代码,IEqualityComparer 代码来自
here

(向下滚动到第二篇文章)。


0
投票

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

在 linq to 对象(这就是 linq to xml 的真正含义)中,针对引用类型的 Union 使用引用相等性来测试重复项。 XElement 是引用类型。


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

当然一定有更好的方法。


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

© www.soinside.com 2019 - 2024. All rights reserved.