Home

Operations on XML Elements

 

Introduction

So far, to create an XML element, we were directly typing in a file. When such a file has been created and saved, it is ready to be processed. Here is an example of a file named Videos.xml:

<?xml version="1.0" encoding="utf-8" ?>
<Videos>
	<Title>The Distinguished Gentleman</Title>
</Videos>

In some applications, you will want the user to provide you with the necessary value(s) to create an element. Fortunately, XmlDocument, the XmlNode, and the XmlElement classes provide all the necessary properties and methods to perform the routine operations of an XML file, an element, or a node. The operations include locating a node, adding a new element, or deleting a node.

Before performing an operation, you will usually need to decide in what section of the file you want to action to bee applied. As it happens, you have the root node, a particular node inside the file, parent of a node, the sibling of a node, etc. To get to a node, you will usually first get a reference to its XmlElement. To do this, you can declare an XmlElement variable and initialize it with that reference.

Practical Learning Practical Learning: Introducing operations on XML Elements

  1. Start Microsoft Visual C# and create a Console Application named CollegeParkAutoParts3
  2. On the main menu, click Project -> Add New Item...
  3. In the Templates list, click XML File
  4. Set the Name to makes and click Add
  5. Change the file as follows:
     
    <?xml version="1.0" encoding="utf-8"?>
    <Makes>
      <Make>Acura</Make>
      <Make>Audi</Make>
      <Make>BMW</Make>
      <Make>Chevrolet</Make>
    </Makes>
  6. On the main menu, click File -> Save makes.xml As...
  7. Access the main folder of the current project and, inside of it, open a sub-folder of the same name (it should be opened already). In the sub-folder of the same name, open the bin sub-folder followed by the Release sub-folder. Click Save
  8. In the Solution Explorer, right-click CollegeParkAutoParts2 -> Add -> New Item...
  9. In the Templates list, make sure XML File is selected.
    Set the Name to models and click Add
  10. To save the file, on the main menu, click File -> Save models.xml As...
  11. Access the main folder of the current project and, inside of it, open a sub-folder of the same name (it should be selected already). In the sub-folder of the same name, open the bin sub-folder followed by the Release sub-folder. Click Save
  12. Change the file as follows:
     
    <?xml version="1.0" encoding="utf-8" ?>
    <Models>
    	<Model>NSX</Model>
    	<Model>TL</Model>
    	<Model>Spider</Model>
    	<Model>A4</Model>
    	<Model>RS6</Model>
    	<Model>323I</Model>
    	<Model>M5</Model>
    	<Model>Astro</Model>
    	<Model>Cavalier</Model>
    	<Model>Prot&#233;g&#233;</Model>
    </Models>

Adding an Empty Element

To assist with programmatically creating a new element, the XmlDocument class provides the CreateElement() method that is overloaded with three versions. One of the versions uses the following syntax:

public XmlElement CreateElement(string name);

Using this method, to create a new element, call it and pass it the name of the element. For example, imagine you want to add a new Title element to the above file. You would start with code as follows:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
    class Program
    {
        static int Main(string[] args)
        {
            string strFilename = "Videos.xml";
            XmlDocument xmlDoc = new XmlDocument();

            if (File.Exists(strFilename))
            {
                xmlDoc.Load(strFilename);

                XmlElement elmNew = xmlDoc.CreateElement("Title");
            }

            Console.WriteLine();
            return 0;
        }
    }
}

In order to add the new element to the file, you must specify its position in the tree: whether it would be the first or the last node, whether you want to position it before or after a node of your choice. For example, if you want to add a new Title element to the above file, it would be considered a child of the root, that is, a child of the XmlDocument.DocumentElement property. In the previous lesson, we learned how to get a reference to the root node.

To support the positions of existing nodes, the XmlNode class, which is the ancestor of all XML nodes of the .NET Framework, provides various appropriate methods. One of these methods is AppendChild(), which is used to add an element as the last child of its parent. The syntax of the XmlNode.AppendChild() method is:

public virtual XmlNode AppendChild(XmlNode newChild);

When calling this method, pass the XmlNode object you had previous created. After adding the node, if you want the file to keep it, you should save it. Here is an example:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
    class Program
    {
        static int Main(string[] args)
        {
            string strFilename = "Videos.xml";
            XmlDocument xmlDoc = new XmlDocument();

            if (File.Exists(strFilename))
            {
                xmlDoc.Load(strFilename);

                XmlElement elmRoot = xmlDoc.DocumentElement;
                XmlElement elmNew = xmlDoc.CreateElement("Title");
                elmRoot.AppendChild(elmNew);
                xmlDoc.Save(strFilename);
            }

            Console.WriteLine();
            return 0;
        }
    }
}

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Title>The Distinguished Gentleman</Title>
  <Title />
</Videos>

Notice that the newly added element is empty.

Adding an Element With Value

If you want the element to have a value, the XmlDocument class provides the CreateTextNode() method. This method returns an XmlText value. The syntax of this method is:

public virtual XmlText CreateTextNode(string text);

This method takes as argument the string that would constitute the value of the element. Before calling it, you should have used the XmlNode.AppendChild() method to create a node. Calling this method on the LastChild node of the one that called the AppendChild() would specify the value of the new node. Here is an example:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
    class Program
    {
        static int Main(string[] args)
        {
            string strFilename = "Videos.xml";
            XmlDocument xmlDoc = new XmlDocument();

            if (File.Exists(strFilename))
            {
                xmlDoc.Load(strFilename);

                XmlElement elmRoot = xmlDoc.DocumentElement;
                XmlElement elmNew = xmlDoc.CreateElement("Title");
                XmlText txtVideo = xmlDoc.CreateTextNode("Basic Instinct");
                elmRoot.AppendChild(elmNew);
                elmRoot.LastChild.AppendChild(txtVideo);

                xmlDoc.Save(strFilename);
            }

            Console.WriteLine();
            return 0;
        }
    }
}

This would produce:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Title>The Distinguished Gentleman</Title>
  <Title />
  <Title>Basic Instinct</Title>
</Videos>

The combination of calls to XmlDocument.CreateElement() and XmlDocument.CreateTextNode() allow you to create a new element that has a value.

Consider the following file:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Video>
    <Title>The Distinguished Gentleman</Title>
  </Video>
  <Video>
    <Title>Basic Instinct</Title>
  </Video>
</Videos>

Notice that the root, Videos, has a repetitive child named Video. This Video child has its own child named Title. Imagine that you want to add a new Video node that has a child. To do this, first create an empty Video node as a child of the root. We learned earlier how to do that:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
    class Program
    {
        static int Main(string[] args)
        {
            string strFilename = "Videos.xml";
            XmlDocument xmlDoc = new XmlDocument();

            if (File.Exists(strFilename))
            {
                xmlDoc.Load(strFilename);

                XmlElement elmRoot = xmlDoc.DocumentElement;
                XmlElement elmNew = xmlDoc.CreateElement("Video");
                elmRoot.AppendChild(elmNew);
            }

            Console.WriteLine();
            return 0;
        }
    }
}

After creating the new child of the root, initialize the grand child with the desired name (the name doesn't have to be one of the existing names) and a value (which is optional if you don't want the new node to have a value). Once the new node is ready, append it as the last child of the root. If this new node has a value, append its XmlText object as the LastChild of the LastChild of the root. Here is an example of how you would do this:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
    class Program
    {
        static int Main(string[] args)
        {
            string strFilename = "Videos.xml";
            XmlDocument xmlDoc = new XmlDocument();

            if (File.Exists(strFilename))
            {
                xmlDoc.Load(strFilename);

                XmlElement elmRoot = xmlDoc.DocumentElement;
                XmlElement elmNew = xmlDoc.CreateElement("Video");
                elmRoot.AppendChild(elmNew);

                elmRoot = xmlDoc.DocumentElement;

                elmNew = xmlDoc.CreateElement("Title");
                XmlText txtVideo = xmlDoc.CreateTextNode("Her Alibi");
               
                elmRoot.LastChild.AppendChild(elmNew);
                elmRoot.LastChild.LastChild.AppendChild(txtVideo);
                
                xmlDoc.Save(strFilename);
            }

            Console.WriteLine();
            return 0;
        }
    }
}

With this code you would go from this:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Video>
    <Title>The Distinguished Gentleman</Title>
  </Video>
  <Video>
    <Title>Basic Instinct</Title>
  </Video>
</Videos>

To this:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Video>
    <Title>The Distinguished Gentleman</Title>
  </Video>
  <Video>
    <Title>Basic Instinct</Title>
  </Video>
  <Video>
    <Title>Her Alibi</Title>
  </Video>
</Videos>

Now consider the following file:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Video>
    <Title>The Distinguished Gentleman</Title>
    <Director>Jonathan Lynn</Director>
    <Length>112 Minutes</Length>
    <Format>DVD</Format>
    <Rating>R</Rating>
  </Video>
  <Video>
    <Title>Her Alibi</Title>
    <Director>Bruce Beresford</Director>
    <Length>94 Mins</Length>
    <Format>DVD</Format>
    <Rating>PG-13</Rating>
  </Video>
</Videos>

The root, Videos, has a child named Video. The Video node has many child nodes. By now, we know how to add a child to the root. We also saw how to add a grand child with value to the root. To had many (grand) children to a node, first build the node, add it to the root, then continuously add the necessary nodes, one at a time, including its name and its optional value. This would be done as follows:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
    class Program
    {
        static int Main(string[] args)
        {
            string strFilename = "Videos.xml";
            XmlDocument xmlDoc = new XmlDocument();

            if (File.Exists(strFilename))
            {
                xmlDoc.Load(strFilename);

                XmlElement elmRoot = xmlDoc.DocumentElement;
                XmlElement elmNew = xmlDoc.CreateElement("Video");
                elmRoot.AppendChild(elmNew);

                elmRoot = xmlDoc.DocumentElement;

                elmNew = xmlDoc.CreateElement("Title");
              XmlText txtVideo = xmlDoc.CreateTextNode("The Day After Tomorrow");
                elmRoot.LastChild.AppendChild(elmNew);
                elmRoot.LastChild.LastChild.AppendChild(txtVideo);

                elmNew = xmlDoc.CreateElement("Director");
                txtVideo = xmlDoc.CreateTextNode("Roland Emmerich");
                elmRoot.LastChild.AppendChild(elmNew);
                elmRoot.LastChild.LastChild.AppendChild(txtVideo);
                
                elmNew = xmlDoc.CreateElement("Length");
                txtVideo = xmlDoc.CreateTextNode("124 Minutes");
                elmRoot.LastChild.AppendChild(elmNew);
                elmRoot.LastChild.LastChild.AppendChild(txtVideo);
                
                elmNew = xmlDoc.CreateElement("Format");
                txtVideo = xmlDoc.CreateTextNode("DVD");
                elmRoot.LastChild.AppendChild(elmNew);
                elmRoot.LastChild.LastChild.AppendChild(txtVideo);
                
                elmNew = xmlDoc.CreateElement("Rating");
                txtVideo = xmlDoc.CreateTextNode("PG-13");
                elmRoot.LastChild.AppendChild(elmNew);
                elmRoot.LastChild.LastChild.AppendChild(txtVideo);

                xmlDoc.Save(strFilename);
            }

            Console.WriteLine();
            return 0;
        }
    }
}

 This would produce:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Video>
    <Title>The Distinguished Gentleman</Title>
    <Director>Jonathan Lynn</Director>
    <Length>112 Minutes</Length>
    <Format>DVD</Format>
    <Rating>R</Rating>
  </Video>
  <Video>
    <Title>Her Alibi</Title>
    <Director>Bruce Beresford</Director>
    <Length>94 Mins</Length>
    <Format>DVD</Format>
    <Rating>PG-13</Rating>
  </Video>
  <Video>
    <Title>The Day After Tomorrow</Title>
    <Director>Roland Emmerich</Director>
    <Length>124 Minutes</Length>
    <Format>DVD</Format>
    <Rating>PG-13</Rating>
  </Video>
</Videos>

Using the same approach, you can add children to children of children, and so on.

Practical Learning Practical Learning: Programmatically Adding an Element

  1. To give the user the ability to create a new car make, change the Program.cs file as follows:
     
    using System;
    using System.Xml;
    
    namespace CollegeParkAutoParts3
    {
        public static class Program
        {
            public static void CreateNewMake()
            {
                string strNewMake = "";
    
                Console.Write("Enter Car Make: ");
                strNewMake = Console.ReadLine();
    
                // Open the Makes.xml file
                XmlDocument docXMLFile = new XmlDocument();
                docXMLFile.Load("Makes.xml");
    
                // Get the root node so we can explore its children
                XmlElement nodRoot = docXMLFile.DocumentElement;
                // Store all the values of the elements in a string
                string allMyChildren = nodRoot.InnerText;
                // Locate the new make among the values of the elements
                int indexLookForNewMake =
                    allMyChildren.IndexOf(strNewMake);
    
                // If the car make exists already, don't add it
                if (indexLookForNewMake >= 0)
                    return;
                else
                {
                    // If the car is not in the list
                    // already, add it as a Make element
                    XmlElement elmXML =
                        docXMLFile.CreateElement("Make");
                    // Create its value using the 
                    // string provided by the user
                    XmlText txtXML = 
                        docXMLFile.CreateTextNode(strNewMake);
                    // Add the new element at the end of the file
                    docXMLFile.DocumentElement.AppendChild(elmXML);
                    // Specify its text
                    docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);
    
                    // Save the file
                    docXMLFile.Save("Makes.xml");
                }
            }
           
            static int Main(string[] args)
            {
                return 0;
            }
        }
    }
  2. To give the user the ability to add a new car model, create the following function in the file:
     
    using System;
    using System.Xml;
    
    namespace CollegeParkAutoParts2
    {
        public static class Program
        {
            public static void CreateNewMake()
            {
                . . . No Change
            }
    
            public static void CreateNewModel()
            {
                string strNewModel = "";
    
                Console.Write("Enter Car Model: ");
                strNewModel = Console.ReadLine();
    
                XmlDocument docXMLFile = new XmlDocument();
                docXMLFile.Load("models.xml");
    
                XmlElement nodRoot = docXMLFile.DocumentElement;
                string allMyChildren = nodRoot.InnerText;
                int indexNewModel =
                    allMyChildren.IndexOf(strNewModel);
    
                if (indexNewModel >= 0)
                    return;
                else
                {
                    XmlElement elmXML =
                        docXMLFile.CreateElement("Model");
                    XmlText txtXML =
                        docXMLFile.CreateTextNode(strNewModel);
    
                    docXMLFile.DocumentElement.AppendChild(elmXML);
                    docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);
    
                    docXMLFile.Save("models.xml");
                }
            }
    
            static int Main(string[] args)
            {
                return 0;
            }
        }
    }
  3. To guide the user with a menu, change the file as follows:
     
    using System;
    using System.Xml;
    
    namespace CollegeParkAutoParts2
    {
        public static class Program
        {
            public static void CreateNewMake()
            {
                . . . No Change
            }
    
            public static void CreateNewModel()
            {
                . . . No Change
            }
    
            static int Main(string[] args)
            {
                char mnuChoice = 'q';
    
                Console.WriteLine("=o=o=o=o=o=o=o=o=o=o=o=o=o=o=o=");
                Console.WriteLine("=-= College Park Auto-Parts =-=");
                Console.WriteLine("=o=o=o=o=o=o=o=o=o=o=o=o=o=o=o=");
    
                do
                {
                    try
                    {
                        Console.WriteLine("=-= Main Menu =-=");
                        Console.WriteLine("1 - Add New Car Make");
                        Console.WriteLine("2 - Add New Car Model");
                        Console.WriteLine("0 - Exit");
                        Console.Write("Your Choice: ");
                        mnuChoice = char.Parse(Console.ReadLine());
                    }
                    catch (FormatException)
                    {
                        Console.WriteLine("Invalid Choice");
                        Console.WriteLine("Please try again");
                    }
    
                    switch (mnuChoice)
                    {
                        case '1':
                            CreateNewMake();
                            break;
                        case '2':
                            CreateNewModel();
                            break;
                        default:
                            break;
                    }
    
                    Console.WriteLine();
                } while((mnuChoice == '1') ||
                        (mnuChoice == '2'));
    
                Console.WriteLine("\nThank you!");
                return 0;
            }
        }
    }
  4. Execute the application and create the following elements:
     
    Makes
    Dodge
    Ford
    Honda
    Toyota
    Models
    A4 Quattro
    Corolla
    Dakota
    Focus
    Escort
    Camry
    Crown Victoria
    Expedition
    Integra
    Neon
  5. Close the DOS window

Adding a Filled Child Element

The above Videos.xml file had only one level under the root and no child element of the root had children. Suppose you have the following version of the file:

<?xml version="1.0" encoding="utf-8"?>
<Videos>
  <Video>
    <Title>The Distinguished Gentleman</Title>
    <Director>Jonathan Lynn</Director>
    <Length>112 Minutes</Length>
    <Format>DVD</Format>
    <Rating>R</Rating>
  </Video>
  <Video>
    <Title>Her Alibi</Title>
    <Director>Bruce Beresford</Director>
    <Length>94 Mins</Length>
    <Format>DVD</Format>
    <Rating>PG-13</Rating>
  </Video>
</Videos>

Imagine that you want to add a Video element. You have a choice of adding one, more, or all child elements of the Video node. To perform this operation, one solution you can use is to "build" all child elements of the Video element, then add the node as a whole. To support this technique, we saw earlier that the XmlNode.InnerXml property comprises a node, its markup, its children and their markup. This means that you can create the child nodes with their markup(s) as a string and assign that string to an XmlNode.InnerXml string. To do this, you would need the set version of the InnerXml property. It is declared as follows:

public virtual string InnerXml{get; set;}

Here is an example that adds a complete new Video node to the above XML file:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
    class Program
    {
        static int Main(string[] args)
        {
            string strFilename = "Videos.xml";
            XmlDocument xmlDoc = new XmlDocument();

            if (File.Exists(strFilename))
            {
                xmlDoc.Load(strFilename);

                XmlElement elmXML = xmlDoc.CreateElement("Video");
                string strNewVideo = "<Title>Other People's Money</Title>" +
                                     "<Director>Alan Brunstein</Director>" +
                                     "<Length>114 Minutes</Length>" +
                             	     "<Format>VHS</Format>" +
                             	     "<Rating>PG-13</Rating>";

                elmXML.InnerXml = strNewVideo;
                xmlDoc.DocumentElement.AppendChild(elmXML);

                xmlDoc.Save("Videos.xml");
            }

            Console.WriteLine();
            return 0;
        }
    }
}
 

Previous Copyright © 2006 FunctionX, Inc. Next