c# - Using linq to merge multiple XML files with the same structure and removing duplicates based on a key -
i have multiple xml files i'm trying merge single file. linq xml best option i'm open ideas (xslt seems @ merging 2 files clumsy n > 2 or n = big).
from reading other questions here, 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. merges values based on third/@id attribute.
how do elegantly linq?
the below still quite ugly, , sure brought more streamlined shape bit of work, seems 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 following output file 2 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>
Comments
Post a Comment