1

I'm trying to re-create an xml document. I'm reading an existing xml document and then trying to re-create it by using C#.

So far I was able to read and create shell of new doc.

I am looping through each child and adding it to the product node.

my xml file (source):

<?xml version="1.0" encoding="utf-8"?>
<DroneList>
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Phantom 3</modelName>
        <estimatedPrice>699</estimatedPrice>
        <flightTime>17 to 20</flightTime>
        <modelSize>Medium</modelSize>   
    </product>
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Inspire 1</modelName>
        <estimatedPrice>2899</estimatedPrice>
        <flightTime>18 to 20</flightTime>
        <modelSize>Large</modelSize>
    </product>
</DroneList>

Note: There are multiple products under the root with unique item.

My goal with the C# program is to be able to:

  • read the existing products from list
  • add them to the new xml document
  • add new items to the new xml document
  • save xml document as a new xml file

my C# code is below:

        private void btnChange_Click(object sender, EventArgs e)
        {
            txtDisplay.Clear();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(XML_FILE_PATH); // load xml data
            XmlDocument newDoc = new XmlDocument(); // create a new xmldocument object to hold new xml data

            txtDisplay.Text += "****Reading Drone List**** \r\n";

            // loaded existing xml data
            XmlElement root = xmlDoc.DocumentElement;
            XmlNodeList children = root.ChildNodes;

            txtDisplay.Text += "****Showing Existing Data**** \r\n children: " + children.Count + "\r\n";

            for (int i = 0; i < children.Count; i++)
            {
                XmlElement product = newDoc.CreateElement("product");
                product.SetAttribute("productId", i.ToString());

                foreach (XmlNode child in children)
                {

                    XmlElement manufacturer = newDoc.CreateElement("manufacturer");
                    XmlElement modelName = newDoc.CreateElement("modelName");
                    XmlElement estimatedPrice = newDoc.CreateElement("estimatedPrice");
                    XmlElement flightTime = newDoc.CreateElement("flightTime");
                    XmlElement modelSize = newDoc.CreateElement("modelSize");

                    manufacturer.InnerText = child["manufacturer"].InnerText;
                    modelName.InnerText = child["modelName"].InnerText;
                    estimatedPrice.InnerText = child["estimatedPrice"].InnerText;
                    flightTime.InnerText = child["flightTime"].InnerText;
                    modelSize.InnerText = child["modelSize"].InnerText;

                    product.AppendChild(manufacturer);
                    product.AppendChild(modelName);
                    product.AppendChild(estimatedPrice);
                    product.AppendChild(flightTime);
                    product.AppendChild(modelSize);
                }
            }



            txtDisplay.Text += "****Showing new doc so far**** \r\n";

            txtDisplay.Text += newDoc.InnerXml + "\r\n"; // display xml in the textbox

            //txtDisplay.Text += newRoot.InnerText + "\r\n";

            txtDisplay.Text += "****Adding New Data**** \r\n";

            

            for (int i = 5; i < 5; i++)
            {
                //
            }

            XmlElement newRoot = newDoc.CreateElement("DroneList"); // the root element is <roster>
            newDoc.AppendChild(newRoot);
            XmlDeclaration xmlDec = newDoc.CreateXmlDeclaration("1.0", null, null);
            newDoc.InsertBefore(xmlDec, newRoot); // insert before the root element

            newDoc.Save("..\\..\\..\\new_drones.xml");

        }

Desired XML outcome:

new xml file (target)

<?xml version="1.0" encoding="utf-8"?>
<DroneList>
    <!-- existing products from source file -->
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Phantom 3</modelName>
        <estimatedPrice>699</estimatedPrice>
        <flightTime>17 to 20</flightTime>
        <modelSize>Medium</modelSize>   
    </product>
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Inspire 1</modelName>
        <estimatedPrice>2899</estimatedPrice>
        <flightTime>18 to 20</flightTime>
        <modelSize>Large</modelSize>
    </product>
    <!-- new products added through C# program (Hard coded) -->
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Inspire 1</modelName>
        <estimatedPrice>2899</estimatedPrice>
        <flightTime>18 to 20</flightTime>
        <modelSize>Large</modelSize>
    </product>
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Inspire 1</modelName>
        <estimatedPrice>2899</estimatedPrice>
        <flightTime>18 to 20</flightTime>
        <modelSize>Large</modelSize>
    </product>
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Inspire 1</modelName>
        <estimatedPrice>2899</estimatedPrice>
        <flightTime>18 to 20</flightTime>
        <modelSize>Large</modelSize>
    </product>
</DroneList>
4
  • 1
    Please add to your question a desired output XML. Overall, it sounds like a task for XSLT. Commented Oct 29, 2021 at 1:07
  • 2
    if it was me I would (1) de-serialize to c# object, (2) write code to add to object's list, (3) de-serialize back to xml. Commented Oct 29, 2021 at 1:11
  • @YitzhakKhabinsky I've updated the question with desired outcome. Commented Oct 29, 2021 at 2:44
  • This kind of thing is so much easier with XSLT, which was purpose-designed for the job. Commented Oct 29, 2021 at 8:26

1 Answer 1

1

Overall, XSLT is made by design to transform input XML into output XML, or other textual formats.

Please try the following XSLT based solution.

The XSLT takes the last product element and multiplies it 4 times. The rest of the input XML stays the same.

The c# code below is a generic boilerplate code for XSLT transformations.

Input XML

<?xml version="1.0"?>
<DroneList>
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Phantom 3</modelName>
        <estimatedPrice>699</estimatedPrice>
        <flightTime>17 to 20</flightTime>
        <modelSize>Medium</modelSize>
    </product>
    <product>
        <manufacturer>DJI</manufacturer>
        <modelName>Inspire 1</modelName>
        <estimatedPrice>2899</estimatedPrice>
        <flightTime>18 to 20</flightTime>
        <modelSize>Large</modelSize>
    </product>
</DroneList>

XSLT 1.0

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="product[last()]">
        <xsl:variable name="product">
            <xsl:copy-of select="."/>
        </xsl:variable>

        <xsl:for-each select="(//node())[4 &gt;= position()]">
            <xsl:copy-of select="$product"/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Output XML

<?xml version="1.0" encoding="utf-8"?>
<DroneList>
  <product>
    <manufacturer>DJI</manufacturer>
    <modelName>Phantom 3</modelName>
    <estimatedPrice>699</estimatedPrice>
    <flightTime>17 to 20</flightTime>
    <modelSize>Medium</modelSize>
  </product>
  <product>
    <manufacturer>DJI</manufacturer>
    <modelName>Inspire 1</modelName>
    <estimatedPrice>2899</estimatedPrice>
    <flightTime>18 to 20</flightTime>
    <modelSize>Large</modelSize>
  </product>
  <product>
    <manufacturer>DJI</manufacturer>
    <modelName>Inspire 1</modelName>
    <estimatedPrice>2899</estimatedPrice>
    <flightTime>18 to 20</flightTime>
    <modelSize>Large</modelSize>
  </product>
  <product>
    <manufacturer>DJI</manufacturer>
    <modelName>Inspire 1</modelName>
    <estimatedPrice>2899</estimatedPrice>
    <flightTime>18 to 20</flightTime>
    <modelSize>Large</modelSize>
  </product>
  <product>
    <manufacturer>DJI</manufacturer>
    <modelName>Inspire 1</modelName>
    <estimatedPrice>2899</estimatedPrice>
    <flightTime>18 to 20</flightTime>
    <modelSize>Large</modelSize>
  </product>
</DroneList>

c#

oid Main()
{
   const string SOURCEXMLFILE = @"e:\Temp\input.xml";
   const string XSLTFILE = @"e:\Temp\process.xslt";
   const string OUTPUTXMLFILE = @"e:\temp\output.xml";

   try
   {
      XsltArgumentList xslArg = new XsltArgumentList();

      using (XmlReader src = XmlReader.Create(SOURCEXMLFILE))
      {
         XslCompiledTransform xslt = new XslCompiledTransform();
         xslt.Load(XSLTFILE, new XsltSettings(true, true), new XmlUrlResolver());

         XmlWriterSettings settings = xslt.OutputSettings.Clone();
         settings.IndentChars = "\t";
         // to remove BOM
         settings.Encoding = new UTF8Encoding(false);

         using (XmlWriter result = XmlWriter.Create(OUTPUTXMLFILE, settings))
         {
            xslt.Transform(src, xslArg, result, new XmlUrlResolver());
            result.Close();
         }
      }
      Console.WriteLine("File '{0}' has been generated.", OUTPUTXMLFILE);
   }
   catch (Exception ex)
   {
      Console.WriteLine(ex.Message);
   }
}
Sign up to request clarification or add additional context in comments.

2 Comments

@Yizhak I need to only do this with C#. I cannot use XSLT or any other approach other than XML DOM and systematically breaking it down using elements and nodes.
XSLT is a part of the .Net Framework. So what's the problem?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.