2011-06-24 74 views
6

2つのXMLファイルがあり、この2つのファイルを1つにマージしたい。 どのように?私はたくさん試しましたが、何も助けません。 マージされたXMLは、最初のXMLからのものであれば、2番目の属性のテキストを残しています。 第2の要素は、第1の属性が持つId/Name/whatevernameによって順序付けされなければなりません。 3番目のノードがXML 2に存在しない場合は、XML 1と同じ場所にノードを作成する必要があります。2つのXMLファイルをC#とマージする方法

ここで示されている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=""/> 

すべての回答のためにThanxしかし、私はタグがどのようにしているかわからないという問題があるので、タグをハードコードすることはできません。

私はちょうどそれがどのように見えるかの例を伝えなければなりません。しかし、次にXMLファイルを取得したとき、上のタグは全く異なる場合があります。それが問題の場所です。だから、このタグがもう存在しないので、新しいXElement( "BO"、boChildren)を言うことができません。

またはこれはハードコードできません==> var cars = xDocuments.SelectMany(x => x.Root.Elements( "CARS"))。 XMLファイルを次に取得するときに、「CARS」はもう存在しないからです。

答えて

3

私はあなたがC#でそれをしないことをお勧めします。可能な限りXSLTを使用してみてください。これは主にxmlの変換に使用されます。

C#を使用する場合は、新しいC#3.5/4 XDocumentを使用します。 LINQベースの構文が優れているため、作業が楽になります。

7

私はLinqでXMLにこれを行うことができると思います。それらを一緒に結合した各セグメント(AC、BO、CARS、POP)に対して個別のクエリを作成し、それらをまとめて新しいドキュメントにします。

ここであなたが始めるために少し抜粋です:

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(); } 
    } 
} 

ただ、ソースドキュメント内の他のノードのために繰り返した後、一緒にすべてを置くが。

幸運、

ゲルト・ヤン

0

あなたはこのような何か持つことができます。

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(); 
0

はにいくつかのコードですあなたを始めましょう。ただし、結合された要素が元の要素からどのように生成されるかについての非常に特殊な要件があります。あなたは、拡張メソッドでそれを実装する必要があります:

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" 
    } 

} 
関連する問題