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