我需要合并一个xml的未知结构。请求是层次结构不会更改:
XDocument xDoc1 = XDocument.Parse(@"<Root>
<LeafA>
<a>item1</a>
</LeafA>
<LeafA>
<b>item3</b>
</LeafA>
</Root>");
XDocument xDoc2 = XDocument.Parse(@"<Root>
<LeafA>
<a>item2</a>
</LeafA>
<LeafA>
<b>item4</b>
</LeafA>
</Root>");
Merge(xDoc1.Root, xDoc2.Root);
到目前为止我已经
了void Merge(XElement left, XElement right)
{
foreach (var node in right.Elements())
{
if (left.Element(node.Name.LocalName) == null)
{
left.Add(node);
}
}
foreach (var x in right.Elements().Where(r => left.Element(r.Name.LocalName) != null))
{
Merge(left.Element(x.Name.LocalName),x);
}
}
这给了我
的输出<Root>
<LeafA>
<a>item1</a>
<b>item4</b>
</LeafA>
<LeafA>
<b>item3</b>
</LeafA>
</Root>
但必须是
<Root>
<LeafA>
<a>item1</a>
<a>item2</a>
</LeafA>
<LeafA>
<b>item3</b>
<b>item4</b>
</LeafA>
</Root>
答案 0 :(得分:0)
这解决了我的问题:
public static void Merge(XElement left, XElement right)
{
foreach (XElement node in right.Elements())
{
int num = MergeXml.NodeWithSameNameAtSameHierarchyLevel(left, node);
if (num == 0)
{
left.Add(node);
}
else
{
if (MergeXml.IsFirstIteration(left, right) && !node.HasElements)
{
left.Add(node);
}
else
{
if (num == 1)
{
MergeXml.CheckDescandants(left, node);
}
else
{
if (node.Descendants().Any<XElement>() && node.Descendants().First<XElement>().Name.LocalName.Equals(node.Name.LocalName))
{
MergeXml.CheckDescandants(left, node);
}
else
{
int num2 = node.ElementsBeforeSelf().Count((XElement x) => x.Name.LocalName.Equals(node.Name.LocalName));
foreach (XElement current in node.Elements())
{
if (current.HasElements)
{
if (MergeXml.ItemNodeExistInLeftFile(left, node, num2) || MergeXml.ItemNodeDescandandsDontHaveAnyElements(current))
{
MergeXml.CheckDescandants(left, current, num2);
}
else
{
(
from x in left.Elements()
where x.Name.LocalName.Equals(node.Name.LocalName)
select x).ElementAt(num2).Add(current);
}
}
else
{
(
from x in left.Elements()
where x.Name.LocalName.Equals(node.Name.LocalName)
select x).ElementAt(num2).Add(current);
}
}
}
}
}
}
}
}
public static XDocument MergeXmlFiles(List<XDocument> docs)
{
MergeXml.Merge(docs[0].Root, docs[1].Root);
MergeXml.Merge(docs[0].Root, docs[2].Root);
return docs[0];
}
private static void CheckDescandants(XElement left, XElement node)
{
if (node.Descendants().Count((XElement x) => x.HasElements) > 0)
{
MergeXml.Merge(left.Element(node.Name.LocalName), node);
return;
}
if (left.Element(node.Name.LocalName) != null)
{
if (node.HasElements)
{
left.Element(node.Name.LocalName).Add(node.Descendants());
return;
}
left.Element(node.Name.LocalName).Add(node);
return;
}
else
{
if (node.HasElements)
{
left.Add(node.Descendants());
return;
}
left.Add(node);
return;
}
}
private static void CheckDescandants(XElement left, XElement node, int recursivCallIndex)
{
if (node.Descendants().Count((XElement x) => x.HasElements) > 0)
{
MergeXml.Merge(left.Elements().ElementAt(recursivCallIndex).Element(node.Name.LocalName), node);
return;
}
IEnumerable<XElement> source =
from x in left.Elements().ElementAt(recursivCallIndex).Descendants()
where x.Name == node.Name
select x;
if (source.Count<XElement>() > 0)
{
source.ElementAt(0).Add(node.Descendants());
return;
}
left.Elements().ElementAt(recursivCallIndex).Add(node);
}
private static bool IsFirstIteration(XElement left, XElement right)
{
return left.Parent == null && right.Parent == null;
}
private static bool ItemNodeDescandandsDontHaveAnyElements(XElement item)
{
return item.Descendants().Count((XElement x) => x.HasElements) == 0;
}
private static bool ItemNodeExistInLeftFile(XElement left, XElement node, int positionNodeInXmlIndex)
{
return left.Elements().ElementAt(positionNodeInXmlIndex).Element(node.Name.LocalName) != null;
}
private static int NodeWithSameNameAtSameHierarchyLevel(XElement left, XElement node)
{
if (!left.Descendants().Any<XElement>())
{
return 0;
}
if (left.Descendants().Count((XElement x) => x.Name.LocalName.Equals(node.Name.LocalName)) == 0)
{
return 0;
}
return left.Descendants().Count((XElement x) => x.Name.LocalName.Equals(node.Name.LocalName) && DivideXml.HasSameParentName(x, node));
}