Using XML Data






Using XML Data

The following sections introduce you to the basic terminology and format of Extensible Markup Language (XML) files, including a discussion of the XmlDocument and XmlNode classes, which are part of the System.Xml namespace. You will also learn how you can synchronize data in a DataSet object with data in an XmlDocument object.

Using the XmlNode, XmlDocument, XmlTextReader, and XmlTextWriter Classes

To understand the .NET Framework representation of an XML document, let's start with the concept of a node. A node is one item in an XML document—it might be an attribute, a comment, an element, or something else. In the System.Xml namespace, nodes are represented by XmlNode objects. Figure shows the most important members of the XmlNode class.

Figure Important Members of the XmlNode Class

Member

Type

Description

AppendChild()

Method

Adds a new child node to the end of this node's list of children.

Attributes

Property

Specifies a collection of the attributes of this node.

ChildNodes

Property

Specifies a collection of child nodes of this node.

FirstChild

Property

Specifies the first child node of this node.

InnerText

Property

Specifies the value of this node and all its children.

InnerXml

Property

Specifies the XML code representing just the children of this node.

InsertAfter()

Method

Inserts a new node after this node.

InsertBefore()

Method

Inserts a new node before this node.

LastChild

Property

Specifies the last child node of this node.

Name

Property

Specifies the name of the node.

NextSibling

Property

Specifies the next child node of this node's parent node.

NodeType

Property

Specifies the type of this node. The XmlNodeType enumeration includes values for all possible node types.

OuterXml

Property

Specifies the XML code representing this node and all its children.

ParentNode

Property

Specifies the parent of this node.

PrependChild()

Method

Adds a new child node to the start of this node's list of children.

PreviousSibling()

Method

Specifies the previous child node of this node's parent node.

RemoveAll()

Method

Removes all children of this node.

RemoveChild()

Method

Removes a specified child of this node.

ReplaceChild()

Method

Replaces a child node with a new node.

Value

Property

Specifies the value of the node.

XmlNode objects are collected into an XmlDocument object. The XmlDocument class provides an in-memory representation of an XML document. Figure lists the most important members of the XmlDocument class.

Figure Important Members of the XmlDocument Class

Member

Type

Description

CreateAttribute()

Method

Creates a new attribute node

CreateElement()

Method

Creates a new element node

CreateNode()

Method

Creates a new XmlNode object

DocumentElement

Property

Returns the XmlNode object that represents the root node of this document

GetElementsByTagName()

Method

Returns a list of all elements with the specified tag name

Load()

Method

Loads an XML document into an XmlDocument object

LoadXml()

Method

Loads a string of XML data into an XmlDocument object

Save()

Method

Saves the XmlDocument object as a file or stream

WriteTo()

Method

Saves the XmlDocument object to an XmlWriter object

Follow these steps to learn how to read the contents of an XML document:

  1. Add a new Visual C# ASP.NET Web Application project (Example7_3) to the current solution.

  2. Add a new XML file (BobsTractors.xml). Enter this text in the new file and then save the file:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Customer list for Bob's Tractor Parts -->
    <Customers>
        <Customer CustomerNumber="1">
            <CustomerName>Lambert Tractor Works
                </CustomerName>
            <CustomerCity>Millbank</CustomerCity>
            <CustomerState>WA</CustomerState>
        </Customer>
        <Customer CustomerNumber="2">
            <CustomerName><![CDATA[Joe's Garage]]>
                </CustomerName>
            <CustomerCity>Doppel</CustomerCity>
            <CustomerState>OR</CustomerState>
        </Customer>
    </Customers>
    
  3. Place a Button control (btnLoadXml) and a ListBox control (lbNodes) on the form.

  4. Switch to Code view and add the following using directives:

    using System.Xml;
    using System.IO;
    
  5. Double-click the Button control and enter this code to load data when the button is clicked:

    private void btnLoadXml_Click(object sender, System.EventArgs e)
    {
        // Hook up to the disk file
        XmlTextReader xtr = new XmlTextReader(
            Server.MapPath("BobsTractors.xml"));
        xtr.WhitespaceHandling = WhitespaceHandling.None;
        XmlDocument xd = new XmlDocument();
        // Load the file into the XmlDocument
        xd.Load(xtr);
        // Add an item representing the document to the ListBox
        lbNodes.Items.Add("XML Document");
        // Find the root node, and add it together with its children
        XmlNode xnod = xd.DocumentElement;
        AddWithChildren(xnod, 1);
    }
    
    private void AddWithChildren(XmlNode xnod, Int32 intLevel)
    {
        // Adds a node to the ListBox, together with its children.
        // intLevel controls the depth of indenting
        XmlNode xnodWorking;
        string strIndent = "";
        for (int i=0; i< 2*intLevel; i++)
            strIndent += "&nbsp;";
    
        // Get the value of the node (if any)
        String strValue= (String) xnod.Value;
        if(strValue != null)
            strValue = "&nbsp;:&nbsp;" + strValue;
    
        // Add the node details to the ListBox
        string str = strIndent + xnod.Name + strValue;
        StringWriter writer = new StringWriter();
        Server.HtmlDecode(str, writer);
        lbNodes.Items.Add(writer.ToString());
    
        // For an element node, retrieve the attributes
        if(xnod.NodeType == XmlNodeType.Element)
        {
           XmlNamedNodeMap mapAttributes= xnod.Attributes;
           // Add the attributes to the ListBox
           foreach(XmlNode xnodAttribute in mapAttributes)
           {
              str = strIndent + "&nbsp;&nbsp;" +
                  xnodAttribute.Name + "&nbsp;:&nbsp; " +
                  xnodAttribute.Value;
              writer = new StringWriter();
              Server.HtmlDecode(str, writer);
              lbNodes.Items.Add(writer.ToString());
          }
         // If there are any child nodes, call this procedure recursively
          if(xnod.HasChildNodes)
          {
              xnodWorking = xnod.FirstChild;
              while (xnodWorking != null)
              {
                  AddWithChildren(xnodWorking, intLevel + 1);
                  xnodWorking = xnodWorking.NextSibling;
              }
          }
      }
    }
    
  6. Set the Web project as the startup project for the solution and run the application. Click the button. The contents of the XML file will be dumped to the ListBox control.

graphics/note_icon.gif

The Server.MapPath() method takes a relative virtual path for a file and returns its physical path. Remember, all the ASP.NET code is running on the server, so any file paths must make sense in the context of the server's file system.


The code in the previous example uses an XmlTextReader object to read the disk file into the XmlDocument object.

The code uses the DocumentElement property of the XmlDocument object to find the node at the root of the tree representation of the XML document. After that, it's just a matter of recursively calling a procedure that adds information about the node to the ListBox control.

One bit of added complexity in the code is necessary to deal with attributes. Attribute nodes are not included in the ChildNodes collection of a node in the XmlDocument object. Instead, you can use the Attributes property of the XmlNode object to get a collection of attribute nodes only. The code uses an XmlNamedNodeMap object to hold this collection; this object can hold an arbitrary collection of XmlNode objects of any type.

You can also modify an XML document through the XmlDocument object. To do so, you need to modify the individual XmlNode objects and then write the file back to disk as shown in the following code segment:

// Write the modified file to disk
XmlTextWriter xtw = new XmlTextWriter(
Server.MapPath("BobsTractors.new.xml"), System.Text.Encoding.UTF8);
xd.WriteTo(xtw);
xtw.Flush();
xtw.Close();

graphics/tip_icon.gif

When you have to read data fast in a forward-only manner and memory is a constraint, you should use XmlTextReader.

When memory is not a constraint and you want flexibility for inserting, deleting, and updating data in any direction, you should use XmlDocument.


Treating XML As Relational Data

You can treat an XML document as relational data. To do this, you can use the XmlDataDocument class, which inherits from XmlDocument. The key feature of the XmlDataDocument class is that it can be synchronized with a DataSet object.

For example, consider the following code segment that reads the BobsTractor.xml file and populates a DataGrid control:

// Create an XmlTextReader object to read the file
XmlTextReader xtr = new XmlTextReader(Server.MapPath("BobsTractors.xml"));
XmlDataDocument xdd = new XmlDataDocument();
// Get the DataSet
DataSet ds = xdd.DataSet;
// Read the schema of the file to initialize the DataSet
ds.ReadXmlSchema(xtr);
xtr.Close();
xtr = new XmlTextReader(Server.MapPath("BobsTractors.xml"));
xtr.WhitespaceHandling = WhitespaceHandling.None;
// Load the file into the XmlDataDocument
xdd.Load(xtr);
xtr.Close();
// And display it on the DataGrid
dgXml.DataSource = ds;
dgXml.DataBind();

For the DataSet object to properly represent the XML, it must have the same schema (structure) as the XML file. In the previous code segment, I've ensured this by using the ReadXmlSchema() method of the DataSet object to load the schema from the same XML file the XmlDataDocument object holds. The XmlTextReader object has to be closed and reopened after the schema is read because it's a forward-only object.

The synchronization between the XmlDataDocument object and the DataSet object is two way. If you derive a dataset object from an XmlDataDocument object, modify the dataset object, and then write the XmlDataDocument object back to disk, the changes you made in the DataSet object are reflected in the XML file.

graphics/note_icon.gif

If you already have a DataSet object in your code, you can create the equivalent XML document by calling an overloaded constructor of the XmlDataDocument class, like so:

XmlDataDocument xdd = new XmlDataDocument(ds);



     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows