[英]Smart merging of two XML files
我正在嘗試合並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)。 但這並沒有給我想要的結果。 請幫忙。
謝謝,哈里特
您可以使用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;
}
請注意,我還沒有測試過,僅從內存中進行過測試,但是您知道如何進行測試。
使用LINQ-to-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>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.