الاتحاد مع LINQ إلى XML
-
21-08-2019 - |
سؤال
ولست بحاجة لاتحاد مجموعتين من XElements إلى ذلك، مجموعة واحدة فريدة من العناصر. باستخدام طريقة تمديد .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())
)
);
المحلول
وأول دفعة لديك الصحيح تقريبا. :) وفقا على ديفيد B ، أو إذا كنت لا تقول LINQ بالضبط كيفية تعريف المساواة وثم تعطيه حفنة من XElements، سيكون مقارنتها بالرجوع . لحسن الحظ، يمكن أن أقول لكم لاستخدام معايير مختلفة لتحديد وIEqualityComparer
وعلى سبيل المثال:
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 هو من <لأ href = "http://community.sgdotnet.org/forums/t/11567.aspx" يختلط = "نوفولو noreferrer"> هنا (انزل إلى آخر الثانية).
نصائح أخرى
وانه من الصعب حقا لاستكشاف الخاص المراقبة "الانضمام اليسار" دون أن يرى ما هو عليه كنت تستخدم للوصول إلى هذا الاستنتاج. وهنا قال لي طلقة في الظلام.
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 إلى كائنات (وهو ما LINQ إلى XML هو حقا)، الاتحاد ضد أنواع المراجع يستخدم المساواة إشارة لاختبار التكرارات. XElement هو نوع مرجع.
وكنت قادرا على الحصول على ما يلي للعمل، لكنه هو قبيح جدا:
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())
)
);
وبالتأكيد يجب أن يكون هناك طريقة أفضل.
وماذا عن شيء مثل هذا؟
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());