Home

The Attributes of an XML Element

 

Introduction

So far, we have used only one attribute per element. Fortunately, you can create as many attributes as you judge necessary in an element. To do this, type the name of each attribute, assign it a double-quoted element and separate the attribute from the next with an empty space. Here is an example of an element with different attributes:

<Video ISBN="0-7888-1623-3" ScreenRatio="Standard" SoundtrackAvailable="True" />

As mentioned already and as you must always remember, attributes belong to an element. To support them, the attributes of an element are stored in the XmlElement::Attributes property and held by a class called XmlAttributeCollection. The XmlAttributeCollection class is based on the XmlNamedNodeMap class. This class lays a foundation to access attributes using their names or index in the collection. To know the number of attributes in an element, you can use the XmlNamedNodeMap::Count property.

 

Practical Learning Practical Learning: Adding Attributes

  1. To manually create some attributes, change the Countries.xml file as follows:
     
    <?xml version="1.0" encoding="utf-8" ?>
    <World Area="510,072,000,000" Population="6,379,157,361">
        <Continent Name="Africa" Area="30,065,000" Population="807,419,000">
            <Country CountryName="Burundi" Area="27,830" Population="6,231,221" Capital="Bujumbura" Code="bi" />
        </Continent>
        <Continent Name="Europe" Area="9,938,000" Population="730,916,000">
            <Country CountryName="Italy" Area="301,230" Population="58,057,477" Capital="Rome" Code="it" />
        </Continent>
    </World>
  2. Change the design of the New Country form as follows:
      
    Country
    Country Name Text Other Properties
    Label   Continent:  
    ComboBox cboContinents   DropDownStyle: DropDownList
    Button btnNewContinent New Continent  
    TextBox txtNewCountry    
    Label   Area (sq km):  
    TextBox txtArea   TextAlign: Right
    Label   Capital:  
    TextBox txtCapital    
    Label   Population:  
    TextBox txtPopulation   TextAlign: Right
    Label   Internet Code:  
    TextBox txtInternetCode   TextAlign: Right
    Button btnAddCountry Add Country  
    Button btnClose Close  
    Form     AcceptButton: btnAddCountry
    MaximizeBox: False
    StartPosition: CenterScreen
  3. Change the design of the New Continent dialog box as follows:
      
    Continent
    Control Name Text Other Properties
    Label   Continent Name:  
    TextBox txtContinentName   Modifiers: Public
    Label   Area:  
    TextBox txtArea   Modifiers: Public
    TextAlign: Right
    Label   Population:  
    TextBox txtPopulation   Modifiers: Public
    TextAlign: Right
  4. Save all

Access to an Attribute

To access an attribute by its position in the collection, you can use the XmlNamedNodeMap::Item() method.

The XmlAttributeCollection class is equipped with an ItemOf indexed property. This property is overloaded in three versions. The first version has the following syntax:

public: __property virtual XmlAttribute* get_ItemOf(int i);

This property allows you to access an attribute by considering that the attributes are stored in an array. The first or most left attribute has an index of 0; the second attribute from left (of course without counting the name of the element) has an index of 1, and so on.

It can be difficult and sometimes unpredictable in some scenarios if you try accessing an attribute by their indices because you must know exactly where each attribute is positioned. Consider the following version of our Videos.xml XML file:

<?xml version="1.0" encoding="utf-8" ?>
<Videos FileDesc="Personal Video Collection">
    <Video ISBN="0-7888-1623-3" ScreenRatio="Standard" SoundtrackAvailable="True">
        <Title StoryBy="Marty Kaplan and Jonathan Reynolds" Screenplay="Marty Kaplan">The Distinguished Gentleman</Title>
        <Director>Jonathan Lynn</Director>
        <Actors></Actors>
        <Length>112 Minutes</Length>
        <Format>DVD</Format>
        <Rating>R</Rating>
    </Video>
    <Video ISBN="0-7907-3900-3">
        <Title Screenplay="Charlie Peters">Her Alibi</Title>
        <Director>Bruce Beresford</Director>
        <Length>94 Mins</Length>
        <Format>DVD</Format>
        <Rating>PG-13</Rating>
    </Video>
</Videos>

In the first video, the name of the screenplay writer is stored at index 1. In the second video, the name of the screenplay writer is stored at index 0. In this case, it may not be a good item to use the index to locate an attribute. Fortunately, the second version of the overloaded XmlAttributeCollection::ItemOf[] property has the following syntax:

public: __property virtual XmlAttribute* get_ItemOf(String* name);

With this version, you can explicitly specify the name of the attribute that you want.

Practical Learning Practical Learning: Accessing an Attribute

  1. Display the New Country form.
    Double-click an unoccupied area of the form to generate its Load event and implement it as follows:
     
    System::Void NewCountry_Load(System::Object *  sender, System::EventArgs *  e)
    {
    	 // Open the XML file
    	 XmlDocument *xmlDocContinents = new XmlDocument;
    	 xmlDocContinents->Load(S"Countries.xml");
    
    	 // Get a list of elements whose names are Continent
    	 XmlNodeList *lstContinents = xmlDocContinents->GetElementsByTagName(S"Continent");
    
    	 // Retrieve the name of each continent and put it in the combo box
    	 for(int i = 0; i < lstContinents->Count; i++)
    		 this->cboContinents->Items->Add(lstContinents->ItemOf[i]->Attributes->ItemOf[S"Name"]->InnerText);
    }
  2. Execute the application and display the New Country dialog box to make sure its combo box is filled with available continent names
  3. Close the forms and return to your programming environment

Attribute Addition

Whether using its index or name, after accessing an attribute, you can manipulate it as you see fit. For example, you can change it or delete using the same techniques we saw to perform on an individual attribute.

As mentioned already, the attributes are stored as a list. Because you have complete access to this list and the positions of its attributes, when creating or adding a new attribute, you can specify the position the new attribute should have in the collection. To create an attribute as the first in an element, you can call the XmlAttributeCollection::Prepend() method. Its syntax is:

public: virtual XmlAttribute* Prepend(XmlAttribute* node);

Another technique you can use consists of locating an attribute first. Once you have one, to create a new attribute before it, you can call the XmlAttributeCollection::InsertBefore() method. Its syntax is:

public: virtual XmlAttribute* InsertBefore(XmlAttribute* newNode, XmlAttribute* refNode);

To add a new attribute after the current one, you can call the XmlAttributeCollection::InsertAfter() method. Its syntax is:

public: virtual XmlAttribute* InsertAfter(XmlAttribute* newNode, XmlAttribute* refNode);

To add an attribute at the end of the list of attributes of an element, you can call the XmlAttributeCollection::Append() method. Its syntax is:

public: virtual XmlAttribute* Append(XmlAttribute* node);

 

Practical Learning Practical Learning: Creating Attributes

  1. Change the Click event of the btnNewContinent button as follows:
     
    System::Void btnNewContinent_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 NewContinent *frmContinent = new NewContinent;
    
    	 // Open the XML file
    	 XmlDocument *xmlDocContinents = new XmlDocument;
    	 xmlDocContinents->Load(S"Countries.xml");
    
    	 // Display the New Continent dialog box and find out if the user clicked OK
    	 if( frmContinent->ShowDialog() == DialogResult::OK )
    	 {
    		 // Create a Continent element that the new attribute will be added to
    		 XmlElement *xmlNewContinent = xmlDocContinents->CreateElement(S"Continent");
    
    		 // Create the Name using the Continent Name string from  the dialog box
    		 xmlNewContinent->SetAttribute(S"Name", frmContinent->txtContinentName->Text);
    		 // Create the Area attribute
    		 xmlNewContinent->SetAttribute(S"Area", frmContinent->txtArea->Text);
    		 // Create the Population attribute
    		 xmlNewContinent->SetAttribute(S"Population", frmContinent->txtPopulation->Text);
    
    		 // Add the element and its attribute to the document
    		 xmlDocContinents->DocumentElement->AppendChild(xmlNewContinent);
    
    		 // Save the XML file
    		 xmlDocContinents->Save(S"Countries.xml");
    	 }
    }
  2. Display the New Country form.
    Double-click the Add Country button and implement its Click event as follows:
     
    System::Void btnAddCountry_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 // If the user didn't select a continent, don't do anything
    	 if( this->cboContinent->SelectedIndex == -1 )
    		 return;
    
    	 // Open the XML file
    	 XmlDocument *xmlDocContinents = new XmlDocument;
    	 xmlDocContinents->Load(S"Countries.xml");
    	 
    	 // The continent selected by the user
    	 String *strContinent = this->cboContinent->Text;
    	 // Get a list of elements whose names are Continent
    	 XmlNodeList *lstContinents = xmlDocContinents->GetElementsByTagName(S"Continent");
    
    	 // Visit each Continent element
    	 for(int i = 0; i < lstContinents->Count; i++)
    	 {
    		 // Get a list of the attributes of the current element
    		 XmlAttributeCollection *curAttributes = lstContinents->ItemOf[i]->Attributes;
    
    		 // Check each attribute, looking for the continent that the user selected
    		 for(int j = 0; j < curAttributes->Count; j++)
    		 {
    			 // Check if the current continent is the same that the user selected
    			 if( curAttributes->ItemOf[S"Name"]->InnerText->Equals(strContinent) )
    			 {
    				 // Once you find one, get its XmlElement reference
    				 XmlElement *elmNewCountry = xmlDocContinents->CreateElement(S"Country");
    
    				 // Create each attribute only if the user specified it
    
    				 // Create the Name using the New Country specified by the user
    				 if( !this->txtNewCountry->Text->Equals(S"") )
    					 elmNewCountry->SetAttribute(S"CountryName", this->txtNewCountry->Text);
    
    				 // Create the Area attribute
    				 if( !this->txtArea->Text->Equals(S"") )
    					 elmNewCountry->SetAttribute(S"Area", this->txtArea->Text);
    
    				 // Create the Population attribute
    				 if( !this->txtPopulation->Text->Equals(S"") )
    					 elmNewCountry->SetAttribute(S"Population", this->txtPopulation->Text);
    
    				 // Create the Capital attribute
    				 if( !this->txtCapital->Text->Equals(S"") )
    					 elmNewCountry->SetAttribute(S"Capital", this->txtCapital->Text);
    
    				 // Create the Code attribute
    				 if( !this->txtInternetCode->Text->Equals(S"") )
    					 elmNewCountry->SetAttribute(S"Code", this->txtInternetCode->Text);
    
    				 // Add the element (and its attribute) as a child of the current Continent
    				 lstContinents->ItemOf[i]->AppendChild(elmNewCountry);
    				 
    				 // Save the XML file
    				 xmlDocContinents->Save(S"Countries.xml");
    
    				 break;
    			 }
    		 }
    	 }
    
    	 this->txtNewCountry->Text = S"";
    	 this->txtArea->Text = S"";
    	 this->txtPopulation->Text = S"";
    	 this->txtCapital->Text = S"";
    	 this->txtInternetCode->Text = S"";
    	 this->txtNewCountry->Focus();
    }
  3. Double-click the Close button and implement its Click event as follows:
     
    System::Void btnClose_Click(System::Object *  sender, System::EventArgs *  e)
    {
    	 Close();
    }
  4. Execute the application to test it
  5. Create some continents and add some countries to them

The Parent of an Attribute

Once an attribute has been created, to identify the element it belongs to, you can access its XmlAttribute::OwnerElement property. This property produces an XmlElement value.

Attribute Removal

If you find out that an element has one or more undesired attributes, you can delete them and you have various options to perform this operation.

Since the attributes are stored in a collection, you can locate the undesired attribute by its index and then delete it. To do this, you can call the XmlAttributeCollection.RemoveAt() method. Its syntax is:

public: virtual XmlAttribute* RemoveAt(int i);

This method expects the index of the attribute that needs to be removed. As mentioned for the XmlAttributeCollection::ItemOf indexed property, to efficiently use this RemoveAt() method, you should know the exact index of the attribute, otherwise, you may access and therefore delete the wrong attribute. An alternative is to explicitly identify the attribute you want to delete. To do this, you can call the XmlAttributeCollection.Remove() method. Its syntax is:

public: virtual XmlAttribute* Remove(XmlAttribute* node);

This method takes as attribute the XmlAttribute identification of the attribute you want to remove.

To delete all attributes of an element, you can call the XmlAttributeCollection.RemoveAll() method. Its syntax is:

public: virtual void RemoveAll();

This method would simply remove all attributes that belong to an XmlElement object.

 

Previous Copyright © 2004-2005 FunctionX, Inc. Next