Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to merge xml streams

Tags:

c#

xml

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?

like image 652
user3710760 Avatar asked Jun 25 '15 18:06

user3710760


People also ask

How do I combine multiple XML files into one?

To use this, create a new XSLT file (File > New > XSLT Stylesheet and place in it the stylesheet above. Save the file as "merge. xsl". You should also add the files (or folder) to an Oxygen project (Project view) and create a scenario of the "XML transformation with XSLT" type for one XML file.

Can we merge two XML files?

It is possible to use XML Merge as the underlying merge tool in your version control system for XML content.

What is XML merge?

The XML Merge component is a transformation component used to take incoming data from upstream SSIS source components and merge them into one SSIS column data based on the XML data structure defined in the component. This data can be then consumed by a downstream pipeline component.


1 Answers

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);
    }
  }
}
like image 166
Gaurav Gupta Avatar answered Sep 27 '22 17:09

Gaurav Gupta