与LINQ to XML结合

deikduxw  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(145)

我需要将两组XElements合并为一组唯一的元素。使用.Union()扩展方法,我只得到一个“union all”而不是一个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())
                   )
               );

字符串

au9on6nz

au9on6nz1#

你的第一个冲动几乎是正确的。:)根据大卫B,如果你不告诉LINQ你是如何定义相等的,然后给予它一堆XElements,它会通过引用来比较它们。幸运的是,你可以通过指定IEqualityComparer‹XElement›来告诉它使用不同的标准(基本上,一个对象有一个Equals方法,当两个XElements根据你的定义相等时返回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.›;

 }

 }


注意事项:我家里没有这个框架,所以没有测试确切的代码,IcontrityComparer代码来自here(向下滚动到第二篇文章)。

yx2lnoni

yx2lnoni2#

如果不知道你是用什么来得出这个结论的,就很难解决你的“左连接”问题。

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的真正含义)中,引用类型的联合使用引用相等来测试重复。XElement是一种引用类型。

bmvo0sr5

bmvo0sr53#

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

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

字符串
一定有更好的办法。

epfja78i

epfja78i4#

像这样的呢?

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

字符串

相关问题