2009-02-02 37 views
5

Tôi cần kết hợp hai bộ XElements thành một bộ duy nhất các phần tử duy nhất. Sử dụng phương thức mở rộng .Union(), tôi chỉ nhận được một "công đoàn tất cả" thay vì một công đoàn. Tui bỏ lỡ điều gì vậy?Liên kết với LINQ to XML

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

Trả lời

4

xung đầu tiên của bạn là gần như chính xác. :) Theo David B, nếu bạn không biết chính xác có bao LINQ bạn xác định sự bình đẳng và sau đó cung cấp cho nó một loạt các XElements, nó sẽ so sánh chúng bằng cách tham khảo. May mắn thay, bạn có thể yêu cầu nó sử dụng các tiêu chuẩn khác nhau bằng cách chỉ định một IEqualityComparer ‹XElement› (về cơ bản, một đối tượng có phương thức Equals trả về true iff hai XElements là bằng nhau theo định nghĩa của bạn và sai khác và phương thức GetHashCode lấy một XElement và trả về mã băm dựa trên tiêu chí bình đẳng của bạn).

Ví dụ:

var elements = xDocument.Descendants(w + "sdt") 
       .Union(otherDocument.Descendants(w + "sdt", new XElementComparer()) 
       .RestOfYourCode 

...

Một nơi nào đó khác trong dự án của bạn

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

} 

} 

Lưu ý: Tôi không có khuôn khổ ở nhà, vì vậy mã chính xác không phải là kiểm tra và mã IEqualityComparer là từ here (cuộn xuống bài đăng thứ hai).

+0

Điều này thật hoàn hảo. Cảm ơn! –

0

Thật khó khắc phục sự quan sát "tham gia trái" của bạn mà không thấy bạn đang sử dụng cái gì để đi đến kết luận đó. Đây là ảnh của tôi trong bóng tối.

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 

Trong LINQ to objects (là linq to xml thực sự), Liên kết với các loại tham chiếu sử dụng bình đẳng tham chiếu để kiểm tra trùng lặp. XElement là một kiểu tham chiếu.

+0

Hóa ra tôi đã sai về vấn đề "tham gia trái" của tôi. Đó là lỗi của tôi. Tuy nhiên, toán tử Union trả về "union tất cả" (đã chỉnh sửa câu hỏi ban đầu của tôi để phản ánh điều này). Tôi sẽ thử giải pháp của bạn. –

+0

Điều này không hiệu quả đối với tôi vì sự khác biệt trong các phần tử là giá trị thuộc tính của các phần tử cháu (xem phản hồi của tôi bên dưới). –

0

tôi đã có thể nhận được như sau để làm việc, nhưng nó là khá xấu xí:

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

Chắc chắn phải có một cách tốt hơn.

0

Còn thứ gì đó như thế này?

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()); 
Các vấn đề liên quan