使用linq合并具有相同结构的多个XML文件,并根据键删除重复项(Using linq to merge multiple XML files with the same structure and

编程入门 行业动态 更新时间:2024-10-28 22:24:39
使用linq合并具有相同结构的多个XML文件,并根据键删除重复项(Using linq to merge multiple XML files with the same structure and removing duplicates based on a key)

我有多个XML文件,我正在尝试合并到一个文件中。 Linq to XML可能是最好的选择,但我对创意持开放态度(XSLT似乎很擅长合并两个文件,但在n> 2或n = big时很笨拙)。

从这里阅读其他问题,某种联系看起来很好。

File1.xml:

<first> <second> <third id="Id1"> <values> <value a="1" b="one"/> <value a="2" b="two"/> <value a="3" b="three"/> </values> </third> <third id="Id2"> <values> <value a="f" b="foo"/> <value a="b" b="bar"/> <value a="w" b="wibble"/> </values> </third> </second> </first>

File2.xml:

<first> <second> <third id="Id1"> <values> <value a="2" b="two"/> <value a="3" b="three"/> <value a="6" b="six"/> </values> </third> <third id="Id3"> <values> <value a="x" b="ex"/> <value a="y" b="why"/> <value a="z" b="zed"/> </values> </third> </second> </first>

Merged.xml:

<first> <second> <third id="Id1"> <values> <value a="1" b="one"/> <value a="2" b="two"/> <value a="3" b="three"/> <value a="6" b="six"/> </values> </third> <third id="Id2"> <values> <value a="f" b="foo"/> <value a="b" b="bar"/> <value a="w" b="wibble"/> </values> </third> <third id="Id3"> <values> <value a="x" b="ex"/> <value a="y" b="why"/> <value a="z" b="zed"/> </values> </third> </second> </first>

即它根据第三个/ @id属性合并值。

我如何用linq优雅地做到这一点?

I have multiple XML files I'm trying to merge into a single file. Linq to XML is probably the best option but I'm open to ideas (XSLT seems good at merging TWO files but is clumsy where n > 2 or n = big).

From reading other questions here, some sort of join looks good.

File1.xml:

<first> <second> <third id="Id1"> <values> <value a="1" b="one"/> <value a="2" b="two"/> <value a="3" b="three"/> </values> </third> <third id="Id2"> <values> <value a="f" b="foo"/> <value a="b" b="bar"/> <value a="w" b="wibble"/> </values> </third> </second> </first>

File2.xml:

<first> <second> <third id="Id1"> <values> <value a="2" b="two"/> <value a="3" b="three"/> <value a="6" b="six"/> </values> </third> <third id="Id3"> <values> <value a="x" b="ex"/> <value a="y" b="why"/> <value a="z" b="zed"/> </values> </third> </second> </first>

Merged.xml:

<first> <second> <third id="Id1"> <values> <value a="1" b="one"/> <value a="2" b="two"/> <value a="3" b="three"/> <value a="6" b="six"/> </values> </third> <third id="Id2"> <values> <value a="f" b="foo"/> <value a="b" b="bar"/> <value a="w" b="wibble"/> </values> </third> <third id="Id3"> <values> <value a="x" b="ex"/> <value a="y" b="why"/> <value a="z" b="zed"/> </values> </third> </second> </first>

i.e. it merges the values based on the third/@id attribute.

How do I do this elegantly with linq?

最满意答案

下面的内容仍然相当丑陋,我相信它可以通过一些工作带入更加流线型的形状,但是现在这似乎可以完成这项工作:

public static void MergeXml() { var xdoc1 = XDocument.Load(@"c:\temp\test.xml"); var xdoc2 = XDocument.Load(@"c:\temp\test2.xml"); var d1Targets = xdoc1.Descendants("third"); var d2Selection = xdoc2.Descendants("third").ToList(); Func<XElement, XElement, string, bool> attributeMatches = (x, y, a) => x.Attribute(a).Value == y.Attribute(a).Value; Func<IEnumerable<XElement>, XElement, bool> hasMatchingValue = (ys, x) => // remove && if matching "a" should cause replacement. ys.Any(d => attributeMatches(d, x, "a") && attributeMatches(d, x, "b")); foreach (var e in d1Targets) { var fromD2 = d2Selection.Find(x => attributeMatches(x, e, "id")); if (fromD2 != null) { d2Selection.Remove(fromD2); var dest = e.Descendants("value"); dest.LastOrDefault() .AddAfterSelf(fromD2.Descendants("value").Where(x => !hasMatchingValue(dest, x))); } }; if (d2Selection.Count > 0) d1Targets.LastOrDefault().AddAfterSelf(d2Selection); xdoc1.Save(@"c:\temp\merged.xml"); }

这将从OPs问题中的两个示例输入文件生成以下输出文件:

<?xml version="1.0" encoding="utf-8"?> <first> <second> <third id="Id1"> <values> <value a="1" b="one" /> <value a="2" b="two" /> <value a="3" b="three" /> <value a="6" b="six" /> </values> </third> <third id="Id2"> <values> <value a="f" b="foo" /> <value a="b" b="bar" /> <value a="w" b="wibble" /> </values> </third> <third id="Id3"> <values> <value a="x" b="ex" /> <value a="y" b="why" /> <value a="z" b="zed" /> </values> </third> </second> </first>

The below is still quite ugly, and I am sure it could be brought into a somewhat more streamlined shape with a bit of work, but for now this seems to do the job:

public static void MergeXml() { var xdoc1 = XDocument.Load(@"c:\temp\test.xml"); var xdoc2 = XDocument.Load(@"c:\temp\test2.xml"); var d1Targets = xdoc1.Descendants("third"); var d2Selection = xdoc2.Descendants("third").ToList(); Func<XElement, XElement, string, bool> attributeMatches = (x, y, a) => x.Attribute(a).Value == y.Attribute(a).Value; Func<IEnumerable<XElement>, XElement, bool> hasMatchingValue = (ys, x) => // remove && if matching "a" should cause replacement. ys.Any(d => attributeMatches(d, x, "a") && attributeMatches(d, x, "b")); foreach (var e in d1Targets) { var fromD2 = d2Selection.Find(x => attributeMatches(x, e, "id")); if (fromD2 != null) { d2Selection.Remove(fromD2); var dest = e.Descendants("value"); dest.LastOrDefault() .AddAfterSelf(fromD2.Descendants("value").Where(x => !hasMatchingValue(dest, x))); } }; if (d2Selection.Count > 0) d1Targets.LastOrDefault().AddAfterSelf(d2Selection); xdoc1.Save(@"c:\temp\merged.xml"); }

This produces the following output file from the two example input files in OPs question:

<?xml version="1.0" encoding="utf-8"?> <first> <second> <third id="Id1"> <values> <value a="1" b="one" /> <value a="2" b="two" /> <value a="3" b="three" /> <value a="6" b="six" /> </values> </third> <third id="Id2"> <values> <value a="f" b="foo" /> <value a="b" b="bar" /> <value a="w" b="wibble" /> </values> </third> <third id="Id3"> <values> <value a="x" b="ex" /> <value a="y" b="why" /> <value a="z" b="zed" /> </values> </third> </second> </first>

更多推荐

本文发布于:2023-07-24 19:38:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1250234.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:多个   结构   文件   merge   linq

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!