【问题标题】:Merge attributes of two xml with same structure in c#在c#中合并两个具有相同结构的xml的属性
【发布时间】:2016-10-18 08:07:08
【问题描述】:

我有两个不同的 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>

我想合并这 2 个 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;
}

【问题讨论】:

  • 显示您拥有的代码。为什么它“非常低效”?您将不得不以某种方式遍历这两组元素。
  • 可以用LINQ Union或者Concat函数合并吗?
  • 你能遇到id为s10的子函数在第二个集合中不存在的情况吗?
  • 不,两个 xml 将具有完全相同数量的具有匹配 id 属性的节点

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


【解决方案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);
        }

【讨论】:

  • 这是一个示例 XML。在我的主要 XML 中,我有多个 标签。这将不起作用。
  • @AjayKumar,我已经修改了答案,使其更适用于更大的数据。
  • 谢谢它工作正常。之前的合并需要 14 秒,而只需要 62 毫秒。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-31
  • 2013-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多