Home

Operations on XML Elements

 

Fundamental Operations

 

Introduction

So far, to create an XML element, we were directly typing in a file. When such a file had been created and saved, it was 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, the XmlDocument, the XmlNode, and the XmlElement classes provide all the necessary properties and methods you would need 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 the action to be applied. As it happens, you have on the root node, on a particular node inside the document, on the parent of a node, on a sibling of a node, etc. To get to a node, you will usually first get a reference to its XmlElement object. To do this, you can create a handle to an XmlElement and initialize it with that reference.

Appending an Element

To assist you 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 element named Title to a document. You would start with code as follows:

Void btnDocument_Click(System::Object^  sender, System::EventArgs^  e)
{
    String ^ Filename = L"videos.xml";
    XmlDocument ^ DOMDocument = gcnew XmlDocument;

    if( File::Exists(Filename) )
    {
        DOMDocument->Load(Filename);

        XmlElement ^ NewElement = DOMDocument->CreateElement(L"Title");
    }
}

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, 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:

Void btnDocument_Click(System::Object^  sender, System::EventArgs^  e)
{
    String ^ Filename = L"videos.xml";
    XmlDocument ^ DOMDocument = gcnew XmlDocument;

    if( File::Exists(Filename) )
    {
        DOMDocument->Load(Filename);

        XmlElement ^ RootElement = DOMDocument->DocumentElement;
        XmlElement ^ NewElement = DOMDocument->CreateElement(L"title");
        RootElement->AppendChild(NewElement);

        DOMDocument->Save(Filename);
    }
}

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 the Inner Text of an Element

Suppose you have the following videos.xml 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 Minutes</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 than one, 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.

In the previous lesson, we saw that the XmlNode::InnerXml property is made of a node, its markup, its children and their markup. This means that you can create the child node(s) with its(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 property String^ InnerXml
    {
	String^ get ();
	void set (String^ value);
    }

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

Void btnDocument_Click(System::Object^  sender, System::EventArgs^  e)
{
    String ^ Filename = L"videos.xml";
    XmlDocument ^ DOMDocument = gcnew XmlDocument;

    if( File::Exists(Filename) )
    {
        DOMDocument->Load(Filename);

        XmlElement ^ Element = DOMDocument->CreateElement(L"video");
        String ^ strNewvideo = L"<title>Other People's Money</title>"
                               L"<director>Alan Brunstein</director>"
			       L"<length>114 Minutes</length>"
			       L"<format>VHS</format>"
			       L"<rating>PG-13</rating>";

        Element->InnerXml = strNewvideo;
        DOMDocument->DocumentElement->AppendChild(Element);

        DOMDocument->Save(Filename);
    }
}

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>Other People's Money</title>
    <director>Alan Brunstein</director>
    <length>114 Minutes</length>
    <format>VHS</format>
    <rating>PG-13</rating>
  </video>
</videos>

Adding an Element With Value

Consider the following XML file named videos.xml:

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

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:

Void btnDocument_Click(System::Object^  sender, System::EventArgs^  e)
{
    String ^ Filename = L"videos.xml";
    XmlDocument ^ DOMDocument = gcnew XmlDocument;

    if( File::Exists(Filename) )
    {
        DOMDocument->Load(Filename);
        XmlElement ^ RootElement = DOMDocument->DocumentElement;

        XmlElement ^ Element = DOMDocument->CreateElement(L"title");
        XmlText ^ TextVideo = DOMDocument->CreateTextNode(L"Basic Instinct");
        RootElement->AppendChild(Element);
        RootElement->LastChild->AppendChild(TextVideo);

        DOMDocument->Save(Filename);
    }
}

This would produce:

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

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

Consider the following XML file named "videos.xml":

<?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:

Void btnDocument_Click(System::Object^  sender, System::EventArgs^  e)
{
    String ^ Filename = L"videos.xml";
    XmlDocument ^ DOMDocument = gcnew XmlDocument;

    if( File::Exists(Filename) )
    {
        DOMDocument->Load(Filename);

        XmlElement ^ RootElement = DOMDocument->DocumentElement;
        XmlElement ^ NewElement = DOMDocument->CreateElement(L"video");
        RootElement->AppendChild(NewElement);
    }
}

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

Void btnDocument_Click(System::Object^  sender, System::EventArgs^  e)
{
    String ^ Filename = L"videos.xml";
    XmlDocument ^ DOMDocument = gcnew XmlDocument;

    if( File::Exists(Filename) )
    {
        DOMDocument->Load(Filename);

        XmlElement ^ RootElement = DOMDocument->DocumentElement;
        XmlElement ^ NewElement = DOMDocument->CreateElement(L"video");
        RootElement->AppendChild(NewElement);

        RootElement = DOMDocument->DocumentElement;

        NewElement = DOMDocument->CreateElement(L"title");
        XmlText ^ Textvideo = DOMDocument->CreateTextNode(L"Her Alibi");

        RootElement->LastChild->AppendChild(NewElement);
        RootElement->LastChild->LastChild->AppendChild(Textvideo);

        DOMDocument->Save(Filename);
    }
}

This would produce:

<?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 Minutes</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:

Void btnDocument_Click(System::Object^  sender, System::EventArgs^  e)
{
    String ^ Filename = L"videos.xml";
    XmlDocument ^ DOMDocument = gcnew XmlDocument;

    if( File::Exists(Filename) )
    {
        DOMDocument->Load(Filename);

        XmlElement ^ RootElement = DOMDocument->DocumentElement;
        XmlElement ^ NewElement = DOMDocument->CreateElement(L"video");
        RootElement->AppendChild(NewElement);

        RootElement = DOMDocument->DocumentElement;

        NewElement = DOMDocument->CreateElement(L"title");
        XmlText ^ TextVideo = DOMDocument->CreateTextNode(L"The Day After Tomorrow");
        RootElement->LastChild->AppendChild(NewElement);
        RootElement->LastChild->LastChild->AppendChild(TextVideo);

        NewElement = DOMDocument->CreateElement(L"director");
        TextVideo = DOMDocument->CreateTextNode(L"Roland Emmerich");
        RootElement->LastChild->AppendChild(NewElement);
        RootElement->LastChild->LastChild->AppendChild(TextVideo);

        NewElement = DOMDocument->CreateElement(L"length");
        TextVideo = DOMDocument->CreateTextNode(L"124 Minutes");
        RootElement->LastChild->AppendChild(NewElement);
        RootElement->LastChild->LastChild->AppendChild(TextVideo);

        NewElement = DOMDocument->CreateElement(L"format");
        TextVideo = DOMDocument->CreateTextNode(L"DVD");
        RootElement->LastChild->AppendChild(NewElement);
        RootElement->LastChild->LastChild->AppendChild(TextVideo);

        NewElement = DOMDocument->CreateElement(L"rating");
        TextVideo = DOMDocument->CreateTextNode(L"PG-13");
        RootElement->LastChild->AppendChild(NewElement);
        RootElement->LastChild->LastChild->AppendChild(TextVideo);

        DOMDocument->Save(Filename);
    }
}

 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 Minutes</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.

 

Exercises

 

Solas Property Rental

  1. Open the Solas Property Rental database from this lesson
  2. Configure the Rental Allocations form so that, after the user has entered a property code and press Tab (or when the control looses focus), the database will first check the status of the property. If the property is occupied, a message box will be displayed to the user and that particular property cannot be selected (the property code text box should be set empty)
  3. Configure the Rent Payments so that the user can decide to see only the payments for one particular tenant (you can create a contextual menu so that if the user right-clicks a certain row and click View Tenant's Payments, the list view would display only that tenant's payments. Of course, make sure the user has a way to display all payments again)
 

Previous Copyright © 2008-2012 FunctionX Home