2014-04-14 71 views
0

我想合併XML,但我有非常具體的要求。我有以下兩個XML文件:兩個XML文件的智能合併

<msg action="getcustomlists" class="lookup" ul="1"> 
    <host name="hp"/> 
</msg> 

<msg action="getcustomlists" class="newLookup" lac="statements"> 
    <environment type="lab"> 
    <login id="manual" /> 
    </environment> 
</msg> 

我要合併這兩個文件,以使這樣的事情:

<msg action="getcustomlists" class="newLookup" lac="statements" ul="1"> 
    <host name="hp"/> 
    <environment type="lab"> 
    <login id="manual" /> 
    </environment> 
</msg> 

換句話說,我需要合併屬性和元素。如果由於重複屬性而發生衝突,我們只需要用第二個文件覆蓋結果。

我試過DataSet.Merge(DataSet)。但這並沒有給我想要的結果。請幫忙。

感謝, Harit

+0

您是否嘗試過使用XSLT? – Graymatter

+0

可能的重複http://stackoverflow.com/questions/6045010/how-can-i-merge-xml-files – Graymatter

+0

我沒有。你能指點我一個參考嗎? –

回答

1

您可以使用XmlDocument的,打開這兩個來源,通過節點迭代,並在新的XmlDocument合併。

另外,使用XmlDocument,您可以使用LINQ來測試碰撞,簡化了這個任務。

XmlDocument MergeDocs(string SourceA, string SourceB) 
    { 

     XmlDocument docA = new XmlDocument(); 
     XmlDocument docB = new XmlDocument(); 
     XmlDocument merged = new XmlDocument(); 

     docA.LoadXml(SourceA); 
     docB.LoadXml(SourceB); 

     var childsFromA = docA.ChildNodes.Cast<XmlNode>(); 
     var childsFromB = docB.ChildNodes.Cast<XmlNode>(); 

     var uniquesFromA = childsFromA.Where(ch => childsFromB.Where(chb => chb.Name == ch.Name).Count() == 0); 
     var uniquesFromB = childsFromB.Where(ch => childsFromA.Where(chb => chb.Name == ch.Name).Count() == 0); 

     foreach (var unique in uniquesFromA) 
      merged.AppendChild(DeepCloneToDoc(unique, merged)); 

     foreach (var unique in uniquesFromA) 
      merged.AppendChild(DeepCloneToDoc(unique, merged)); 

     var Duplicates = from chA in childsFromA 
         from chB in childsFromB 
         where chA.Name == chB.Name 
         select new { A = chA, B = chB }; 

     foreach (var grp in Duplicates) 
      merged.AppendChild(MergeNodes(grp.A, grp.B, merged)); 

     return merged; 

    } 

    XmlNode MergeNodes(XmlNode A, XmlNode B, XmlDocument TargetDoc) 
    { 
     var merged = TargetDoc.CreateNode(A.NodeType, A.Name, A.NamespaceURI); 

     foreach (XmlAttribute attrib in A.Attributes) 
      merged.Attributes.Append(TargetDoc.CreateAttribute(attrib.Prefix, attrib.LocalName, attrib.NamespaceURI)); 

     var fromA = A.Attributes.Cast<XmlAttribute>(); 

     var fromB = B.Attributes.Cast<XmlAttribute>(); 

     var toAdd = fromB.Where(attr => fromA.Where(ata => ata.Name == attr.Name).Count() == 0); 

     foreach (var attrib in toAdd) 
      merged.Attributes.Append(TargetDoc.CreateAttribute(attrib.Prefix, attrib.LocalName, attrib.NamespaceURI)); 

     var childsFromA = A.ChildNodes.Cast<XmlNode>(); 
     var childsFromB = B.ChildNodes.Cast<XmlNode>(); 

     var uniquesFromA = childsFromA.Where(ch => childsFromB.Where(chb => chb.Name == ch.Name).Count() == 0); 
     var uniquesFromB = childsFromB.Where(ch => childsFromA.Where(chb => chb.Name == ch.Name).Count() == 0); 

     foreach (var unique in uniquesFromA) 
      merged.AppendChild(DeepCloneToDoc(unique, TargetDoc)); 

     foreach (var unique in uniquesFromA) 
      merged.AppendChild(DeepCloneToDoc(unique, TargetDoc)); 

     var Duplicates = from chA in childsFromA 
         from chB in childsFromB 
         where chA.Name == chB.Name 
         select new { A = chA, B = chB }; 

     foreach(var grp in Duplicates) 
      merged.AppendChild(MergeNodes(grp.A, grp.B, TargetDoc)); 

     return merged; 
    } 

    XmlNode DeepCloneToDoc(XmlNode NodeToClone, XmlDocument TargetDoc) 
    { 

     var newNode = TargetDoc.CreateNode(NodeToClone.NodeType, NodeToClone.Name, NodeToClone.NamespaceURI); 

     foreach (XmlAttribute attrib in NodeToClone.Attributes) 
      newNode.Attributes.Append(TargetDoc.CreateAttribute(attrib.Prefix, attrib.LocalName, attrib.NamespaceURI)); 

     foreach (XmlNode child in NodeToClone.ChildNodes) 
      newNode.AppendChild(DeepCloneToDoc(NodeToClone, TargetDoc)); 

     return newNode; 

    } 

請注意我沒有測試過,只是從內存中完成,但你有關於如何去的想法。

+1

沒有downvote你,但我會說如果你打算使用LINQ,XDocument是一個更好的選擇。或者如果你不,真的。 – Magus

+0

你能指點我一個參考嗎? –

+0

以示例更新。 – Gusman

1

使用LINQ到XML +的XDocument

創建,做一個擴展方法是:

public static XDocument MergeXml(this XDocument xd1, XDocument xd2) 
{ 
    return new XDocument(
     new XElement(xd2.Root.Name, 
      xd2.Root.Attributes() 
       .Concat(xd1.Root.Attributes()) 
       .GroupBy (g => g.Name) 
       .Select (s => s.First()), 
      xd2.Root.Elements() 
       .Concat(xd1.Root.Elements()) 
       .GroupBy (g => g.Name) 
       .Select (s => s.First()))); 
} 

要使用它:

var xd1 = XDocument.Load("test1.xml").MergeXml(XDocument.Load("test2.xml")); 

這將產生:

<msg action="getcustomlists" class="newLookup" lac="statements" ul="1"> 
    <environment type="lab"> 
    <login id="manual" /> 
    </environment> 
    <host name="hp" /> 
</msg>