【问题标题】:How to merge 2 XML files with C#如何用 C# 合并 2 个 XML 文件
【发布时间】:2011-06-24 12:28:52
【问题描述】:

我有两个 XML 文件,我想将这两个文件合并为一个。 但是怎么做?我已经尝试了很多,但没有任何帮助。 如您所见,如果合并后的 XML 来自第一个 XML,那么它会留下来自第二个属性的文本。 其次,元素必须按第一个属性的 Id/Name/whatevername 排序。 第三,如果 XML 2 中不存在节点,则必须在与 XML 1 相同的位置创建它。

这里显示的 XML 文件只是整个 XML 的一个片段,还有很多属性名称。

如何用 C# 做到这一点?

XML 1

<APPLICATION>
    <AC>
            <CLASS Name="Hello1" Capt="do1"/>
            <CLASS Name="Hello2" Capt="do2"/>
            <CLASS Name="Hello5" Capt="do5"/>
            <CLASS Name="Hello8" Capt="do8"/>
    </AC>

    <BO>
            <ITEM Id="1" DefaultValue="name1"/>
            <ITEM Id="3" DefaultValue="name3"/>
            <ITEM Id="11" DefaultValue="name11"/>
            <ITEM Id="12" DefaultValue="name12">
                    <VAL>
                            <REASON Id="Job1" SecondOne="Hallo"/>
                    </VAL>
            </ITEM>
    </BO>
    <POP Id="Green" Value="Monster"/>
    <POP Id="Blue" Value="Doggie"/>

XML 2

<APPLICATION>
    <AC>
            <CLASS Name="Hello1" Capt="dodo1"/>
            <CLASS Name="Hello2" Capt="dodo2"/>
            <CLASS Name="Hello3" Capt="dodo3"/>
            <CLASS Name="Hello9" Capt="dodo9"/>
    </AC>
    <CARS Wheel="Fore" Default="45x255xZ"/>
    <CARS Wheel="BACK" Default="45x255xZ"/>
    <CARS Wheel="SPARE" Default="45x255xZ"/>
    <BO>
            <ITEM Id="1" DefaultValue="namename1"/>
            <ITEM Id="3" DefaultValue=""/>
            <ITEM Id="9" DefaultValue="name11"/>
            <ITEM Id="10" DefaultValue="name12">
                    <VAL>
                            <REASON Id="Job1" SecondOne="Hallo"/>
                    </VAL>
            </ITEM>
    </BO>

合并后的 XML 应该如下所示:

<APPLICATION>
    <AC>
            <CLASS Name="Hello1" Capt="dodo1"/>
            <CLASS Name="Hello2" Capt="dodo2"/>
            <CLASS Name="Hello3" Capt="dodo3"/>
            <CLASS Name="Hello5" Capt=""/>
            <CLASS Name="Hello8" Capt=""/>
            <CLASS Name="Hello9" Capt="dodo9"/>
    </AC>
    <CARS Wheel="Fore" Default="45x255xZ"/>
    <CARS Wheel="BACK" Default="45x255xZ"/>
    <CARS Wheel="SPARE" Default="45x255xZ"/>
    <BO>
            <ITEM Id="1" DefaultValue="namename1"/>
            <ITEM Id="3" DefaultValue=""/>
            <ITEM Id="9" DefaultValue="name11"/>
            <ITEM Id="10" DefaultValue="name12">
                    <VAL>
                            <REASON Id="Job1" SecondOne="Hallo"/>
                    </VAL>
            </ITEM>
            <ITEM Id="11" DefaultValue=""/>
            <ITEM Id="12" DefaultValue="">
                    <VAL>
                            <REASON Id="Job1" SecondOne=""/>
                    </VAL>
            </ITEM>
    </BO>
    <POP Id="Green" Value=""/>
    <POP Id="Blue" Value=""/>

感谢所有答案,但我仍然有一个问题,我不知道标记名是如何的,所以我无法对标记进行硬编码。

我只需要给你一个例子就可以了。但是下次我得到我的 XML 文件时,上面的标签可能会完全不同。这就是问题所在。所以不能说new XElement("BO", boChildren),因为下次这个标签就不存在了。

或者我不能硬编码这个 ==> var cars = xDocuments.SelectMany(x => x.Root.Elements("CARS")).Merge();因为下次我获取 XML 文件时,“CARS”不再存在。

【问题讨论】:

    标签: c# xml linq


    【解决方案1】:

    我认为您可以使用 Linq to XML 做到这一点。为将它们连接在一起的每个段(AC、BO、CARS、POP)创建单独的查询,然后将它们放在一个新文档中。

    这里有一个小 sn-p 帮助您入门:

    using System.Collections.Generic;
    using System.Linq;
    using System.Xml.Linq;
    
    namespace XML_Merge {
        class Program {
            static void Main(string[] args) {
    
                // load two xdocs
                var x1 = XDocument.Load("x1.xml");
                var x2 = XDocument.Load("x2.xml");
    
                // select the CLASS nodes from each
                var c1 = x1.Descendants("AC").First().Descendants("CLASS");
                var c2 = x2.Descendants("AC").First().Descendants("CLASS");
    
                // this one gives the distinct union of the two, you can put that into the result xdoc.
                var cComb =
                    c1
                    .Union(c2)
                    .Distinct(new ClassComparer()) // this uses the IEqualityComparer from below
                    .OrderBy(c => c.Attribute("Name").Value);
            }
        }
    
        // This is required for Union to work. (Also Intersect etc)
        class ClassComparer : IEqualityComparer<XElement> {
            public bool Equals(XElement x, XElement y) { return x.Attribute("Name").Value == y.Attribute("Name").Value; }
            public int GetHashCode(XElement obj) { return obj.Attribute("Name").Value.GetHashCode(); }
        }
    }
    

    只需重复源文档中的其他节点,然后将它们放在一起。

    祝你好运,

    格特-简

    【讨论】:

      【解决方案2】:

      我建议您不要使用 C# 来执行此操作。尽量使用 XSLT,主要用于转换 xml。

      如果您确实想使用 C#,请使用新的 C# 3.5/4 XDocument。它有很好的基于 LINQ 的语法,使其更易于使用。

      【讨论】:

        【解决方案3】:

        您可以使用 XmlDocument 类。 检查此链接: http://support.microsoft.com/kb/311530

        【讨论】:

          【解决方案4】:

          你可以有这样的东西:

          class APPLICATION
          {
              public APPLICATION()
              {
                  this.Classes = new List<CLASS>();
                  this.Cars = new List<CARS>();
                  this.Items = new List<ITEM>();
                  this.Pops = new List<POP>();
              }
          
              public List<CLASS> Classes { get; set; }
          
              public List<CARS> Cars { get; set; }
          
              public List<ITEM> Items { get; set; }
          
              public List<POP> Pops { get; set; }
          
              public override string ToString()
              {
                  string toString = string.Empty;
                  using (MemoryStream stream = new MemoryStream())
                  {
                      using (XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8))
                      {
                          writer.Formatting = Formatting.Indented;
                          writer.Indentation = 5;
                          writer.WriteStartDocument();
                              writer.WriteStartElement("APPLICATION");
                                  writer.WriteStartElement("AC");
                                  if (this.Classes != null && Classes.Count > 0)
                                  {
                                      foreach (CLASS c in Classes)
                                      {
                                          writer.WriteStartElement("CLASS");
                                              writer.WriteAttributeString("Name", c.Name);
                                              writer.WriteAttributeString("Capt", c.Capt);
                                          writer.WriteEndElement(); //CLASS
                                      }
                                  }
                                  writer.WriteEndElement(); //AC
          
                                  if (this.Cars != null && Cars.Count > 0)
                                  {
                                      foreach (CARS c in Cars)
                                      {
                                          writer.WriteStartElement("CARS");
                                              writer.WriteAttributeString("Wheel", c.Wheel);
                                              writer.WriteAttributeString("Default", c.Default);
                                          writer.WriteEndElement(); //CARS
                                      }
                                  }
          
                                  writer.WriteStartElement("BO");
                                  if (this.Items != null && Items.Count > 0)
                                  {
                                      foreach (ITEM c in Items)
                                      {
                                          writer.WriteStartElement("ITEM");
                                              writer.WriteAttributeString("Id", c.Id);
                                              writer.WriteAttributeString("DefaultValue", c.DefaultValue);
                                              if (c.Reason != null)
                                              {
                                                  writer.WriteStartElement("VAL");
                                                      writer.WriteStartElement("REASON");
                                                          writer.WriteAttributeString("Id", c.Reason.Id);
                                                          writer.WriteAttributeString("SecondOne", c.Reason.SecondOne);
                                                      writer.WriteEndElement(); //ITEM
                                                  writer.WriteEndElement(); //VAL
                                              }
                                          writer.WriteEndElement(); //ITEM
                                      }
                                  }
                                  writer.WriteEndElement(); //BO
                              writer.WriteEndElement(); //APPLICATION
                          writer.WriteEndDocument();
          
                          writer.Flush();
                          stream.Position = 0;
          
                          XmlTextReader reader = new XmlTextReader(stream);
          
                          reader.MoveToContent();
                          toString = reader.ReadOuterXml();
          
                          writer.Close();
                          stream.Close();
                      }
                  }
          
                  return toString;
              }
          }
          
          public class REASON
          {
              public REASON()
              {
                  Id = string.Empty;
                  SecondOne = string.Empty;
              }
          
              public string Id { get; set; }
              public string SecondOne { get; set; }
          }
          
          public class ITEM
          {
              public ITEM()
              {
                  Id = string.Empty;
                  DefaultValue = string.Empty;
              }
          
              public string Id { get; set; }
              public string DefaultValue { get; set; }
              public REASON Reason { get; set; }
          }
          
          public class CARS
          {
              public CARS()
              {
                  Wheel = string.Empty;
                  Default = string.Empty;
              }
          
              public string Wheel { get; set; }
              public string Default { get; set; }
          }
          
          public class CLASS
          {
              public CLASS()
              {
                  Name = string.Empty;
                  Capt = string.Empty;
              }
          
              public string Name { get; set; }
              public string Capt { get; set; }
          }
          
          public class POP
          {
              public POP()
              {
                  Id = string.Empty;
                  Value = string.Empty;
              }
          
              public string Id { get; set; }
              public string Value { get; set; }
          }
          

          并像这样使用它:

          APPLICATION application = new APPLICATION();
          application.Classes = ... //Populate this with classes read from xml 1 and 2.
          application.Cars = ... //Populate this with cars read from xml 1 and 2.
          application.Items = ... //Populate this with items read from xml 1 and 2.
          application.Pops = ... //Populate this with pops read from xml 1 and 2.
          string yourXmlString = application.ToString();
          

          【讨论】:

            【解决方案5】:

            这里有一些代码可以帮助您入门。但是,您对如何从原始元素生成合并元素有一些非常具体的要求。您必须在扩展方法中实现它:

            var xDocuments = new[] { XDocument.Parse(xml1), XDocument.Parse(xml2) };
            
            var acChildren = xDocuments.SelectMany(x => x.Root.Elements("AC"))
              .SelectMany(x => x.Elements()).Merge();
            var cars = xDocuments.SelectMany(x => x.Root.Elements("CARS")).Merge();
            var boChildren = xDocuments.SelectMany(x => x.Root.Elements("BO"))
              .SelectMany(x => x.Elements()).Merge();
            var pops = xDocuments.SelectMany(x => x.Root.Elements("POP")).Merge();
            
            var mergedXDocument = new XDocument(
              new XElement("APPLICATION",
                new XElement("AC", acChildren),
                cars,
                new XElement("BO", boChildren),
                pops
              )
            );
            

            扩展方法的模板如下:

            public static class Extensions {
            
              public static IEnumerable<XElement> Merge(this IEnumerable<XElement> xElements) {
                // Implement the requirement:
                // "the merged XML has left the text from the second attribute if it came from
                // the first XML"
              }
            
            }
            

            【讨论】:

              猜你喜欢
              • 2012-09-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多