简体   繁体   中英

How to merge xml streams

I have multiple xml streams with this format:

xml1:

<?xml version="1.0" encoding="utf-8"?>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test2</NodeB>
      <NodeC>
         <Att>test4</Att>
         <Value1>1.0</Value1>
      </NodeC>
</Node>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test7</NodeB>
      <NodeC>
         <Att>test8</Att>
         <Value1>2.0</Value1>
      </NodeC>
</Node>
...

xmlN:

<?xml version="1.0" encoding="utf-8"?>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test2</NodeB>
      <NodeC>
         <Att>test4</Att>
         <ValueN>5.0</ValueN>
      </NodeC>
</Node>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test7</NodeB>
      <NodeC>
         <Att>test8</Att>
         <ValueN>6.0</ValueN>
      </NodeC>
</Node>
<Node>
      <NodeA>test9</NodeA>
      <NodeB>test8</NodeB>
      <NodeC>
         <Att>test8</Att>
         <ValueN>6.0</ValueN>
      </NodeC>
</Node>

I want the merged xml to look like this:

<?xml version="1.0" encoding="utf-8"?>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test2</NodeB>
      <NodeNEW>test4</Att>
      <Value1>1.0</Value1>
      <ValueN>5.0</ValueN>
</Node>
<Node>
      <NodeA>test1</NodeA>
      <NodeB>test7</NodeB>
      <NodeNEW>test8</NodeNEW>
      <Value1>2.0</Value1>
      <ValueN>6.0</ValueN>
</Node>
<Node>
      <NodeA>test9</NodeA>
      <NodeB>test8</NodeB>
      <NodeNEW>test8</NodeNew>
      <Value1></Value1>
      <ValueN>6.0</ValueN>

</Node>

So I create unique keys NodeA>NodeB>NodeNEW with different Value1, ... ValueN which are assigned nothing if this unique key does not appear in its respective xml.

What would be the most efficient way to do this?

Below code should give you desired results it will not show the value of previous nodes if it is not published but you can play around and get that working too. Idea here is to read items using XMLReader and update existing nodes in the same iteration.

    static void Main(string[] args) {

  //Ideally you should have well formed xml with root element as eg given below
  //but since it is stream it is possible but not sure how much control you have on it.
  //eg: <Nodes><Node1/><Node2/>...</Nodes> 

  //Reading your data from locally stored stream files
  var streamFiles=new[] { @"C:\temp\stack\xml1.xml", @"C:\temp\stack\xmlN.xml" };

  var dict = new Dictionary<int,XElement>();

  foreach(var streamFile in streamFiles) {
    using(var reader=XmlReader.Create(streamFile, new XmlReaderSettings { ConformanceLevel=ConformanceLevel.Fragment })) {
      var nodeNo=0;
      while(reader.MoveToContent()==XmlNodeType.Element) {
        var element=XNode.ReadFrom(reader) as XElement;
        //Now merge the data. Yahoo
        XElement currentElement;
        if(!dict.TryGetValue(nodeNo, out currentElement)) {
          currentElement = new XElement("Node");
          dict.Add(nodeNo, currentElement);
        }

        foreach(var el in element.Elements().Where(e => !e.HasElements)) {
          currentElement.SetElementValue(el.Name, el.Value);
        }

        currentElement.SetElementValue("NodeNEW",
          element.Elements().Where(e => e.HasElements)
            .SelectMany(e => e.Elements()
              .Where(w => w.Name=="Att"))
            .FirstOrDefault().Value);

        currentElement.Add(element.Elements().Where(e => e.HasElements)
          .SelectMany(e => e.Elements()
            .Where(w => w.Name!="Att")));

        nodeNo++;
      }
    }
  }

  using(var writer=XmlWriter.Create(@"C:\temp\stack\xmlMerged.xml",
    new XmlWriterSettings {
      ConformanceLevel=ConformanceLevel.Fragment,
      Indent=true
    })) {
    foreach(var element in dict.Values) {
      element.WriteTo(writer);
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM