How do you create XML document from reading another XML file using C#?

1.3k Views Asked by At

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>
1

There are 1 best solutions below

2
Yitzhak Khabinsky On

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);
   }
}