合并c#中具有相同结构的两个xml的属性

时间:2016-10-18 08:07:08

标签: c# xml linq linq-to-xml

我有两个不同的XML,结构如下:

XML 1:

<function>
    <subfunction id="s1" value="s1">
        <display id="1" value="a"></display>
        <display id="2" value="b"></display>
        <display id="3" value="c"></display>
        <display id="4" value="d"></display>
    </subfunction>
</function>

XML 2:

<function>
    <subfunction id="s1" some-value="other">
        <display id="1" another-data="something"></display>
        <display id="2" another-data="something"></display>
        <display id="3" another-data="something"></display>
        <display id="4" another-data="something"></display>
    </subfunction>
</function>

我想合并这两个XML,所以最终输出如下所示:

<function>
    <subfunction id="s1" value="s1" some-value="other">
        <display id="1" value="a" another-data="something"></display>
        <display id="2" value="b" another-data="something"></display>
        <display id="3" value="c" another-data="something"></display>
        <display id="4" value="d" another-data="something"></display>
    </subfunction>
</function>

目前我在C#中使用forEach循环来合并这两个非常低效的XML。有没有其他方法可以一次执行此操作?

我正在使用以下代码进行合并

public XmlDocument MergeXMLAttributes(XmlDocument doc, XmlDocument trimmedXmlDoc)
{
var nodes = trimmedXmlDoc.DocumentElement.SelectNodes("//*");
foreach (XmlElement displayNode in nodes)
{
    var nodeId = displayNode.GetAttribute("id");
    var nodeXPath = String.Format("//*[@id='{0}']", nodeId);
    XmlElement fullNode = doc.SelectSingleNode(nodeXPath) as XmlElement;

      foreach (XmlAttribute attribute in displayNode.Attributes)
      {
         fullNode.SetAttribute(attribute.Name, attribute.Value);
      }
   }
   return doc;
}

1 个答案:

答案 0 :(得分:1)

        static void Main(string[] args)
        {
            var xml1 = XElement.Parse(@"<function>
    <subfunction id=""s1"" value=""s1"">
        <display id=""1"" value=""a""></display>
        <display id=""2"" value=""b""></display>
        <display id=""3"" value=""c""></display>
        <display id=""4"" value=""d""></display>
    </subfunction>
</function>");
            var xml2 = XElement.Parse(@"<function>
    <subfunction id=""s1"" some-value=""other"">
        <display id=""1"" another-data=""something""></display>
        <display id=""2"" another-data=""something""></display>
        <display id=""3"" another-data=""something""></display>
        <display id=""4"" another-data=""something""></display>
    </subfunction>
</function>");
            var xml3 = Merge(xml1, xml2);
            Console.WriteLine(xml3.ToString());
            Console.ReadLine();
        }

        private static XElement Merge(XElement thisElement, XElement otherElement)
        {
            if(thisElement.Name == otherElement.Name)
            {
                var merged = new XElement(thisElement.Name);
                merged.ReplaceAttributes(Attributes(thisElement, otherElement).ToArray());
                var thisChildren = thisElement.Elements().Where(e => e.Attribute("id") != null);
                if(thisChildren.Any())
                {
                    var children = thisChildren.Select(thisChild => {
                        var otherChild = otherElement
                            .Elements()
                            .Where(e => e.Attribute("id") != null && e.Attribute("id").Value == thisChild.Attribute("id").Value)
                            .FirstOrDefault();
                        if(otherChild != null)
                        {
                            return Merge(thisChild, otherChild);
                        }
                        return null;
                    }).Where(child => child != null);
                    merged.Add(children.ToArray());
                }
                return merged;
            }
            return null;
        }

        private static IEnumerable<XAttribute> Attributes(XElement thisElement, XElement otherElement)
        {
            return thisElement
                .Attributes()
                .Concat(otherElement.Attributes())
                .GroupBy(a => a.Name)
                .Select(g => g.FirstOrDefault())
                .Where(a => a != null);
        }