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

Popular posts from this blog

c++ - No viable overloaded operator for references a map -

java - Custom OutputStreamAppender not run: LOGBACK: No context given for <MYAPPENDER> -

java - Cannot secure connection using TLS -