0

I have a task that is very cumbersome, as I have to do it by hand (my company bought a tool for a ludicrous amount of money that doesn't work anymore).

I have two XML lists, each of them has half of it missing, so I need to piece it together into a third one before sending it to the system. As well as changing the header to the date I'm sending the file.

I've managed to set up the input for the date, it's easy enough to ask the user for the input. But the rest of the task is driving me mad, I tried many things I've found around here and on the Microsoft forums, to no avail... this task is killing me because I'm the only one that is "tech savvy" to do it (it's literally monkey job of copying and pasting text from XMLs).

It's not trucks and cars, obviously, and there are more files than two, but they all are like this: one kind has only cars, with an empty truck node, and the other has trucks but with empty cars node.

Example of File 1

<?xml version="1.0" encoding="utf-8"?> <document> <header> <startDate>01/01/2020</startDate> <endDate>01/02/2020</endDate> </header> <body> <cars> <car> <ID>1</ID> <Name>Blue Car</Name> </car> <car> <ID>2</ID> <Name>Red Car</Name> </car> </cars> <trucks> </trucks> </body> </document> 

Example of File 2

<?xml version="1.0" encoding="utf-8"?> <document> <header> <startDate>01/01/2020</startDate> <endDate>01/02/2020</endDate> </header> <body> <cars> </cars> <trucks> <truck> <ID>1</ID> <Name>Blue Truck</Name> </truck> <truck> <ID>2</ID> <Name>Red Truck</Name> </truck> </trucks> </body> </document> 

Example of File 3

<?xml version="1.0" encoding="utf-8"?> <document> <header> <Date>03/02/2020</Date> </header> <body> <cars> <car> <ID>1</ID> <Name>Blue Car</Name> </car> <car> <ID>2</ID> <Name>Red Car</Name> </car> </cars> <trucks> <truck> <ID>1</ID> <Name>Blue Truck</Name> </truck> <truck> <ID>2</ID> <Name>Red Truck</Name> </truck> </trucks> </body> </document> 
2
  • Can you share the C# code you have tried? Commented Sep 15, 2021 at 0:05
  • Deserialize the trucks into one instance of a matching class, then Deserialize the cars into a second instance. Finally, have a third instance into which you assign the trucks from instance1 and the cars from instance two (remember you are doing reference type assignment, not a deep copy, so it's not too expensive). Finally serialize that 3rd instance because into XML Commented Sep 15, 2021 at 2:36

3 Answers 3

1

Use XSLT:

<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="*"> <xsl:copy><xsl:apply-templates/></xsl:copy> </xsl:template> <xsl:template match="cars"> <cars> <xsl:copy-of select="car"/> <xsl:copy-of select="document('other-doc.xml')//car"/> </cars> </xsl:template> <xsl:template match="trucks"> <trucks> <xsl:copy-of select="truck"/> <xsl:copy-of select="document('other-doc.xml')//truck"/> </trucks> </xsl:template> </xsl:transform> 

This can of course be run very easily using from C# using the System.Xml.Xsl processor.

I haven't tried to do anything with the dates in the header because I'm not sure what your logic is, but that's easily added.

If you want to use a later version of XSLT it becomes a little shorter but then you need to install a third-party library:

<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:mode on-no-match="shallow-copy"/> <xsl:template match="cars"> <cars> <xsl:copy-of select="car, doc('other-doc.xml')//car"/> </cars> </xsl:template> <xsl:template match="trucks"> <trucks> <xsl:copy-of select="truck, doc('other-doc.xml')//truck"/> </trucks> </xsl:template> </xsl:transform> 
Sign up to request clarification or add additional context in comments.

2 Comments

This worked neatly, but the output document has weird line breaks, such as the "truck" tag closing and opening another in the same line, the <document> tag on the same line as the <?xml version> line.
You can fix this with <xsl:strip-space elements="*"/>
0
Please use below code string xml1 = @"<document><header><startDate>01/01/2020</startDate><endDate> 01/02/ 2020</endDate></header><body><cars><car><ID>1</ID><Name>Blue Car</Name></car><car><ID>2</ID><Name>Red Car</Name></car></cars><trucks></trucks></body></document>"; //load xml in StringReader StringReader sr = new StringReader(xml1); DataSet ds1 = new DataSet(); // Read XML in ds1 ds1.ReadXml(sr); string xml2 = @"<document><header><startDate> 01 / 01 / 2020 </startDate><endDate> 01 / 02 / 2020</endDate></header><body><cars></cars><trucks><truck><ID> 1 </ID><Name> Blue Truck </Name></truck><truck><ID>2</ID><Name>Red Truck</Name></truck></trucks></body></document>"; sr = new StringReader(xml2); DataSet ds2 = new DataSet(); ds2.ReadXml(sr); DataSet dsHeaders = new DataSet(); dsHeaders.Tables.Add(ds1.Tables[0].Copy()); string headersXML = dsHeaders.GetXml(); headersXML = headersXML.Replace("<NewDataSet>", "").Replace("</NewDataSet>", ""); // Console.WriteLine(headersXML.Trim()); DataSet dsCars = new DataSet("Cars"); dsCars.Tables.Add(ds1.Tables[3].Copy()); string carsXML = dsCars.GetXml(); // Console.WriteLine(carsXML); DataSet dsTrucks = new DataSet("Trucks"); dsTrucks.Tables.Add(ds2.Tables[3].Copy()); string trucksXML = dsTrucks.GetXml(); // Console.WriteLine(trucksXML); string resultXML = @"<document>" + headersXML + "<body>" + Environment.NewLine + carsXML + trucksXML + Environment.NewLine + "</body>" + Environment.NewLine + "</document>"; Console.WriteLine(resultXML); Your required XML <document> <header> <startDate>01/01/2020</startDate> <endDate> 01/02/ 2020</endDate> </header> <body> <Cars> <car> <ID>1</ID> <Name>Blue Car</Name> </car> <car> <ID>2</ID> <Name>Red Car</Name> </car> </Cars><Trucks> <truck> <ID> 1 </ID> <Name> Blue Truck </Name> </truck> <truck> <ID>2</ID> <Name>Red Truck</Name> </truck> </Trucks> </body> </document> 

Comments

0

Using xml linq :

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Xml.Linq; namespace ConsoleApplication2 { class Program { const string FILE1 = @"c:\TEMP\TEST.XML"; const string FILE2 = @"c:\TEMP\TEST1.XML"; static void Main(string[] args) { string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><document></document>"; XDocument doc3 = XDocument.Parse(xml); XElement doc = doc3.Root; doc.Add(new XElement("header", new XElement("Date", DateTime.Now.ToString("mm/dd/yyyy")))); XDocument doc1 = XDocument.Load(FILE1); XDocument doc2 = XDocument.Load(FILE2); XElement body = new XElement("body"); doc.Add(body); XElement cars = new XElement("cars"); body.Add(cars); List<XElement> cars1 = doc1.Descendants("car").ToList(); cars.Add(cars1); List<XElement> cars2 = doc2.Descendants("car").ToList(); cars.Add(cars2); XElement trucks = new XElement("trucks"); body.Add(trucks); List<XElement> trucks1 = doc1.Descendants("truck").ToList(); trucks.Add(trucks1); List<XElement> trucks2 = doc2.Descendants("truck").ToList(); trucks.Add(trucks2); } } } 

2 Comments

This also worked neatly, but the "body" only makes a self-closing tag.
I added card and trucks to doc instead of body. There are new lines : body.Add(cars); body.Add(trucks);

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.