AddThis Social Bookmark Button

Print

Using the XmlDataDocument Class

by Wei-Meng Lee
03/31/2003

The DataSet class in ADO.NET provides the developer with a relational view of data. Using the DataSet, data are stored as tables, which allows for easy retrievals using SQL statements. However, there are times when you need a hierarchical representation of the data, allowing you to perform quick searches using, say, XPath queries. You may also need to transform a set of data into another format using XSLT. In such cases, the .NET framework provides you with the XmlDocument class for this purpose.

However, the DataSet and XmlDocument classes only allow one way of data representation--either you have a relational or hierarchical view, but not both. It is with this purpose that the XmlDataDocument class was designed. The XmlDataDocument class is derived from the XmlDocument class, providing a hierarchical view of data as well as a relational view by binding it to a DataSet. Best of all, it automatically synchronizes the data changes made by either one of the two views. XmlDataDocument provides the best of both worlds--it can manipulate the data using the familiar DataSet, as well as support the various services in the XML classes (such as DOM, XPath, and XSLT). In this case, I will show you how you how to use the XmlDataDocument class.

Creating the XML Document

Let's create a new Windows application using Visual Studio .NET 2003. Add an XML document to your project by going to Solution Explorer, right-clicking on the Project name, and selecting Add->Add New Item...

Create the following simple XML document containing some books' information. Name the file Xmlfile1.xml.

   
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<books>
    <book>
        <title isbn="0-596-00461-3">Linux Server Hacks </title>
        <authors>
            <author>Rob Flickenger</author>
        </authors>
        <pubdate>January 2003</pubdate>
        <pages>240</pages>
        <prices>
            <us>24.95</us>
            <ca>38.95</ca>
            <uk>17.50</uk>
        </prices>
    </book>
    <book>
        <title isbn="0-596-00447-8">Google Hacks</title>
        <authors>
            <author>Tara Calishain</author>
            <author>Rael Dornfest</author>
        </authors>
        <pubdate>February 2003</pubdate>
        <pages>352</pages>
        <prices>
            <us>24.95</us>
            <ca>38.95</ca>
            <uk>17.50</uk>
        </prices>
    </book>
    <book>
        <title isbn="0-596-00460-5">Mac OS X Hacks</title>
        <authors>
            <author>Rael Dornfest</author>
            <author>Kevin Hemenway</author>
        </authors>
        <pubdate>March 2003</pubdate>
        <pages>430</pages>
        <prices>
            <us>24.95</us>
            <ca>38.95</ca>
            <uk>17.50</uk>
        </prices>
    </book>
</books>

Generating the Typed DataSet

With the XML document in place, create a XML schema for the XML document. To create a schema in Visual Studio .NET 2003, right-click on the XML document and select Create Schema.

Creating a schema for the XML document
Figure 1: Creating a schema for the XML document

The schema created is as shown in Figure 2:

The XML Schema generated for the XML document (xmlfile1.xsd)
Figure 2: The XML Schema generated for the XML document (xmlfile1.xsd)

Modify the schema by deleting the definition for the <prices> element. You can simply click on the "prices" box in Figure 2 and delete it. I will explain the reason for deleting the prices element in a bit. Next, we want to create a strongly-typed DataSet using the newly created schema. A strongly-typed DataSet allows you to access tables and columns by name, instead of using collection-based methods. To create the strongly-typed DataSet, right-click on the XML Schema and select Generate DataSet.

Generating a strongly-typed DataSet based on the schema
Figure 3: Generating a strongly-typed DataSet based on the schema

You can see the tables created by the Typed DataSet by selecting Preview DataSet... :

The tables created by the Typed DataSet
Figure 4: The tables created by the Typed DataSet

Synchronizing an XmlDataDocument with a DataSet

Now that the Typed DataSet is created, we can proceed to load the XML document using the XmlDataDocument class. First, create a new instance of the Typed DataSet (books, in this case). Then, create an instance of the XmlDataDocument class using the new DataSet, and load the XML document:

   
Const XMLFILENAME = "..\XMLFile1.xml"
Dim booksDS As New books
Dim xmlDocument As New XmlDataDocument(booksDS)
xmlDocument.Load(XMLFILENAME)

Remember how, earlier, we modified the schema and removed the prices element? In this case, the prices element will not be exposed by the DataSet view (you can refer to Figure 4 to confirm that the price information is not found within the four tables). However, the whole XML document is still visible through the hierarchical view. That is, you can still find the prices element if you traverse the document tree. This is an important characteristic of the XmlDataDocument class. Using this feature, you can selectively load only the portions of the XML document that are of concern to you.

We can now modify the data using the DataSet:

   
'---Relational View - changing the isbn of a title
Dim title As books.titleRow
For Each title In booksDS.title
    If title.isbn = "0-596-00460-5" Then
        title.title_Text = "Mac OS X 10.2 Hacks"
    End If
Next

And we can view the data hierarchically by traversing the tree:

   
'---Hierarchical View - 
Dim node As XmlNode
For Each node In xmlDocument.DocumentElement.ChildNodes
    If node.ChildNodes(1).ChildNodes.Count > 1 Then
        Console.WriteLine("Title : " & _
                  node.ChildNodes(0).InnerText)
        Console.WriteLine("ISBN : " & _
                  node.ChildNodes(0).Attributes(0).Value)
        Console.WriteLine("Price (US) : " & _
                node.ChildNodes(4).ChildNodes(0).InnerText)
    End If
Next

In the above case, we are looking for books that have more than one author, and when one is found, we will print out the title, ISBN, and price of the book. The output of this block of code is:

   
Title : Google Hacks
ISBN : 0-596-00447-8
Price (US) : 24.95
Title : Mac OS X 10.2 Hacks
ISBN : 0-596-00460-5
Price (US) : 24.95

The new title for the second book confirms that the updates made using the DataSet are reflected in the hierarchical view.

When we are done with the document, we can save the document using the Save() method:

   
xmlDocument.Save("outfile.xml")

The content of outfile.xml is as follows:

   
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<books xmlns="http://tempuri.org/XMLFile1.xsd">
  <book>
    <title isbn="0-596-00461-3">Linux Server Hacks </title>
    <authors>
      <author>Rob Flickenger</author>
    </authors>
    <pubdate>January 2003</pubdate>
    <pages>240</pages>
    <prices>
      <us>24.95</us>
      <ca>38.95</ca>
      <uk>17.50</uk>
    </prices>
  </book>
  <book>
    <title isbn="0-596-00447-8">Google Hacks</title>
    <authors>
      <author>Tara Calishain</author>
      <author>Rael Dornfest</author>
    </authors>
    <pubdate>February 2003</pubdate>
    <pages>352</pages>
    <prices>
      <us>24.95</us>
      <ca>38.95</ca>
      <uk>17.50</uk>
    </prices>
  </book>
  <book>
    <title isbn="0-596-00460-5">Mac OS X 10.2 Hacks</title>
    <authors>
      <author>Rael Dornfest</author>
      <author>Kevin Hemenway</author>
    </authors>
    <pubdate>March 2003</pubdate>
    <pages>430</pages>
    <prices>
      <us>24.95</us>
      <ca>38.95</ca>
      <uk>17.50</uk>
    </prices>
  </book>
</books>

As you can see, only the title for the third book is changed; the rest of the information in the XML document is still intact.

Loading XmlDataDocument from a Database

Besides loading the XmlDataDocument class from an XML document, you can also load it from a database. The following example shows a DataSet filled with the authors table from the pubs database (I have added a SQLDataAdapter control to my project). An XmlDataDocument object is then loaded with the DataSet.

   
'---load from database
Dim ds As New DataSet
SqlDataAdapter1.SelectCommand.CommandText = _
                "SELECT * FROM authors"
SqlDataAdapter1.Fill(ds, "Authors_Table")
Dim xmldocument2 As New XmlDataDocument(ds)

As usual, you can navigate the data using the DataSet:

   
Dim row As DataRow
For Each row In xmldocument2.DataSet.Tables(0).Rows()
    Console.WriteLine(row.Item(1)) 'prints au_lname
Next

And you can also navigate through the data by applying an XPath query:

   
'---XPATH Query
Dim xmlnodes As XmlNodeList
Dim node2 As XmlNode
xmlnodes = _
   xmldocument2.DocumentElement.SelectNodes("//au_fname")
For Each node2 In xmlnodes
    Console.WriteLine(node2.InnerText)
Next

Wei-Meng Lee (Microsoft MVP) http://weimenglee.blogspot.com is a technologist and founder of Developer Learning Solutions http://www.developerlearningsolutions.com, a technology company specializing in hands-on training on the latest Microsoft technologies.


Return to ONDotnet.com