提问人: 提问时间:2/3/2009 最后编辑:Andrew Truckle 更新时间:11/14/2023 访问量:6576
与 LINQ to XML 合并
Union with LINQ to XML
问:
我需要将两组 XElements 合并为一组唯一的元素。使用扩展方法,我只得到一个“union all”而不是一个union。我错过了什么吗?.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())
)
);
答:
0赞
Amy B
2/3/2009
#1
如果不了解您用来得出该结论的是什么,就很难对“左联接”观察结果进行故障排除。这是我在黑暗中的镜头。
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 against reference types 使用引用相等性来测试重复项。XElement 是引用类型。
评论
0赞
2/3/2009
事实证明,我对我的“左加入”问题是错误的。那是我的错。但是,Union 运算符返回“union all”(编辑了我原来的问题以反映这一点)。我会尝试你的解决方案。
0赞
2/3/2009
这对我不起作用,因为元素的区别是孙子元素的属性值(请参阅下面的回复)。
0赞
user29439
2/3/2009
#2
我能够让以下内容工作,但它非常丑陋:
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())
)
);
当然,一定有更好的方法。
0赞
Dave Markle
2/3/2009
#3
这样的事情呢?
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());
4赞
Ria
2/3/2009
#4
根据 David B 的说法:)如果你不告诉 LINQ 你是如何定义相等的,然后给它一堆 XElements,它将通过引用来比较它们。幸运的是,你可以通过指定一个对象来告诉它使用不同的条件(基本上,一个对象有一个 Equals 方法,该方法返回 true iff 两个 XElement 根据你的定义相等,否则返回 false,以及一个接受 an 并根据您的相等标准返回哈希代码的方法)。IEqualityComparer‹XElement›
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 代码来自这里(向下滚动到第二篇文章)。
评论