Thursday, September 16, 2010

C# XmlWriter vs XmlDocument vs StreamWriter

Use XmlWriter for creating xml document.The below example uses the following classes
  • Contact class is used for storing name and address
  • AddressBook is the colleciton of Contact class
The c# code example in this article will generate xml document as below, but with 10000 contacts elements.
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
The example first creates and populates an AddressBook class with 10000 Contact objects and measures time taken to generate the xml file with 10000 contacts using using XmlDocument, XmlWriter and StreamWriter (usign StringBuilder).
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Diagnostics;
using System.Xml.Linq;
namespace XmlWrite
{
    class Contact
    {
        public string Name { get; set; }
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public int Zip { get; set; }
        public string Phone { get; set; }
        public Contact(string strName, string strAddress1, string strAddress2,
            int iZip,
            string strPhone)
        {
            Name = strName;
            Address1 = strAddress1;
            Address2 = strAddress2;
            Zip = iZip;
            Phone = strPhone;
        }
    }
    class AddressBook
    {
        private List<Contact> InnerList = null;
        public List<Contact> GetContacts()
        {
            return InnerList;
        }
        public AddressBook()
        {
            InnerList = new List<Contact>();
        }
        public void Add(Contact objContact)
        {
            InnerList.Add(objContact);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objSW = null;
            XmlDocument objXmlDoc = null;
            XmlWriter objXmlWriter = null;
            XDocument objXDoc = null;
            StringBuilder objSB = null;
            StreamWriter objStreamWriter = null;
            AddressBook objAddrBook = null;
            int iCount = 10000;
            List<Contact> objContacts = null;

            //populate contacts in the addressbook object model
            objAddrBook = new AddressBook();
            objSW = new Stopwatch();
            for (int i = 0; i < iCount; i++)
            {
                Contact objContact = null;
                string strName = "Person" + (i + 1);
                string strAddress1 = "Number" + (i + 101);
                string strAddress2 = "Address" + (i + 501);
                int iZip = 50000 + (i + 1);
                string strPhone = "99999" + (i + 1);
                objContact = new Contact(strName, strAddress1, strAddress2, iZip,
                    strPhone);
                objAddrBook.Add(objContact);
            }
            //xml creation using XmlDocument
            objSW.Reset();
            objSW.Start();
            objXmlDoc = new XmlDocument();
            XmlElement objXmlAddrBook = objXmlDoc.CreateElement("AddressBook");
            objContacts = objAddrBook.GetContacts();
            for (int i = 0; i < objContacts.Count; i++)
            {
                XmlElement objXmlContact = objXmlDoc.CreateElement("Contact");
                XmlElement objXmlName = objXmlDoc.CreateElement("Name");
                objXmlName.InnerText = objContacts[i].Name;
                objXmlContact.AppendChild(objXmlName);
                XmlElement objXmlAddress1 = objXmlDoc.CreateElement("Address1");
                objXmlAddress1.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Address1));
                objXmlContact.AppendChild(objXmlAddress1);
                XmlElement objXmlAddress2 = objXmlDoc.CreateElement("Address2");
                objXmlAddress2.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Address2));
                objXmlContact.AppendChild(objXmlAddress2);
                XmlElement objXmlZip = objXmlDoc.CreateElement("Zip");
                objXmlZip.InnerText = objContacts[i].Zip.ToString();
                objXmlContact.AppendChild(objXmlZip);
                XmlElement objXmlPhone = objXmlDoc.CreateElement("Phone");
                objXmlPhone.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Phone));
                objXmlContact.AppendChild(objXmlPhone);
                objXmlAddrBook.AppendChild(objXmlContact);
            }
            objXmlDoc.AppendChild(objXmlAddrBook);
            objXmlDoc.Save("address_dom.xml");
            objSW.Stop();
            Console.WriteLine("XML file created using XmlDocument");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml creation using XmlWriter
            objSW.Reset();
            objSW.Start();
            XmlWriterSettings objSettings = new XmlWriterSettings();
            objSettings.Indent = true;
            using (objXmlWriter = XmlWriter.Create("address_xw.xml", objSettings))
            {
                objXmlWriter.WriteStartElement("AddressBook");
                objContacts = objAddrBook.GetContacts();
                for (int i = 0; i < objContacts.Count; i++)
                {
                    objXmlWriter.WriteStartElement("Contact");

                    objXmlWriter.WriteStartElement("Name");
                    objXmlWriter.WriteString(objContacts[i].Name);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Address1");
                    objXmlWriter.WriteCData(objContacts[i].Address1);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Address2");
                    objXmlWriter.WriteCData(objContacts[i].Address2);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Zip");
                    objXmlWriter.WriteString(objContacts[i].Zip.ToString());
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Phone");
                    objXmlWriter.WriteCData(objContacts[i].Phone);
                    objXmlWriter.WriteEndElement();

                    objXmlWriter.WriteEndElement();
                }
                objXmlWriter.WriteEndElement();
            }
            objSW.Stop();
            Console.WriteLine("XML file created using XmlWriter");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            //xml creation using StringBuilder
            objSW.Reset();
            objSW.Start();
            objSB = new StringBuilder();
            objSB.AppendLine("<AddressBook>");
            objContacts = objAddrBook.GetContacts();

            for (int i = 0; i < objContacts.Count; i++)
            {
                objSB.AppendLine("<Contact>");
                objSB.AppendLine("<Name>" + objContacts[i].Name + "</Name>");
                objSB.AppendLine(
                "<Address1><![CDATA[" + objContacts[i].Address1 + "]]></Address1>");
                objSB.AppendLine(
                "<Address2><![CDATA[" + objContacts[i].Address2 + "]]></Address2>");
                objSB.AppendLine("<Zip>" + objContacts[i].Zip + "</Zip>");
                objSB.AppendLine(
                "<Phone><![CDATA[" + objContacts[i].Phone + "]]></Phone>");
                objSB.AppendLine("</Contact>");
            }
            objSB.AppendLine("</AddressBook>");
            using (objStreamWriter = new StreamWriter("address_sb.xml", false))
            {
                objStreamWriter.Write(objSB.ToString());
            }
            objSW.Stop();
            Console.WriteLine("XML file created using StringBuilder");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml creation using XDocument (LINQ)
            objSW.Reset();
            objSW.Start();
            objContacts = objAddrBook.GetContacts();
            XElement[] arrXElem = new XElement[objContacts.Count];
            for (int i = 0; i < objContacts.Count; i++)
            {
                arrXElem[i] = new XElement("Contact",
                    new XElement("Name", objContacts[i].Name),
                    new XElement("Address1",
                    new XCData(objContacts[i].Address1)),
                    new XElement("Address2",
                    new XCData(objContacts[i].Address2)),
                    new XElement("Zip", objContacts[i].Zip),
                    new XElement("Phone", new XCData(objContacts[i].Phone)));
            }
            objXDoc = new XDocument(new XElement("AddressBook",arrXElem));
            objXDoc.Save("address_xdocument.xml");
            objSW.Stop();
            Console.WriteLine("XML file created using XDocument");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            Console.ReadLine();

        }
    }
}
Output:
XML file created using XmlDocument
TimeElapsed (Stopwatch float):90.0323ms
TimeElapsed (Stopwatch rounded):90ms
XML file created using XmlWriter
TimeElapsed (Stopwatch float):36.2555ms
TimeElapsed (Stopwatch rounded):36ms
XML file created using StringBuilder
TimeElapsed (Stopwatch float):91.5911ms
TimeElapsed (Stopwatch rounded):91ms
XML file created using XDocument
TimeElapsed (Stopwatch float):71.3794ms
TimeElapsed (Stopwatch rounded):71ms

Note: The StringBuilder performance can be improved by specifying the required capacity when creating the StringBuilder object.

Note: XmlDocument can be considered, if forward and backward reference is unavoidable during the generation of xml document.

Rule: Use XmlWriter for generating or creating xml document.

No comments: