[ Team LiB ] Previous Section Next Section

17.4 XmlDataDocument Object Overview

There is one .NET object that combines an XML view with a DataSet—the XmlDataDocument. The XmlDataDocument inherits from XmlDocument, so it provides the same node-based iteration ability and XPath querying methods. It also provides a single additional property, XmlDataDocument.DataSet, which provides the relational representation of XML data.

When using the XmlDataDocument, you can start with either an XML document or a DataSet. To create an XmlDataDocument based on a DataSet, use the overloaded constructor that accepts a DataSet instance:

XmlDataDocument dataDoc = new XmlDataDocument(ds);

Although you can use the XmlDataDocument.Nodes collection to modify the information in the DataSet, it becomes much more difficult to take into account referential integrity and other database-specific concepts. It can be useful if you want to execute an XPath query or perform an XSLT transform (as shown in the next two examples) or take advantage of some other XML-specific feature. However, it won't replace the tasks you can accomplish through the DataSet model.

Another useful role for the XmlDataDocument is to provide a DataSet projection on an XML file. To use this approach, you create the XmlDataDocument, load a schema into the DataSet (this is a required step), and then load the XML file using the XmlDataDocument.Load( ) method:

XmlDataDocument dataDoc = new XmlDataDocument();
dataDoc.DataSet.ReadXmlSchema("myschema.xsd");
dataDoc.Load("myfile.xml")

The primary advantage of this approach, versus just using the DataSet directly, is that you don't lose any information that isn't defined in the schema. The DataSet acts as a projection of a portion of the information. If you load a document with an extra element that's not included in the DataSet schema, you won't be able to access that column through the XmlDocument.DataSet object. However, you can access it directly through the XmlDocument nodes, and you won't lose the information when you call the XmlDocument.Save( ) method.

17.4.1 Searching a DataSet with XPath

You can use the XmlDataDocument to perform an XPath query. Example 17-4 demonstrates how you can create the XmlDataDocument for an existing DataSet and then select nodes using an XPath query.

Example 17-4. Searching a DataSet with XPath
// ... create and populate a DataSet (ds) with the query:
// SELECT CategoryID, CategoryName, Description  FROM Categories

// Create the XML data document interface.
XmlDataDocument dataDoc = new XmlDataDocument(ds);

// Perform search for all Categories that have a
// CategoryName which starts with "C".
string XPath;
XPath = @"//Categories[starts-with(child::CategoryName, 'C')]";
XmlNodeList nodes = dataDoc.DocumentElement.SelectNodes(XPath);

foreach (XmlNode node in nodes)
{
    Console.Write("\nMatch: ");

    foreach (XmlNode child in node.ChildNodes)
    {
         Console.WriteLine(child.InnerText);
    }
}

The XPath query roughly translates into "get all the nodes named Categories where the contained CategoryName element has a value that starts with the letter 'C.'" The code then iterates through the results and produces the following console output:

Match: 2
Condiments
Sweet and savory sauces, relishes, spreads, and seasonings

Match: 3
Confections
Desserts, candies, and sweet breads

17.4.2 Transforming DataSet XML with XSLT

Another reason you might use the XmlDataDocument is so you can apply an XSL transformation. XSL is a language that defines transformations. These transformations allow you to convert an XML document into an XML document with a different format or an entirely different document (such as an HTML page). XSL documents are themselves written as XML documents that use a specialized XML grammar. This is usually called the XSL transformation document, and is given the extension .xsl or .xslt. Essentially, the XSL document maps the source XML to a new document. In .NET, XSL transformations are performed by the XslTransform class in the System.Xml.Xsl namespace.

The XSL standard (defined at http://www.w3.org/TR/xslt) is beyond the scope of this book. However, it's easy to illustrate the fundamentals with a quick example. Consider, for example, this simple XSL document:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

<xsl:template match="CustomerDataSet">
 This is the Customer DataSet.
 (If this is an HTML document, we could insert opening tags here.)

 Here's the customer list:
      <xsl:apply-templates select="Customers"/>

 (Closing tags belong here.)
</xsl:template>

<xsl:template match="Customers">
Customer: <xsl:value-of select="ContactName"/>  
Phone: <xsl:value-of select="Phone"/></xsl:template>

</xsl:stylesheet>

The document matches two elements in the XML document. First, it matches CustomerDataSet as the root, which must be the name of the DataSet you create. Once this match is made (on the fourth line), a few lines of ordinary text are output into the new document. Then, the Customers element is matched, which is the name of the table rows. Every time a customer row is found, the text from the ContactName and Phone elements are output.

Example 17-5 shows a console application that uses this XSL document. Note that the DataSet is carefully generated to use the matching element names CustomerDataSet and Customers. If it doesn't, the XSL transform will fail. The source XML for the transformation is supplied directly from the XmlDataDocument. The target document is the output stream for the console window.

Example 17-5. Transforming a DataSet with XSL
using System;
using System.Data;
using System.Data.SqlClient;
using System.Xml;
using System.Xml.Xsl;

public class XslTransformDataSet
{
    private static string connectionString = "Data Source=localhost;" +
         "Initial Catalog=Northwind;Integrated Security=SSPI";

    public static void Main() 
    {
        string SQL = "SELECT TOP 5 * FROM Customers";

        // Create ADO.NET objects.
        SqlConnection con = new SqlConnection(connectionString);
        SqlCommand com = new SqlCommand(SQL, con);
        SqlDataAdapter adapter = new SqlDataAdapter(com);
        DataSet ds = new DataSet("CustomerDataSet");

        // Execute the command.
        try
        {
            con.Open();
            adapter.FillSchema(ds, SchemaType.Mapped, "Customers");
            adapter.Fill(ds, "Customers");
        }
        catch (Exception err)
        {
            Console.WriteLine(err.ToString());
        }
        finally
        {
            con.Close();
        }

        // Create the XML data document interface.
        XmlDataDocument dataDoc = new XmlDataDocument(ds);

        // Create the XSL transform object.
        XslTransform xsl = new XslTransform();
        xsl.Load("transform.xsl");
             
        // Perform the transformation.
        xsl.Transform(dataDoc, null, Console.Out);
     }
}

When this code is executed, you'll see the following output:

<?xml version="1.0" encoding="IBM437"?>
 This is the Customer DataSet.
 (If this is an HTML document, we could insert opening tags here.)

 Here's the customer list:

Customer: Maria Anders, Phone: 030-0074321
Customer: Ana Trujillo, Phone: (5) 555-4729
Customer: Antonio Moreno, Phone: (5) 555-3932
Customer: Thomas Hardy, Phone: (171) 555-7788
Customer: Christina Berglund, Phone: 0921-12 34 65

 (Closing tags belong here.)
    [ Team LiB ] Previous Section Next Section