Using XML with DataSets


Using XML with DataSets

In Chapter 12, "Working with DataSets," you learned how to use a DataSet to represent data retrieved from a database such as Microsoft SQL Server. A DataSet can also be used to represent XML data.

A DataSet can represent XML data in two ways : You can load XML data directly into a DataSet , or you can build an XmlDataDocument class from an existing DataSet . In the following sections, you examine both ways of working with XML data.

Reading an XML Document into a DataSet

You can read an XML file directly from the hard drive into a DataSet by using the ReadXml() method of the DataSet class. For example, imagine that you want to represent the XML document contained in Listing 13.1 with a DataSet .

Listing 13.1 Menu.xml
 <Menu>   <MenuItem>     <Food>       French Toast     </Food>     <Price>       12.45     </Price>   </MenuItem>   <MenuItem>     <Food>       Scrambled Eggs     </Food>     <Price>       3.89     </Price>   </MenuItem> </Menu> 

The C# version of this code can be found on the CD-ROM.

Listing 13.1 contains a simple XML file that represents a menu from a restaurant. The menu contains two menu items. The first item on the menu is French Toast, which costs $12.45, and the second item is Scrambled Eggs, which costs $3.89.

The ASP.NET page in Listing 13.2 demonstrates how you can read the Menu.xml file into a DataSet (see Figure 13.1).

Listing 13.2 ReadMenu.aspx
 <%@ Import Namespace="System.Data" %> <Script Runat="Server"> Sub Page_Load   Dim dstMenu As DataSet   dstMenu = New DataSet()   dstMenu.ReadXml( MapPath( "Menu.xml" ) )   dgrdMenu.DataSource = dstMenu   dgrdMenu.DataBind() End Sub </Script> <html> <head><title>ReadMenu.aspx</title></head> <body> <asp:DataGrid   ID="dgrdMenu"   cellpadding="10"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Figure 13.1. Displaying the Menu.xml file.

graphics/13fig01.jpg

In the Page_Load subroutine in Listing 13.2, an instance of the DataSet class is created. Next, the ReadXml() method is called to read the Menu.xml file from the hard drive. The DataSet is bound to the DataGrid control, and the menu is displayed.

NOTE

You might notice that the MapPath method is used in Listing 13.2 with the ReadXml() method. The MapPath() method translates a virtual file path , such as /xmlfiles/menu.xml , into a physical file path, such as c:\inetpub\ wwwroot \_xmlfiles\menu.xml . The ReadXml() method expects a physical path.


You can use the same method to bind XML data to any of the standard ASP.NET controls that have a DataSource property. For example, you could bind an XML file that contains a list of countries to a DropDownList or ListBox control.

Using a Schema with ReadXml

In the preceding section, you learned how to use the ReadXml() method to load an XML file into a DataSet . You might have been surprised that you did not have to supply either a Document Type Definition (DTD) or XML schema when loading the XML file. How does the DataSet determine the structure of the XML document? It makes its best guess.

When you read the XML file into the DataSet , the DataSet infers the structure of the XML file. For example, it checks whether the elements directly under the root node can be interpreted as tables. If they can be, the root node is interpreted as a DataSet . Otherwise, the root node represents a table.

There are some significant disadvantages to allowing the DataSet to guess the structure of an XML document. One problem is that the DataSet must interpret all the elements as representing strings. So, even the Price element in the Menu.xml file in Listing 13.1 is interpreted as a string, when it should, more accurately be represented as a decimal.

If you are simply displaying the XML file in a control such as a DataGrid , you might not care how the value of the element is represented. However, in certain applications, you want the data types of the elements to be correctly represented. To do so, you need to supply an XML schema with the XML file.

NOTE

To learn more details about XML schemas, visit the W3C Web site at http://www.w3.org/xml/schema.


You can specify a schema with an XML file in two ways. You can include the schema in the same document as the XML file, or you can read the schema separately by using the ReadXmlSchema() method.

The file in Listing 13.3 contains both a schema and XML data in the same file.

Listing 13.3 SchemaData.xml
 <Menu>   <xsd:schema id="Menu"   xmlns:xsd="http://www.w3.org/2001/XMLSchema"   xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">     <xsd:element name="MenuItem">       <xsd:complexType>         <xsd:all>           <xsd:element name="Food" minOccurs="0" type="xsd:string"/>           <xsd:element name="Price" minOccurs="0" type="xsd:decimal"/>         </xsd:all>       </xsd:complexType>     </xsd:element>     <xsd:element name="Menu" msdata:IsDataSet="true">       <xsd:complexType>         <xsd:choice maxOccurs="unbounded">           <xsd:element ref="MenuItem"/>         </xsd:choice>       </xsd:complexType>     </xsd:element>   </xsd:schema>   <MenuItem>     <Food>       French Toast     </Food>     <Price>       12.45     </Price>   </MenuItem>   <MenuItem>     <Food>       Scrambled Eggs     </Food>     <Price>       3.89     </Price>   </MenuItem> </Menu> 

The C# version of this code can be found on the CD-ROM.

The schema in Listing 13.3 specifies the data types for both the Food and Price elements: The Food element contains string values, and the Price element contains decimal values.

The ASP.NET page in Listing 13.4 displays all the menu items from the SchemaData.xml file by using a Repeater control (see Figure 13.2).

Listing 13.4 ReadSchemaData.aspx
 <%@ Import Namespace="System.Data" %> <Script Runat="Server"> Sub Page_Load   Dim dstMenu As DataSet   dstMenu = New DataSet()   dstMenu.ReadXml( MapPath( "SchemaData.xml" ) )   rptMenu.DataSource = dstMenu   rptMenu.DataBind() End Sub </Script> <html> <head><title>ReadSchemaData.aspx</title></head> <body> <asp:Repeater   ID="rptMenu"   Runat="Server" > <ItemTemplate>   <hr>   <p><b>Food:</b>   <br><%# Container.DataItem( "Food" )%>   <p><b>Food Data Type:</b>   <br><%# Container.DataItem( "Food" ).GetType %>   <p><b>Price:</b>   <br><%# Container.DataItem( "Price" )%>   <p><b>Price Data Type:</b>   <br><%# Container.DataItem( "Price" ).GetType %> </ItemTemplate> </asp:Repeater> </body> </html> 

The C# version of this code can be found on the CD-ROM.

Figure 13.2. Displaying menu items in a Repeater control.

graphics/13fig02.jpg

In the Page_Load subroutine in Listing 13.4, the ReadXml() method retrieves the SchemaData.xml file into the DataSet . The DataSet is then bound to a Repeater control, which displays the values of all the elements.

Additionally, to illustrate that the Food column is represented as a string and the Price column is represented as a decimal, the data type of each element is displayed by the Repeater control. The data type is returned with the GetType() method.

If you prefer, you can place an XML schema in a separate file and read the schema by using the ReadXmlSchema() method instead. For example, Listing 13.5 contains the schema for the Menu.xml file.

Listing 13.5 MenuSchema.xml
 <xsd:schema id="Menu"   xmlns:xsd="http://www.w3.org/2001/XMLSchema"   xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">   <xsd:element name="MenuItem">     <xsd:complexType>       <xsd:all>         <xsd:element name="Food" minOccurs="0" type="xsd:string"/>         <xsd:element name="Price" minOccurs="0" type="xsd:decimal"/>       </xsd:all>     </xsd:complexType>   </xsd:element>   <xsd:element name="Menu" msdata:IsDataSet="true">     <xsd:complexType>       <xsd:choice maxOccurs="unbounded">         <xsd:element ref="MenuItem"/>       </xsd:choice>     </xsd:complexType>   </xsd:element> </xsd:schema> 

The C# version of this code can be found on the CD-ROM.

The page in Listing 13.6 illustrates how you can read the MenuSchema.xml file by using the ReadXmlSchema() method.

Listing 13.6 ReadSchema.aspx
 <%@ Import Namespace="System.Data" %> <Script Runat="Server"> Sub Page_Load   Dim dstMenu As DataSet   dstMenu = New DataSet()   dstMenu.ReadXmlSchema( MapPath( "MenuSchema.xml" ) )   dstMenu.ReadXml( MapPath( "menu.xml" ) )   dgrdMenu.DataSource = dstMenu   dgrdMenu.DataBind() End Sub </Script> <html> <head><title>ReadSchema.aspx</title></head> <body> <asp:DataGrid   ID="dgrdMenu"   cellpadding="10"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM.

The ASP.NET page in Listing 13.6 uses both the MenuSchema.xml and Menu.xml files to load the XML data. After the XML data is retrieved into the DataSet , the DataSet is bound to a DataGrid control, and the XML data is displayed.

Writing an XML Document from a DataSet

The DataSet class includes several methods for retrieving an XML representation of the data contained in a DataSet . You can use these methods regardless of whether you originally loaded the DataSet with data from an XML file or from a database table.

If you want to retrieve a string representation of XML data, you can use the GetXml() method. For example, the page in Listing 13.7 uses the GetXml() method to output an XML representation of a DataSet to the browser (see Figure 13.3).

Listing 13.7 GetXml.aspx
 <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <Script Runat="Server"> Sub Page_Load   Dim conPubs As SqlConnection   Dim dadTitles As SqlDataAdapter   Dim dstTitles As DataSet   Dim strXmlData As String   conPubs = New SqlConnection( "Server=localhost;UID=sa;PWD=secret;Database=Pubs" )   dadTitles = New SqlDataAdapter( "Select * From Titles", conPubs )   dstTitles = New DataSet()   dadTitles.Fill( dstTitles, "Titles" )   strXmlData = dstTitles.GetXml()   Response.Write( "<pre>" & Server.HtmlEncode( strXmlData ) & "</pre>" ) End Sub </Script> 

The C# version of this code can be found on the CD-ROM.

Figure 13.3. An XML representation of data contained in a DataSet .

graphics/13fig03.jpg

In Listing 13.7, a DataSet is populated from a SQL Server database table named Titles. After the Titles table is added to the DataSet , the GetXml() method retrieves a string that contains an XML representation of the DataSet . This string is assigned to a variable named strXmlData and outputted using the Response object.

NOTE

The Server.HtmlEncode() method in Listing 13.7 converts the < and > characters to HTML-safe character entities so they can be properly displayed in a browser.


The GetXml() method actually retrieves two things: the XML data itself and the XML schema for the DataSet . If you want to retrieve only the XML schema, not the XML data, you can use the GetXmlSchema() method.

The DataSet class also contains two methods for writing an XML representation of the DataSet to a stream: WriteXml() and WriteXmlSchema() .

The page in Listing 13.8, for example, illustrates how you can write an XML representation of a DataSet to a file named myXml.xml by using the WriteXml() method.

Listing 13.8 WriteXml.aspx
 <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <Script Runat="Server"> Sub Page_Load   Dim conPubs As SqlConnection   Dim dadTitles As SqlDataAdapter   Dim dstTitles As DataSet   conPubs = New SqlConnection( "Server=localhost;UID=sa;PWD=secret;Database=Pubs" )   dadTitles = New SqlDataAdapter( "Select * From Titles", conPubs )   dstTitles = New DataSet()   dadTitles.Fill( dstTitles, "Titles" )   dstTitles.WriteXml( "c:\myXml.xml" )   Response.Write( "Saved myXml.xml file!" ) End Sub </Script> 

The C# version of this code can be found on the CD-ROM.

In Listing 13.8, the DataSet that is created contains the Titles table from the Pubs database. An XML representation of the DataSet is written to a file named myXml.xml located at the root of the C: drive.

The WriteXml() method accepts an additional parameter that specifies how the XML data should be saved. This parameter can accept any of the following values of the XmlWriteMode enumeration:

  • DiffGram ” Writes the XML data so that it can be used with SQL Server 2000 UpdateGrams

  • IgnoreSchema ” Writes the XML data without including the XML schema

  • WriteSchema ” Writes both the XML data and the XML schema (the default)

The page in Listing 13.9, for example, writes an XML representation of a DataSet to the Response object's output stream. The XmlWriteMode parameter is assigned the value IgnoreSchema to display only the XML data. On recent versions of Internet Explorer (for example, Internet Explorer 5.0 and higher), the XML file is displayed directly in the browser (see Figure 13.4).

Listing 13.9 WriteXMLResponse.aspx
 <%@ Page ContentType="text/xml" %> <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Data.SqlClient" %> <Script Runat="Server"> Sub Page_Load   Dim conPubs As SqlConnection   Dim dadTitles As SqlDataAdapter   Dim dstTitles As DataSet   conPubs = New SqlConnection( "Server=localhost;UID=sa;PWD=secret;Database=Pubs" )   dadTitles = New SqlDataAdapter( "Select * From Titles", conPubs )   dstTitles = New DataSet()   dadTitles.Fill( dstTitles, "Titles" )   dstTitles.WriteXml( Response.OutputStream, XmlWriteMode.IgnoreSchema ) End Sub </Script> 

The C# version of this code can be found on the CD-ROM.

Figure 13.4. Writing XML to the output stream.

graphics/13fig04.jpg

CAUTION

A page directive at the top of Listing 13.9 specifies the content type of the output of the page. Internet Explorer has an unpleasant tendency to cache the content type of a page. So, if you open the page once in Internet Explorer without specifying the content type correctly, you'll have a difficult time displaying the page correctly in the browser thereafter. If you get desperate, you can force Internet Explorer to recognize a new page content type by renaming the page.


Using XMLDataDocuments with DataSets

In the previous sections, you learned how to load an XML document into a DataSet . A DataSet provides you with a relational view of the XML data; all the information is represented with tables, rows, and columns .

In certain situations, however, working with a nonrelational view of the data contained in a DataSet is more convenient . In other words, sometimes it makes more sense to represent data as nodes on a tree rather than as tables, rows, and columns.

Consider, for example, the XML document in Listing 13.10.

Listing 13.10 Recipes.xml
 <RecipeList>   <Recipe>     <Name>       French Toast     </Name>     <Ingredients>       <Ingredient>         Bread       </Ingredient>       <Ingredient>         Butter       </Ingredient>       <Ingredient>         Sugar       </Ingredient>     </Ingredients>   </Recipe>   <Recipe>     <Name>       Tomato Soup     </Name>     <Ingredients>       <Ingredient>         Tomatoes       </Ingredient>       <Ingredient>         Water       </Ingredient>     </Ingredients>   </Recipe> </RecipeList> 

The C# version of this code can be found on the CD-ROM.

The XML document in Listing 13.10 represents a list of recipes. It contains recipes for French Toast and Tomato Soup. Each recipe, in turn , contains a list of ingredients.

In the Recipes.xml document, notice that the < Ingredients> tag is nested under the < Recipe> tag. There is nothing wrong with nesting XML tags, and it provides an intuitive representation of the data. However, translating nested elements into tables, rows, and columns can be somewhat complex.

You can, in fact, load the XML document in Listing 13.10 into a DataSet . However, the DataSet must do some extra work to represent the structure of the XML document using a relational view. The page in Listing 13.11 demonstrates how a DataSet would translate the Recipes.xml file (see Figure 13.5).

Listing 13.11 ReadRecipes.aspx
 <%@ Import Namespace="System.Data" %> <Script Runat="Server"> Sub Page_Load   Dim dstRecipes As DataSet   dstRecipes = New DataSet()   dstRecipes.ReadXml( MapPath( "Recipes.xml" ) )   lblTable1.Text = dstRecipes.Tables( 0 ).TableName   dgrdTable1.DataSource = dstRecipes   dgrdTable1.DataMember = dstRecipes.Tables( 0 ).TableName   lblTable2.Text = dstRecipes.Tables( 1 ).TableName   dgrdTable2.DataSource = dstRecipes   dgrdTable2.DataMember = dstRecipes.Tables( 1 ).TableName   lblTable3.Text = dstRecipes.Tables( 2 ).TableName   dgrdTable3.DataSource = dstRecipes   dgrdTable3.DataMember = dstRecipes.Tables( 2 ).TableName   DataBind() End Sub </Script> <html> <head><title>ReadRecipes.aspx</title></head> <body> <asp:Label   ID="lblTable1"   Font-Size="14pt"   Runat="Server"/> <br> <asp:DataGrid   ID="dgrdTable1"   CellPadding="10"   Runat="Server" /> <p> <asp:Label   ID="lblTable2"   Font-Size="14pt"   Runat="Server"/> <br> <asp:DataGrid   ID="dgrdTable2"   CellPadding="10"   Runat="Server" /> <p> <asp:Label   ID="lblTable3"   Font-Size="14pt"   Runat="Server"/> <br> <asp:DataGrid   ID="dgrdTable3"   CellPadding="10"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM..

Figure 13.5. Relational view of XML data.

graphics/13fig05.jpg

In the Page_Load subroutine in Listing 13.11, the Recipes.xml file is loaded into a DataSet . When the XML file is loaded, it is automatically converted into three tables: the Recipe, Ingredients, and Ingredient tables. The contents of each table are displayed by a DataGrid .

The Recipe table represents the name of each recipe and a recipe ID (the ID column is automatically generated for you). The Ingredient table represents each ingredient for a recipe. Finally, the Ingredients table joins the Recipe and Ingredient tables using the Recipe_ID and Ingredient_ID columns.

Instead of viewing the contents of the Recipes.xml document as a set of tables, you can view the contents of the XML document nonrelationally by using the XmlDataDocument class, which represents data as nodes on a tree. You create a new XmlDataDocument by using a DataSet in the XmlDataDocument 's constructor.

In Listing 13.12, for example, an instance of the XmlDataDocument class is created from a DataSet . The XmlDataDocument then displays a list of all the ingredients in the Recipes.xml file.

Listing 13.12 XmlDataDocument.aspx
 <%@ Import Namespace="System.Data" %> <%@ Import Namespace="System.Xml" %> <Script Runat="Server"> Sub Page_Load   Dim dstRecipes As DataSet   Dim objDataDocument As XmlDataDocument   Dim objRecipes As XmlNodeList   Dim objRecipe As XmlNode   dstRecipes = New DataSet()   dstRecipes.ReadXml( MapPath( "Recipes.xml" ) )   objDataDocument = New XmlDataDocument( dstRecipes )   objRecipes = objDataDocument.GetElementsByTagName( "Ingredient" )   For Each objRecipe In objRecipes     lblOutput.Text &= objRecipe.InnerXml   Next End Sub </Script> <html> <head><title>XmlDataDocument.aspx</title></head> <body> <h2>All Ingredients</h2> <asp:Label   ID="lblOutput"   Runat="Server" /> </body> </html> 

The C# version of this code can be found on the CD-ROM

NOTE

You must import the System.Xml namespace before using the XmlDataDocument class.


In the Page_Load subroutine in Listing 13.12, an instance of the XmlDataDocument class is created from a DataSet . Next, the GetElementsByTagName() method retrieves a list of nodes that have the tag name Ingredient . Finally, this list of nodes is displayed in a Label control. When the page is displayed, a combined list of ingredients for all the recipes is displayed.

Using the XmlDataDocument class with the DataSet class provides you with a great deal of flexibility. You can use these two classes to provide very different views on the same underlying data. If you want to represent data with tables, columns, and rows, you can use a DataSet . If you want to represent the same data as nodes on a tree, you can use the XmlDataDocument class.



ASP.NET Unleashed
ASP.NET 4 Unleashed
ISBN: 0672331128
EAN: 2147483647
Year: 2003
Pages: 263

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net