Home > Articles

chap16_0789724499

Retrieving SQL Server Data in XML Format

SQL Server 2000 can produce results directly in XML format. This option makes data management from the client side easier, especially with Active Server Pages.

When SQL Server 2000 needs to produce results in XML format, there is an internal component that translates the internal rowset into an XML stream. The component to use depends on the selected XML mode.

The XML stream is sent to the client application and the data is shown using any of the available formatting capabilities in either the server or the client computer.

Query Analyzer cannot interpret XML data correctly, because it does not use the XML Parser at all. It shows XML streams as several text rows, each one up to 2033 bytes long. The reason for these Transact-SQL extensions is to access SQL Server data in XML format from HTTP connections or from Web applications, and not from Query Analyzer.

Note

Later in this chapter, the section "HTTP Access to SQL Server" teaches you how to configure Internet Information Server to provide HTTP access to SQL Server. You can follow those instructions to provide HTTP access to SQL Server, and then you can execute the exercises of this section using Internet Explorer to retrieve the XML results directly.

Using the FOR XML Clause

To retrieve data in XML format, you must use the new FOR XML extension for the SELECT statement. Listing 16.8 shows a simple SELECT statement that retrieves the data in XML format and the output produced as seen in Query Analyzer:

Listing 16.8—Using FOR XML to Produce Results in XML Format

USE Northwind
GO

SELECT CategoryID, CategoryName, Description
FROM Categories
FOR XML AUTO
XML_F52E2B61-18A1-11d1-B105-00805F49916B
----------------------------------------------------
<Categories CategoryID="1" CategoryName="Beverages"
Description="Soft drinks, coffees, teas, beers, and ales"/>
<Categories CategoryID="2" CategoryName="Condiments"
Description="Sweet and savory sauces, relishes, spreads, and seasonings"/>
<Categories CategoryID="3" CategoryName="Confections"
Description="Desserts, candies, and sweet breads"/>
<Categories CategoryID="4" CategoryName="Dairy Products"
Description="Cheeses"/><Categories CategoryID="5"
CategoryName="Grains/Cereals"
Description="Breads, crackers, pasta, and cereal"/>
<Categories CategoryID="6" CategoryName="Meat/Poultry"
Description="Prepared meats"/><Categories CategoryID="7"
CategoryName="Produce" Description="Dried fruit and bean curd"/>
<Categories CategoryID="8" CategoryName="Seafood"
Description="Seaweed and fish"/>

(8 row(s) affected)

CAUTION

Adjust the Maximum characters per column setting in Query Analyzer to a value larger than 2033, or some of the examples in this section will be truncated.

You can adjust this setting by going to the Tools, Options menu and entering the Results tab.

You can see in Listing 16.8 and its output some interesting things:

  • The only extra keywords sent to SQL Server were the FOR XML AUTO at the end of a standard SELECT statement.

  • The output in Query Analyzer shows only one column, with a bizarre name: XML plus a GUID-like expression.

  • The entire output goes to a single line, but the row count still says 8 row(s) affected. The output line is extremely long and it includes the entire result set.

Copy the line from the result set pane in Query Analyzer to Notepad, and add some carriage returns and tabs in the right places to make the result more XML-like, as shown in Listing 16.9.

Listing 16.9—Manually Formatted Query Output Using the FOR XML Clause

<Categories
 CategoryID="1"
 CategoryName="Beverages"
 Description="Soft drinks, coffees, teas, beers, and ales"/>
<Categories
 CategoryID="2"
 CategoryName="Condiments"
 Description="Sweet and savory sauces, relishes, spreads, and seasonings"/>
<Categories
 CategoryID="3"
 CategoryName="Confections"
 Description="Desserts, candies, and sweet breads"/>
<Categories
 CategoryID="4"
 CategoryName="Dairy Products"
 Description="Cheeses"/>
<Categories
 CategoryID="5"
 CategoryName="Grains/Cereals"
 Description="Breads, crackers, pasta, and cereal"/>
<Categories
 CategoryID="6"
 CategoryName="Meat/Poultry"
 Description="Prepared meats"/>
<Categories
 CategoryID="7"
 CategoryName="Produce"
 Description="Dried fruit and bean curd"/>
<Categories
 CategoryID="8"
 CategoryName="Seafood"
 Description="Seaweed and fish"/>

Save this document into a file called xmlListing9.xml and try to open it from Internet Explorer. You will receive the error message shown in Figure 16.7, because this XML output is not a well-formed XML document, as it contains more than one root element. This kind of document is called a XML document fragment.

Figure 16.7 The direct output using the FOR XML clause is not a well-formed XML document.

Edit the document again and add a new root node, as shown in Listing 16.10. You can successfully open this document from Internet Explorer.

Listing 16.10—Adding a Root Node Converts the XML Output into a Well-Formed XML Document

<CategoryList>
 <Categories
   CategoryID="1"
   CategoryName="Beverages"
   Description="Soft drinks, coffees, teas, beers, and ales"/>
 <Categories
   CategoryID="2"
   CategoryName="Condiments"
   Description="Sweet and savory sauces, relishes, spreads, and seasonings"/>
 <Categories
   CategoryID="3"
   CategoryName="Confections"
   Description="Desserts, candies, and sweet breads"/>
 <Categories
   CategoryID="4"
   CategoryName="Dairy Products"
   Description="Cheeses"/>
 <Categories
   CategoryID="5"
   CategoryName="Grains/Cereals"
   Description="Breads, crackers, pasta, and cereal"/>
 <Categories
   CategoryID="6"
   CategoryName="Meat/Poultry"
   Description="Prepared meats"/>
 <Categories
   CategoryID="7"
   CategoryName="Produce"
   Description="Dried fruit and bean curd"/>
 <Categories
   CategoryID="8"
   CategoryName="Seafood"
   Description="Seaweed and fish"/>
</CategoryList>

However, you can use aliases to produce a better output that improves the element naming, as shown in the query from Listing 16.11. A more readable naming convention will call every element using the table singular name.

As an example, you can use the alias "Category" for the Categories table, providing in this way the name "Category" to each element in the XML output. Listing 16.12 shows the output after adding the root node Categories to complete the XML fragment produced that this query produces.

Listing 16.11—Using Table and Column Aliases to Improve XML Element Naming

USE Northwind
GO

SELECT CategoryID as ID,
CategoryName as Name,
Description
FROM Categories as Category
FOR XML AUTO

Listing 16.12—Output From Listing 16.11 After Adding the Categories Root Node

<Categories>
 <Category
   ID="1"
   Name="Beverages"
   Description="Soft drinks, coffees, teas, beers, and ales"/>
 <Category
   ID="2"
   Name="Condiments"
   Description="Sweet and savory sauces, relishes, spreads, and seasonings"/>
 <Category
   ID="3"
   Name="Confections"
   Description="Desserts, candies, and sweet breads"/>
 <Category
   ID="4"
   Name="Dairy Products"
   Description="Cheeses"/>
 <Category
   ID="5"
   Name="Grains/Cereals"
   Description="Breads, crackers, pasta, and cereal"/>
 <Category
   ID="6"
   Name="Meat/Poultry"
   Description="Prepared meats"/>
 <Category
   ID="7"
   Name="Produce"
   Description="Dried fruit and bean curd"/>
 <Category
   ID="8"
   Name="Seafood"
   Description="Seaweed and fish"/>
</Categories>

In the preceding examples you selected the XML output in AUTO mode. SQL Server accepts the following modes:

  • RAW: Produces an XML stream as independent row elements, where every element is called row, regardless of the table name

  • AUTO: Produces an XML stream as independent row elements, where every element is named according to the table from where the data is read

  • EXPLICIT: Produces a Universal Table that can be used to have a tighter control on the way XML data is organized

Note

EXPLICIT mode exceeds the objectives of this chapter. If you are interested on detailed information on this XML mode, you can search for information and examples in Books Online, or attend the Microsoft Official Curriculum Course 2091A, "Building XML-Enabled Applications Using Microsoft SQL Server 2000."

Listing 16.13 shows the same query as in Listing 16.11, but in RAW mode, with its unformatted output. As you can see in the output, the main difference is the name of the elements, which in this case is always row.

Listing 16.13—Using FOR XML RAW to Produce Results in XML Format

USE Northwind
GO

SELECT CategoryID as ID,
CategoryName as Name,
Description
FROM Categories as Category
FOR XML RAW
XML_F52E2B61-18A1-11d1-B105-00805F49916B
-----------------------------------------------
<row ID="1" Name="Beverages"
Description="Soft drinks, coffees, teas, beers, and ales"/>
<row ID="2" Name="Condiments"
Description="Sweet and savory sauces, relishes, spreads, and seasonings"/>
<row ID="3" Name="Confections"
Description="Desserts, candies, and sweet breads"/>
<row ID="4" Name="Dairy Products"
Description="Cheeses"/><row ID="5" Name="Grains/Cereals"
Description="Breads, crackers, pasta, and cereal"/>
<row ID="6" Name="Meat/Poultry" Description="Prepared meats"/>
<row ID="7" Name="Produce" Description="Dried fruit and bean curd"/>
<row ID="8" Name="Seafood" Description="Seaweed and fish"/>

(8 row(s) affected)

However, if the SELECT statement retrieves data from more than a single table, there is a big difference between the way the RAW and AUTO modes work. Listing 16.14 shows the same query in both formats, with the correspondent outputs.

Listing 16.14—Comparing RAW and AUTO Modes to Execute Multi-Table Queries

USE Northwind
GO

SELECT CategoryName,
ProductName
FROM Categories as Category
JOIN Products as Product
ON Product.CategoryID = Category.CategoryID
WHERE Product.CategoryID <3
ORDER BY CategoryName, ProductName
FOR XML RAW

SELECT CategoryName,
ProductName
FROM Categories as Category
JOIN Products as Product
ON Product.CategoryID = Category.CategoryID
WHERE Product.CategoryID <3
ORDER BY CategoryName, ProductName
FOR XML AUTO
XML_F52E2B61-18A1-11d1-B105-00805F49916B
----------------------------------------------
<row CategoryName="Beverages" ProductName="Chai"/>
<row CategoryName="Beverages" ProductName="Chang"/>
<row CategoryName="Beverages" ProductName="Chartreuse verte"/>
<row CategoryName="Beverages" ProductName="Côte de Blaye"/>
<row CategoryName="Beverages" ProductName="Guaraná Fantástica"/>
<row CategoryName="Beverages" ProductName="Ipoh Coffee"/>
<row CategoryName="Beverages" ProductName="Lakkalikööri"/>
<row CategoryName="Beverages" ProductName="Laughing Lumberjack Lager"/>
<row CategoryName="Beverages" ProductName="Outback Lager"/>
<row CategoryName="Beverages" ProductName="Rhönbräu Klosterbier"/>
<row CategoryName="Beverages" ProductName="Sasquatch Ale"/>
<row CategoryName="Beverages" ProductName="Steeleye Stout"/>
<row CategoryName="Condiments" ProductName="Aniseed Syrup"/>
<row CategoryName="Condiments"
ProductName="Chef Anton&apos;s Cajun Seasoning"/>
<row CategoryName="Condiments" ProductName="Chef Anton&apos;s Gumbo Mix"/>
<row CategoryName="Condiments" ProductName="Genen Shouyu"/>
<row CategoryName="Condiments"
ProductName="Grandma&apos;s Boysenberry Spread"/>
<row CategoryName="Condiments" ProductName="Gula Malacca"/>
<row CategoryName="Condiments"
ProductName="Louisiana Fiery Hot Pepper Sauce"/>
<row CategoryName="Condiments" ProductName="Louisiana Hot Spiced Okra"/>
<row CategoryName="Condiments" ProductName="Northwoods Cranberry Sauce"/>
<row CategoryName="Condiments"
ProductName="Original Frankfurter grüne Soße"/>
<row CategoryName="Condiments" ProductName="Sirop d&apos;érable"/>
<row CategoryName="Condiments" ProductName="Vegie-spread"/>

(24 row(s) affected)

XML_F52E2B61-18A1-11d1-B105-00805F49916B
----------------------------------------------
<Category CategoryName="Beverages">
<Product ProductName="Chai"/>
<Product ProductName="Chang"/>
<Product ProductName="Chartreuse verte"/>
<Product ProductName="Côte de Blaye"/>
<Product ProductName="Guaraná Fantástica"/>
<Product ProductName="Ipoh Coffee"/>
<Product ProductName="Lakkalikööri"/>
<Product ProductName="Laughing Lumberjack Lager"/>
<Product ProductName="Outback Lager"/>
<Product ProductName="Rhönbräu Klosterbier"/>
<Product ProductName="Sasquatch Ale"/>
<Product ProductName="Steeleye Stout"/>
</Category>
<Category CategoryName="Condiments">
<Product ProductName="Aniseed Syrup"/>
<Product ProductName="Chef Anton&apos;s Cajun Seasoning"/>
<Product ProductName="Chef Anton&apos;s Gumbo Mix"/>
<Product ProductName="Genen Shouyu"/>
<Product ProductName="Grandma&apos;s Boysenberry Spread"/>
<Product ProductName="Gula Malacca"/>
<Product ProductName="Louisiana Fiery Hot Pepper Sauce"/>
<Product ProductName="Louisiana Hot Spiced Okra"/>
<Product ProductName="Northwoods Cranberry Sauce"/>
<Product ProductName="Original Frankfurter grüne Soße"/>
<Product ProductName="Sirop d&apos;érable"/>
<Product ProductName="Vegie-spread"/>
</Category>

(24 row(s) affected)

You can see from the preceding output that AUTO mode shows data in hierarchical way automatically. This suits most applications well, because in this way the user can expand the hierarchy to examine deeper levels of detail if necessary.

Using AUTO mode, you can use the ELEMENTS option to show all the attributes as elements, as in Listing 16.15

Listing 16.15—Use the ELEMENTS Option to Show Attributes As Elements

USE Northwind
GO

SELECT CategoryName,
ProductName
FROM Categories as Category
JOIN Products as Product
ON Product.CategoryID = Category.CategoryID
WHERE Product.CategoryID <3
ORDER BY CategoryName, ProductName
FOR XML AUTO, ELEMENTS
XML_F52E2B61-18A1-11d1-B105-00805F49916B
----------------------------------------------
<Category>
<CategoryName>Beverages</CategoryName>
<Product>
<ProductName>Chai</ProductName>
</Product>
<Product>
<ProductName>Chang</ProductName>
</Product>
<Product>
<ProductName>Chartreuse verte</ProductName>
</Product>
<Product>
<ProductName>Côte de Blaye</ProductName>
</Product>
<Product>
<ProductName>Guaraná Fantástica</ProductName>
</Product>
<Product>
<ProductName>Ipoh Coffee</ProductName>
</Product>
<Product>
<ProductName>Lakkalikööri</ProductName>
</Product>
<Product>
<ProductName>Laughing Lumberjack Lager</ProductName>
</Product>
<Product>
<ProductName>Outback Lager</ProductName>
</Product>
<Product>
<ProductName>Rhönbräu Klosterbier</ProductName>
</Product>
<Product>
<ProductName>Sasquatch Ale</ProductName>
</Product>
<Product>
<ProductName>Steeleye Stout</ProductName>
</Product>
</Category>
<Category>
<CategoryName>Condiments</CategoryName>
<Product>
<ProductName>Aniseed Syrup</ProductName>
</Product>
<Product>
<ProductName>Chef Anton&apos;s Cajun Seasoning</ProductName>
</Product>
<Product>
<ProductName>Chef Anton&apos;s Gumbo Mix</ProductName>
</Product>
<Product>
<ProductName>Genen Shouyu</ProductName>
</Product>
<Product>
<ProductName>Grandma&apos;s Boysenberry Spread</ProductName>
</Product>
<Product>
<ProductName>Gula Malacca</ProductName>
</Product>
<Product>
<ProductName>Louisiana Fiery Hot Pepper Sauce</ProductName>
</Product>
<Product>
<ProductName>Louisiana Hot Spiced Okra</ProductName>
</Product>
<Product>
<ProductName>Northwoods Cranberry Sauce</ProductName>
</Product>
<Product>
<ProductName>Original Frankfurter grüne Soße</ProductName>
</Product>
<Product>
<ProductName>Sirop d&apos;érable</ProductName>
</Product>
<Product>
<ProductName>Vegie-spread</ProductName>
</Product>
</Category>

(24 row(s) affected)

You can use the XMLDATA option to produce an XML Schema in the output, as shown in Listing 16.16

Listing 16.16—Use the ELEMENTS Option to Show Attributes As Elements

USE Northwind
GO

SELECT CategoryName,
ProductName
FROM Categories as Category
JOIN Products as Product
ON Product.CategoryID = Category.CategoryID
WHERE Product.CategoryID <3
ORDER BY CategoryName, ProductName
FOR XML AUTO, XMLDATA
XML_F52E2B61-18A1-11d1-B105-00805F49916B
----------------------------------------------
<Schema name="Schema2"
xmlns="urn:schemas-microsoft-com:xml-data"
xmlns:dt="urn:schemas-microsoft-com:datatypes">
<ElementType name="Category"
content="eltOnly" model="closed" order="many">
<element type="Product" maxOccurs="*"/>
<AttributeType name="CategoryName" dt:type="string"/>
<attribute type="CategoryName"/>
</ElementType>
<ElementType name="Product"
content="empty" model="closed">
<AttributeType name="ProductName" dt:type="string"/>
<attribute type="ProductName"/>
</ElementType>
</Schema>
<Category xmlns="x-schema:#Schema2" CategoryName="Beverages">
<Product ProductName="Chai"/>
<Product ProductName="Chang"/>
<Product ProductName="Chartreuse verte"/>
<Product ProductName="Côte de Blaye"/>
<Product ProductName="Guaraná Fantástica"/>
<Product ProductName="Ipoh Coffee"/>
<Product ProductName="Lakkalikööri"/>
<Product ProductName="Laughing Lumberjack Lager"/>
<Product ProductName="Outback Lager"/>
<Product ProductName="Rhönbräu Klosterbier"/>
<Product ProductName="Sasquatch Ale"/>
<Product ProductName="Steeleye Stout"/>
</Category>
<Category xmlns="x-schema:#Schema2" CategoryName="Condiments">
<Product ProductName="Aniseed Syrup"/>
<Product ProductName="Chef Anton&apos;s Cajun Seasoning"/>
<Product ProductName="Chef Anton&apos;s Gumbo Mix"/>
<Product ProductName="Genen Shouyu"/>
<Product ProductName="Grandma&apos;s Boysenberry Spread"/>
<Product ProductName="Gula Malacca"/>
<Product ProductName="Louisiana Fiery Hot Pepper Sauce"/>
<Product ProductName="Louisiana Hot Spiced Okra"/>
<Product ProductName="Northwoods Cranberry Sauce"/>
<Product ProductName="Original Frankfurter grüne Soße"/>
<Product ProductName="Sirop d&apos;érable"/>
<Product ProductName="Vegie-spread"/>
</Category>

(24 row(s) affected)

As you can see, the output from Listing 16.16 is the same as the output of the second query from Listing 16.14. The only difference is the schema information at the beginning of the output. You can use this information to create an XML-Data Reduced (XDR) schema file.

Note

Trying to read the output from Listings 16.14 to 16.16 directly in Internet Explorer will produce XML parser errors, unless you add a valid root node and save these outputs in Unicode format from Notepad.

Reading SQL Server XML Data From Active Server Pages

Although this is not an ASP book, it is interesting to show at least one example on how to write a simple Active Server Page (ASP) application to retrieve SQL Server data in XML format.

For a complete understanding of how to create Active Server Pages, you can read the book Active Server Pages 3.0 by Example (Bob Reselman, Que, ISBN 0-7897-2240-2). Working with ASP requires scripting knowledge and some understanding of HTML.

In this section you learn how to write a simple ASP to read the XML document produced from the second query in Listing 16.14.

To write the ASP you can use Notepad or any other text editor. Listing 16.17 contains the complete code for the Active Server Page SQLXML.ASP. For this code to run, you must save this file in a directory managed by Internet Information Server. In this example, you create the directory XML inside the default WWW path (c:\InetPub\wwwroot).

The script contains two main areas:

  • Server-Side Scripting. This section includes the main programming logic. This is where you connect to SQL Server to retrieve the information you need. This code is executed in the server computer (Internet Information Server); this code won't be sent to the client computer at all.

  • Client-Side Scripting. This section shows the results in the place and format you need. This code is executed in the client computer.

Both areas are properly marked in the code with comments.

Listing 16.17—A Simple Active Server Page to Read a SQL Query Using FOR XML AUTO

<%@ LANGUAGE = VBScript %>
<% Option Explicit %>

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html" charset="UTF-8"/>
<TITLE>SQL-XML by Example - SQLXML.asp</TITLE>

<%
 ' THIS IS THE SERVER SIDE SCRIPTING
 ' this part won't be visible from the client side

 ' some constants to make the code more readable
 ' some of these constants are available in the adovbs.inc file

 const adUseClient = 3
 const adWriteChar = 0
 const adWriteLine = 1
 const adExecuteStream = 1024

 ' Create a ADO Connection object

 Dim adoConn
 Set adoConn = Server.CreateObject("ADODB.Connection")

 ' Define the connection string to connect to a valid SQL Server 2000 instance
 ' and the Northwind database. Specify client side processing,
 ' which in this case will be in the IIS server

 ' Note: if your default instance is SQL Server 7, this code will not work
 '       unless you installed XML support for SQL Server 7.0

 Dim sConn
 sConn = "Provider=sqloledb;"
 sConn = sConn & "Data Source=MSSQLFGG\S2K;"
 sConn = sConn & "Initial Catalog=Northwind;"
 sConn = sConn & "User ID=sa"
 adoConn.ConnectionString = sConn
 adoConn.CursorLocation = adUseClient

 ' Open the connection

 adoConn.Open

 ' Create an ADO Command object,
 ' to send the XML query and receive the XML results

 Dim adoCmd
 Set adoCmd = Server.CreateObject("ADODB.Command")
 Set adoCmd.ActiveConnection = adoConn

 ' Let's start the XML request

 Dim sQuery
 sQuery = "<Catalog xmlns:sql='urn:schemas-microsoft-com:xml-sql'>"
 sQuery = sQuery & "<sql:query>"

 ' This is the Query from Listing 16.14

 sQuery = sQuery & "SELECT CategoryName, "
 sQuery = sQuery & "ProductName "
 sQuery = sQuery & "FROM Categories as Category "
 sQuery = sQuery & "JOIN Products as Product "
 sQuery = sQuery & "ON Product.CategoryID = Category.CategoryID "

 ' Note that you must change the symbol < into &lt;
 ' because < is reserved in XML
 ' and in this code the query will be enclosed in a XML stream

 sQuery = sQuery & "WHERE Product.CategoryID &lt; 3 "
 sQuery = sQuery & "ORDER BY CategoryName, ProductName "
 sQuery = sQuery & "FOR XML AUTO"

 ' Now we can finish the XML request

 sQuery = sQuery & "</sql:query></Catalog>"

 ' Create and open the Stream object

 Dim adoStreamQuery
 Set adoStreamQuery = Server.CreateObject("ADODB.Stream")
 adoStreamQuery.Open

 ' Write the XML query into the Stream object

 adoStreamQuery.WriteText sQuery, adWriteChar
 adoStreamQuery.Position = 0

 ' Select the Stream object as the Command to execute
 ' Note the GUID for the Dialect property,
 ' this GUID represents the MSSQLXML format

 adoCmd.CommandStream = adoStreamQuery
 adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"

 ' Now we will select to send the output to the Response object
 ' which is a Stream object too

 adoCmd.Properties("Output Stream") = Response

 ' We define the XML output as a Data Isle called CatalogIsle
 ' to be used from the client side execution

 Response.write "<XML ID=CatalogIsle>"
 adoCmd.Execute , , adExecuteStream
 Response.write "</XML>"
%>

<SCRIPT language="VBScript" For="window" Event="onload">	

 ' This is the client side scripting,
 ' and it will be viusible from the client browser

 Dim xmlDoc
 dim OutputXML

 ' Get a reference to the data island containing
 ' the XML results

 Set xmlDoc = CatalogIsle.XMLDocument

 Dim root, CChild, PChild

 ' Get a reference to the root node of the XML document

 Set root = xmlDoc.documentElement

 ' Navigate through the first level of the three
 ' retrieving every category
 ' we display the CategoryName attribute in bold typeface

 For each CChild in root.childNodes
   OutputXML = document.all("log").innerHTML
   document.all("log").innerHTML = OutputXML & "<LI><B>" &
CChild.getAttribute("CategoryName") & "</B></LI>"

   ' For every category,
   ' navigate through the next level of the three
   ' retrieving every product that belongs to the category
   ' we display the ProductName attribute in normal typeface

   For each PChild in CChild.childNodes
     OutputXML = document.all("log").innerHTML
     document.all("log").innerHTML = OutputXML & "<UL>" &
PChild.getAttribute("ProductName") & "</UL>"
   Next
 Next
</SCRIPT>
</HEAD>
<BODY>
 <H1>SQL-XML by Example</H1>
 <H3>This is the Product Catalog for categories 1 and 2</H3>
 <UL id=log>
 </UL>
</BODY>
</HTML>

Looking at Listing 16.17, you can see the following line at the beginning of the file:

<META HTTP-EQUIV="Content-Type" content="text/html" charset="UTF-8"/>

It is important to specify UTF-8 (Unicode) as the character set, because the data to show in this case contains characters not available in the standard character set.

The process of this ASP is as follows:

  1. Create a Connection object, called adoConn in this example, and connect it to SQL Server.

  2. Create a Stream Object, called adoStreamQuery in this example, to define the XML query to be sent to SQL Server.

  3. Create a Command object, called adoCmd in this example, to send the query to SQL Server, defined by the Stream object, and send the results directly to the Response object.

  4. Execute the Command object, including the results in a Data Island called Catalog. In this way, the client-side scripting can easily access this data.

The client-side scripting only has a double loop to navigate through the categories and every product for each category.

You can see throughout the code many comments describing the purpose of every statement.

Opening this file with Internet Explorer (through the URL http://localhost/XML/SQLXML.ASP), you can see the same output as in Figure 16.8.

Figure 16.8 SQLXML.ASP running in Internet Information Server to retrieve SQL Server data.

Now take a look at what the user could see when searching for client-side scripting. In Internet Explorer, go to the View menu and select Source. Notepad opens to show the source code for this page, as shown in Listing 16.18. As you can see in Listing 16.18, your server-side scripting is hidden from the client, including the connection string and the SQL query to retrieve the data.

Note in Listing 16.18 that the first part includes the data island containing the query results in XML format. Code comments have been automatically removed as well from the final HTML document.

Listing 16.18—This Is the Source Code of the HTML Page Returned to the Client

<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" content="text/html" charset="UTF-8"/>
<TITLE>SQL-XML by Example - SQLXML.asp</TITLE>

<XML ID=CatalogIsle>
<Catalog xmlns:sql="urn:schemas-microsoft-com:xml-sql">
<Category CategoryName="Beverages">
<Product ProductName="Chai"/>
<Product ProductName="Chang"/>
<Product ProductName="Chartreuse verte"/>
<Product ProductName="Côte de Blaye"/>
<Product ProductName="Guaraná Fantástica"/>
<Product ProductName="Ipoh Coffee"/>
<Product ProductName="Lakkalikööri"/>
<Product ProductName="Laughing Lumberjack Lager"/>
<Product ProductName="Outback Lager"/>
<Product ProductName="Rhönbräu Klosterbier"/>
<Product ProductName="Sasquatch Ale"/>
<Product ProductName="Steeleye Stout"/>
</Category>
<Category CategoryName="Condiments">
<Product ProductName="Aniseed Syrup"/>
<Product ProductName="Chef Anton&apos;s Cajun Seasoning"/>
<Product ProductName="Chef Anton&apos;s Gumbo Mix"/>
<Product ProductName="Genen Shouyu"/>
<Product ProductName="Grandma&apos;s Boysenberry Spread"/>
<Product ProductName="Gula Malacca"/>
<Product ProductName="Louisiana Fiery Hot Pepper Sauce"/>
<Product ProductName="Louisiana Hot Spiced Okra"/>
<Product ProductName="Northwoods Cranberry Sauce"/>
<Product ProductName="Original Frankfurter grüne Soße"/>
<Product ProductName="Sirop d&apos;érable"/>
<Product ProductName="Vegie-spread"/>
</Category>
</Catalog>
</XML>

<SCRIPT language="VBScript" For="window" Event="onload">

 Dim xmlDoc
 dim OutputXML
 Set xmlDoc = CatalogIsle.XMLDocument

 Dim root, CChild, PChild
 Set root = xmlDoc.documentElement

 For each CChild in root.childNodes
   OutputXML = document.all("log").innerHTML
   document.all("log").innerHTML = OutputXML & "<LI><B>" &
CChild.getAttribute("CategoryName") & "</B></LI>"

   For each PChild in CChild.childNodes
     OutputXML = document.all("log").innerHTML
     document.all("log").innerHTML = OutputXML & "<UL>" &
PChild.getAttribute("ProductName") & "</UL>"
   Next
 Next
</SCRIPT>
</HEAD>
<BODY>
 <H1>SQL-XML by Example</H1>
 <H3>This is the Product Catalog for categories 1 and 2</H3>
 <UL id=log>
 </UL>
</BODY>
</HTML>

Now you can use the example in Listing 16.17 as a template to display your own queries.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020