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?
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.
It is possible to use XML Merge as the underlying merge tool in your version control system for XML content.
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.
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);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With