0

我需要合并一个未知结构的 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>
4

1 回答 1

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));
    }
于 2013-05-16T11:27:46.757 回答