Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ASP .NET Web Developer s Guide - Mesbah Ahmed, Chris Garrett

.pdf
Скачиваний:
38
Добавлен:
24.05.2014
Размер:
7.32 Mб
Скачать

380 Chapter 8 • Using XML in the .NET Framework

the collection by using the GetElementsByTagName(“ProductName”) method of the XmlDataDocument object. Finally, it is just a matter of iterating through the productNames collection and loading each of its members in the list box.

At this stage, you will probably ask why we are not finding the unit price of the selected product. Actually, therein lies the beauty of the XmlDataDocument. Because it has extended the XmlDocument class, all of the members of the XmlDocument class are also available to us.Thus, we could use the same technique as shown in our previous example to find the price. Nevertheless, the reason for not showing the searching technique here is that we will cover it later when we discuss the XPathIterator object.

Figure 8.25 XmlDataDocument1.aspx

<!—\Chapter8\xmlDataDocument1.aspx —>

<%@ Page Language = "VB" Debug ="True" %> <%@ Import Namespace="System.Xml" %> <html><head></head><body><form runat="server"> Select a Product: <br/>

<asp:ListBox id="lstProducts" runat="server" rows = "2" /><br/><br/> </body></form><html>

<Script Language="vb" runat="server">

Sub Page_Load(s As Object, e As EventArgs)

If Not Page.IsPostBack Then

Dim myDataDoc As New XmlDataDocument() myDataDoc.Load(Server.MapPath("Catalog2.xml"))

Dim productNames As XmlNodeList

productNames= myDataDoc.GetElementsByTagName("ProductName") Dim x As XmlNode

For Each x In productNames lstProducts.Items.Add (x.FirstChild().Value) Next

End If End Sub </Script>

www.syngress.com

Using XML in the .NET Framework • Chapter 8

381

Using the Relational View of

an XmlDataDocument Object

In this example, we will process and display the Catalog3.xml document’s data as a relational table in a DataGrid. The Catalog3.xml is exactly the same as Catalog2.xml except that it has more data.The Catalog3.xml file is available in the accompanying CD.The output of this example is shown in Figure 8.26.

Figure 8.26 Output of XmlDataDocument DataSet View Example

If we want to process the XML data as relational data, we need to load the schema of the XML document first.We have generated the following schema for the Catalog3.xml using VS.NET. The schema specification is shown in Figure 8.27 (also available in the accompanying CD).

Figure 8.27 Catalog3.xsd

<xsd:schema id="Catalog" targetNamespace="http://tempuri.org /Catalog3.xsd" xmlns="http://tempuri.org/Catalog3.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata ="urn:schemas-microsoft-com:xml-msdata" attributeFormDefault ="qualified" elementFormDefault="qualified">

<xsd:element name="Catalog" msdata:IsDataSet="true" msdata:EnforceConstraints="False">

<xsd:complexType>

<xsd:choice maxOccurs="unbounded"> <xsd:element name="Product">

<xsd:complexType>

<xsd:sequence>

<xsd:element name="ProductID" type="xsd:string" minOccurs="0"

Continued

www.syngress.com

382 Chapter 8 • Using XML in the .NET Framework

Figure 8.27 Continued

msdata:Ordinal="0" />

<xsd:element name="ProductName" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />

<xsd:element name="ListPrice" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />

</xsd:sequence>

<xsd:attribute name="Type" form="unqualified" type="xsd:string"/> <xsd:attribute name="SupplierId" form="unqualified"

type="xsd:string" /> </xsd:complexType>

</xsd:element>

</xsd:choice>

</xsd:complexType>

</xsd:element>

</xsd:schema>

NOTE

When we create a schema from a sample XML document, VS.NET automatically inserts an xmlns attribute to the root element. The value of this attribute specifies the name of the schema. Thus when we created the schema for Catalog3.xml, the schema was named Catalog3.xsd and VS.NET inserted the following attributes in the root element of Catalog3.xml:

<Catalog xmlns="http://tempuri.org/Catalog3.xsd">

In our .aspx code, we loaded the schema using the ReadXmlSchema method of our XmlDataDocument object as:

myDataDoc.DataSet.ReadXmlSchema(Server.MapPath("Catalog3.xsd")).

Next, we have loaded the XmlDataDocument as:

myDataDoc.Load(Server.MapPath("Catalog3.xml")).

www.syngress.com

Using XML in the .NET Framework • Chapter 8

383

Since the DataDocument provides two views, we have exploited its DataSet

.Table(0) property to load the DataGrid and display our XML file’s information in the grid.The complete listing of the code is shown in Figure 8.28.The code is also available in the XmlDataDocDataSet1.aspx file in the accompanying CD.

Figure 8.28 Complete Listing XmlDataDocDataSet1.aspx

<!— Chapter8\XmlDataDocDataSet1.aspx —> <%@ Page Language = "VB" Debug ="True" %> <%@ Import Namespace="System.Xml" %>

<%@ Import Namespace="System.Data" %> <html><head></head><body><form runat="server"> Select a Product: <br/>

<asp:DataGrid id="myGrid" runat="server"/> </body></form></html>

<Script Language="vb" runat="server">

Sub Page_Load(s As Object, e As EventArgs)

If Not Page.IsPostBack Then

Dim myDataDoc As New XmlDataDocument()

' load the schema

myDataDoc.DataSet.ReadXmlSchema(Server.MapPath("Catalog3.xsd"))

' load the xml data

myDataDoc.Load(Server.MapPath("Catalog3.xml"))

myGrid.DataSource = myDataDoc.DataSet.Tables(0)

myGrid.DataBind()

End If End Sub </Script>

Viewing Multiple Tables of

a XmlDataDocument Object

In many instances, an XML document may contain nested elements. Suppose that a bank has many customers, and a customer has many accounts.We have modeled this simple scenario in an XML document with nested elements.This

www.syngress.com

384 Chapter 8 • Using XML in the .NET Framework

document, named Bank1.xml, is shown in Figure 8.29. It is also available in the accompanying CD.

Figure 8.29 Bank1.xml

<?xml version="1.0" encoding="utf-8" ?> <Bank xmlns="http://tempuri.org/Bank1.xsd">

<Customer>

<CustomerID>C100</CustomerID> <CustomerName>Alfred Smith</CustomerName> <City>Toledo</City>

<Account>

<Type>Savings</Type>

<Balance>1500.00</Balance>

</Account>

<Account>

<Type>Checking</Type>

<Balance>111.11</Balance>

</Account>

<Account>

<Type>Home Equity</Type> <Balance>50000</Balance>

</Account>

</Customer>

<Customer> —- —- —- —- —- —-

</Customer>

</Bank>

If we load the above XML document and its schema in an XmlDataDocument object, it will provide two relational tables’ views: one for the customer’s information, and the other for the account’s information. Our objective is to display the data of these relational tables in two DataGrids as shown in Figure 8.30.

To develop this application, first we had to generate the schema for our Bank1.xml file.We used the VS.NET XML designer to accomplish this task. It is

www.syngress.com

Using XML in the .NET Framework • Chapter 8

385

interesting to observe that while creating the schema,VS.NET automatically generates the 1:Many relationship between the Customer and Accounts elements.To establish the relationship, it also creates an auto-numbered primary key column (Customer_Id) in the Customer DataTable. Simultaneously, it inserts the appropriate values of the foreign keys in the Account DataTable.The DataSet view of the generated schema is shown in Figure 8.31.

Figure 8.30 Displaying Customer and Accounts Data in Two Data Grids

Figure 8.31 XmlDataDocument DataSet Representation in Visual Studio .NET

In order to provide the relational view of our XML document (Bank1.xml), VS.NET included the Customer_Id attributes in both Customer and Account elements in its generated schema. It also generated the necessary schema entries to

www.syngress.com

386 Chapter 8 • Using XML in the .NET Framework

describe the implied relationship among the Customer and Account elements. Figure 8.32 shows an excerpt of the generated schema for our XML file.The complete schema is available in a file named Bank1.xsd in the accompanying CD.

Figure 8.32 Primary Key and Foreign Key Specifications in the Bank1.xsd

<xsd:unique name="Constraint1" msdata:PrimaryKey="true"> <xsd:selector xpath=".//Customer" /> <xsd:field xpath="@Customer_Id" /></xsd:unique>

<xsd:keyref name="Customer_Account" refer="Constraint1"msdata:IsNested="true">

<xsd:selector xpath=".//Account" /> <xsd:field xpath="@Customer_Id" />

</xsd:keyref>

In the above fragment of the generated schema, the xsd:unique element specifies the Customer_Id attribute as the primary key of the Customer element. Subsequently, the xsd:keyref element specifies the Customer_Id attribute as the foreign key of the Account element. XPath expressions have been used to achieve the afore-mentioned objectives.

The complete listing of the application is shown in Figure 8.33. It is also available in the xmlDataDocDataSet2.aspx file in the accompanying CD.The code is pretty straightforward.We have loaded two data grids from two DataTables of the DataSet, associated with the XmlDataDocument object.

Figure 8.33 Complete Code of XmlDataDocDataSet2.aspx

<!— Chapter8\XmlDataDocDataSet2.aspx —> <%@ Page Language = "VB" Debug ="True" %> <%@ Import Namespace="System.Xml" %>

<%@ Import Namespace="System.Data" %> <html><head></head><body><form runat="server"> Customers : <br/>

<asp:DataGrid id="myCustGrid" runat="server"/><br/> Accounts : <br/>

<asp:DataGrid id="myAcctGrid" runat="server"/><br/> </body></form></html>

<Script Language="vb" runat="server">

Continued

www.syngress.com

Using XML in the .NET Framework • Chapter 8

387

Figure 8.33 Continued

Sub Page_Load(s As Object, e As EventArgs)

If Not Page.IsPostBack Then

Dim myDataDoc As New XmlDataDocument()

'load the schema myDataDoc.DataSet.ReadXmlSchema(Server.MapPath("Bank1.xsd"))

'load the xmldata myDataDoc.Load(Server.MapPath("Bank1.xml")) myCustGrid.DataSource = myDataDoc.DataSet.Tables("Customer") myCustGrid.DataBind()

'load the Account grid

myAcctGrid.DataSource = myDataDoc.DataSet.Tables("Account") myAcctGrid.DataBind()

End If End Sub </Script>

NOTE

In a Windows Form, the DataGrid control by default provides automatic drill-down facilities for two related DataTables. Unfortunately, it does not work in this fashion in a Web form. Additional programming is needed to simulate the drill-down functionality.

In this example, we have illustrated how an XmlDataDocument object maps nested XML elements into multiple DataTables.Typically, an element is mapped to a table if it contains other elements. Otherwise, it is mapped to a column.

Attributes are mapped to columns. For nested elements, the system creates the relationship automatically.

www.syngress.com

388 Chapter 8 • Using XML in the .NET Framework

Querying XML Data Using

XPathDocument and XPathNavigator

The XmlDocument and the XmlDataDocument have certain limitations. First of all, the entire document needs to be loaded in the cache. Often, the navigation process via the DOM tree itself gets to be clumsy.The navigation via the relational views of the data tables may not be very convenient either.To alleviate these problems, the XML.NET has provided the XPathDocument and XPathNavigator classes.These classes have been implemented using the W3C XPath 1.0 Recommendation (www.w3.org/TR/xpath).

The XPathDocument class enables you to process the XML data without loading the entire DOM tree. An XPathNavigator object can be used to operate on the data of an XPathDocument. It can also be used to operate on XmlDocument and XmlDataDocument. It supports navigation techniques for selecting nodes, iterating over the selected nodes, and working with these nodes in diverse ways for copying, moving, and removal purposes. It uses XPath expressions to accomplish these tasks.

The W3C XPath 1.0 specification outlines the query syntax for retrieving data from an XML document.The motivation of the framework is similar to SQL; however, the syntax is significantly different. At first sight, the XPath query syntax may appear very complex. But with a certain amount of practice, you may find it very concise and effective in extracting XML data.The details of the XPath specification are beyond the scope of this chapter. However, we will illustrate several frequently used XPath query expressions. In our exercises, we will illustrate two alternative ways to construct the expressions.The first alternative follows the recent XPath 1.0 syntax.The second alternative follows XSL Patterns, which is a precursor to XPath 1.0. Let us consider the following XML document named Bank2.xml.The Bank2.xml document is shown in Figure 8.34, and it is also available in the accompanying CD. It contains data about various accounts. We will use this XML document to illustrate our XPath queries.

Figure 8.34 Bank 2.xml

<!-- Chapter8\Bank2.xml -->

<Bank>

<Account>

<AccountNo>A1112</AccountNo>

<Name>Pepsi Beagle</Name>

Continued

www.syngress.com

Using XML in the .NET Framework • Chapter 8

389

Figure 8.34 Continued

<Balance>1200.89</Balance>

<State>OH</State>

</Account>

------ ---

------ ---

<Account>

<AccountNo>A7833</AccountNo> <Name>Frank Horton</Name> <Balance>8964.55</Balance> <State>MI</State>

</Account>

</Bank>

Sample Query Expression 1: Suppose that we want the names of all account holders.The following alternative XPath expressions will accomplish the job equally well:

Alternative 1: descendant::Name

Alternative 2: Bank/Account/Name

The first expression can be read as “Give me the descendents of all Name nodes.”The second expression can be read as “Give me the Name nodes of the Account nodes of the Bank node.” Both of these expressions will return the same node set.

Sample Query Expression 2: We want the records for all customers from Ohio.We may specify any one of the following expressions:

Alternative 1: descendant::Account[child::State=’OH’]

Alternative 2: Bank/Account[child::State=’OH’]

Sample Query Expression 3: Any one of the following alternative expressions will return the Account node-sets for all accounts with a balance more than 5000.00:

Alternative 1: descendant::Account[child::Balance > 5000]

Alternative 2: Bank/Account[child::Balance > 5000.00]

www.syngress.com