SQL Server 2000
With the advent of XML and the increasing requirements for distributed
applications in today’s marketplace, a larger demand has been placed on the
developer to provide messaging and data in an XML format. Providing data in
XML format, until now, has con-sisted of querying data in the form of a cursor
or ADO record set and using a conversion routine to convert the data into XML
format. Now with the new features in SQL Server 2000, this task can be
accomplished with minimal effort, which allows the developer to concentrate on
the more important task of writing the business logic.
SQL Server 2000 allows the developer to query SQL Server data and
receive that data in XML format through the use of a special clause: FOR XML. This clause provides three
dif-ferent options by which SQL Server can return data in XML format: AUTO, RAW, and
EXPLICIT.
Issuing the SQL SELECT command with FOR XML AUTO will return the result set in XML format, with each record having a
node whose tag name is the same as the table name on which the query was
performed. Each node will have attributes equal to the field names specified in
the query with values equal to the values of the fields within the table. Using
the FOR XML RAW clause
will return XML in which each record is represented by a node whose tag name is
“row” and whose attributes are the fields from the query. The last option, FOR XML EXPLICIT, uses queries written in a
specific format to return the XML in a specific format. However, these options
are only available from within the SQL Server Query Analyzer or by accessing
SQL server through a URL.
In this chapter, we will be using Web Release 2 for SQL Server 2000.
Configuring IIS
Before you can utilize the new XML support within SQL Server 2000, you
must first configure it. Simply click Start, Programs, Microsoft SQL Server XML
Tools, Configure IIS Support—Web Release 2. This will launch the configuration
utility necessary to pro-vide XML support within SQL Server 2000, as shown in
Figure 18.1.
Once you have the IIS Virtual Directory Management for SQL Server page
open, drill down in the tree on the left side of the screen until you get to
the Default Web Site node or the Web site from which you wish to access SQL
Server 2000. On the right side of the screen, right-click and select New,
Virtual Directory. This will bring up the New Virtual Directory Properties
dialog box, where you enter information regarding how SQL Server 2000 should be
configured to run when accessed from a URL, as shown in Figure 18.2.
On the “General” page, you will be required to give
the new virtual directory a name and provide the physical path on the hard
drive associated with this virtual directory. This first page determines how
you may access SQL Server via HTTP. For instance, in the case of Default Web
Site, if you enter a virtual directory name of SQL2000, you could access it via
HTTP as http://localhost/sql2000.
The “Security” page, shown in Figure 18.3, is where
you indicate how you wish to log in to SQL Server 2000.
The “Data Source” page, shown in Figure 18.4,
allows you to specify the SQL Server installation to use and the database name
to access.
The “Settings” page, shown in Figure 18.5, allows you to indicate the
different types of queries that can be run: URL queries, template queries,
and/or XPath queries, as well as whether HTTP POSTs are allowed.
The “Virtual Names” page allows you to map various special virtual
directories to your main SQL Server virtual directory. If you want to execute
template queries, you’ll need to at least create a template virtual directory
here. If you want to use XPath queries, you’ll need to create a schema virtual
directory as well. Figure 18.6 shows you the “Virtual Names” page of the dialog
box, whereas Figure 18.7 shows you the Virtual Name Configuration dialog box.
There’s one “Advanced” page on the dialog box for advanced configuration
options. This page allows you to specify the SQL ISAPI DLL to use for the
virtual directory as well as whether various items in memory, such as
templates, schemas, and XSLT style sheets, should be cached. Figure 18.8 shows
this final page.
Once you’ve configured IIS to support XML for SQL Server 2000, you can
begin access-ing your new virtual directory via HTTP in the form of URL
queries, template queries, and XPath queries.
URL Queries
The easiest way in which to test or become familiar with URL queries in
SQL Server is to open Microsoft’s Internet Explorer and enter queries into the
address space available. It is important to keep in mind that the XML string
returned by SQL Server 2000 is not well-formed XML; rather, it is an XML
fragment. This is because there is no single root node from which all other
nodes are children. However, a parameter can be passed along with the query
itself to specify the root node, which will eliminate this problem by wrap-ping
the returned XML string with the node specified.
For instance, the query
SELECT * FROM
Customers
as a URL query looks like this:
http://localhost/sql2000?sql=Select+*+From+Customers+Where+ ➥ CustomerID+Like+’A%25’+For+XML+Auto&Root=Results
The preceding URL query returns all the records in the Customers table
that have a CustomerID that begins with the letter A, wrapped with a root node called Results, as shown in Listing
18.1.
LISTING 18.1 The
Output Returned from SQL Server 2000 for All Customers with a CustomerID beginning with A
<?xml version=”1.0”?>
<Results>
<Customers
CustomerID=”ALFKI”
CompanyName=”Alfreds
➥ Futterkiste” ContactName=”Maria Anders” ContactTitle=
➥ ”Sales Representative” Address=”Obere Str. 57” City=
➥ ”Test” PostalCode=”12209” Country=”Germany” Phone=
➥ ”030-0074321”
Fax=”030-0076545”/>
<Customers
CustomerID=”ANATR”
CompanyName=”Ana Trujillo
➥ Emparedados y helados”
ContactName=”Ana Trujillo”
➥ ContactTitle=”Owner” Address=”Avda. de la Constitución
➥ 2222” City=”México D.F.” PostalCode=”05021” Country=
➥ ”Mexico” Phone=”(5) 555-4729” Fax=”(5) 555-3745”/>
<Customers CustomerID=”ANTON”
CompanyName=”Antonio Moreno
➥ Taquería” ContactName=”Antonio Moreno” ContactTitle=
➥ ”Owner” Address=”Mataderos 2312”
City=”México D.F.”
➥ PostalCode=”05023”
Country=”Mexico” Phone=”(5) 555-3932”/>
<Customers
CustomerID=”AROUT” CompanyName=”Around the
Horn”
➥ ContactName=”Thomas Hardy” ContactTitle=”Sales
➥ Representative” Address=”120 Hanover Sq.” City=”London”
➥ PostalCode=”WA1 1DP” Country=”UK” Phone=”(171) 555-7788”
➥ Fax=”(171) 555-6750”/>
</Results>
In this example, each record is represented by a node called Customers
whose attributes are the fields within the Customers table. The URL query used
to return these results uses the For XML
Auto clause. The Auto portion indicates to SQL ISAPI that it should produce an XML string with
the specified table as the main element and that it should include the fields
as attributes.
The For XML Raw clause will produce a slightly different XML grammar from the one
created by For XML Auto.
For instance, the following URL query returns all records in the
Customers table that have a CustomerID that begins with the letter A, wrapped in a root node called
Results:
http://localhost/sql2000?sql=Select+*+From+Customers+Where+ ➥ CustomerID+Like+’A%25’+For+XML+Raw&Root=Results
The main difference here is that every record is represented by a tag
named “row,” as shown in Listing 18.2.
LISTING 18.2 Results
Returned from SQL Server 2000 for All Customers with a CustomerID beginning with A
Using the For XML Raw Clause
<?xml version=”1.0”?>
<Results>
<row
CustomerID=”ALFKI”
CompanyName=”Alfreds Futterkiste”
➥ ContactName=”Maria Anders” ContactTitle=”Sales
➥ Representative”
Address=”Obere Str. 57”
City=”Test”
➥ PostalCode=”12209” Country=”Germany” Phone=”030-0074321”
➥ Fax=”030-0076545”/>
<row
CustomerID=”ANATR”
CompanyName=”Ana Trujillo Emparedados
➥ y helados” ContactName=”Ana Trujillo” ContactTitle=
➥ ”Owner” Address=”Avda. de la Constitución 2222”
➥ City=”México D.F.” PostalCode=”05021” Country=”Mexico”
➥ Phone=”(5) 555-4729” Fax=”(5) 555-3745”/>
<row
CustomerID=”ANTON”
CompanyName=”Antonio Moreno Taquería”
➥ ContactName=”Antonio
Moreno” ContactTitle=”Owner”
➥ Address=”Mataderos 2312” City=”México D.F.” PostalCode=
➥ ”05023” Country=”Mexico” Phone=”(5) 555-3932”/>
<row CustomerID=”AROUT” CompanyName=”Around the
Horn”
➥ ContactName=”Thomas Hardy” ContactTitle=”Sales
➥ Representative” Address=”120 Hanover Sq.” City=”London” ➥ PostalCode=”WA1 1DP” Country=”UK” Phone=”(171) 555-7788” ➥ Fax=”(171) 555-6750”/>
</Results>
Both versions of the returned XML appear very similar to the way in
which ADO stores and loads record sets in XML format. However, this may not
always coincide with the grammar of XML that is expected within an application.
For this reason, another parame-ter, xsl, can be included with the URL to specify an XSLT style sheet to use to
trans-form the native XML grammar given by SQL Server 2000 into the expected
grammar. Let’s look at the following example of an XSLT style sheet called Customers1.xsl, which, in this case, resides in
the root of the virtual directory SQL2000, as shown in Listing 18.3.
LISTING 18.3 Customers1.xsl Contains
an XSLT Transformation for Use with Results
Returned from SQL Server 2000
<?xml version=”1.0”?>
<xsl:stylesheet
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
➥ version=”1.0”> <xsl:template
match=”/”>
<CUSTOMERS>
<xsl:for-each
select=”results/customers”>
<CUSTOMER>
<CUSTOMERID><xsl:value-of
select=”@CustomerID”/></CUSTOMERID> <COMPANY><xsl:value-of
select=”@CompanyName”/></COMPANY> <CONTACT><xsl:value-of
select=”@ContactName”/></CONTACT> <ADDRESS><xsl:value-of
select=”@Address”/></ADDRESS> <CITY><xsl:value-of
select=”@City”/></CITY> <PHONE><xsl:value-of
select=”@Phone”/></PHONE>
</CUSTOMER>
</xsl:for-each> </CUSTOMERS>
</xsl:template>
</xsl:stylesheet>
As an example, the URL query
http://localhost/sql2000?sql=Select+*+From+Customers+Where+
➥ +CustomerID+Like+’A%25’+For+XML+Auto&Root=Results&xsl= ➥ Customers1.xsl
produces the results shown in Listing 18.4.
LISTING 18.4 Results
Returned from SQL Server 2000 Using the Customers1.xsl Style Sheet to Transform the Native Results
<?xml version=”1.0”?>
<CUSTOMERS>
<CUSTOMER>
<CUSTOMERID>ALFKI</CUSTOMERID>
<COMPANY>Alfreds Futterkiste</COMPANY> <CONTACT>Maria
Anders</CONTACT> <ADDRESS>Obere Str. 57</ADDRESS>
<CITY>Test</CITY> <PHONE>030-0074321</PHONE>
</CUSTOMER>
<CUSTOMER>
<CUSTOMERID>ANATR</CUSTOMERID>
<COMPANY>Ana Trujillo Emparedados y
helados</COMPANY> <CONTACT>Ana Trujillo</CONTACT>
<ADDRESS>Avda. de la Constitución
2222</ADDRESS> <CITY>México D.F.</CITY>
<PHONE>(5)
555-4729</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>ANTON</CUSTOMERID>
<COMPANY>Antonio Moreno Taquería</COMPANY> <CONTACT>Antonio
Moreno</CONTACT> <ADDRESS>Mataderos 2312</ADDRESS>
<CITY>México D.F.</CITY>
<PHONE>(5)
555-3932</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>AROUT</CUSTOMERID>
<COMPANY>Around the Horn</COMPANY> <CONTACT>Thomas
Hardy</CONTACT> <ADDRESS>120 Hanover Sq.</ADDRESS>
<CITY>London</CITY>
<PHONE>(171)
555-7788</PHONE> </CUSTOMER>
</CUSTOMERS>
In this case, our query is executed first, and then the XSLT style sheet
is applied to per-form the transformation.
Knowing that an XSLT style sheet can be applied to the result set, using
another parame-ter (contenttype) will return the output in HTML format. Using the style sheet in Listing
18.5, coupled with the contenttype parameter, indicates that the resulting XML grammar should be
interpreted as HTML.
LISTING 18.5 Customers2.xsl Contains
an XSLT Transformation to Convert the Results
into an HTML Table
<?xml version=”1.0”?>
<xsl:stylesheet
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”
➥ version=”1.0”>
<xsl:template match=”/”>
<TABLE width=”100%”>
<TR
bgcolor=”moccasin”>
<TD valign=”top”><b>Customer
Id</b></TD> <TD
valign=”top”><b>Company</b></TD>
<TD valign=”top”><b>Contact</b></TD>
<TD valign=”top”><b>Address</b></TD> <TD
valign=”top”><b>City</b></TD> <TD
valign=”top”><b>Phone</b></TD>
</TR>
<xsl:for-each
select=”Results/Customers”>
<TR
bgcolor=”white”>
<TD valign=”top”><xsl:value-of
select=”@CustomerID”/></TD> <TD valign=”top”><xsl:value-of
select=”@CompanyName”/></TD> <TD valign=”top”><xsl:value-of
select=”@ContactName”/></TD> <TD valign=”top”><xsl:value-of
select=”@Address”/></TD>
<TD valign=”top”><xsl:value-of
select=”@City”/></TD> <TD valign=”top”><xsl:value-of
select=”@Phone”/></TD>
</TR>
</xsl:for-each>
</TABLE>
</xsl:template>
</xsl:stylesheet>
Because we’ve specified that the content type should be text/HTML, a
browser will be sure to interpret the resulting XML as HTML and display the
results appropriately. In our case, by specifying the URL query
http://localhost/sql2000?sql=Select+*+From+Customers+Where+
➥ +CustomerID+Like+’A%25’+For+XML+Auto&Root=Results&xsl=
➥ Customers2.xsl&ContentType=text.html
we get the result set in Listing 18.6.
LISTING 18.6 The
Results from Applying the Customers2.xsl Style Sheet to the Results Returned from SQL Server 2000
<?xml version=”1.0”?>
<TABLE width=”100%”>
<TR
bgcolor=”moccasin”>
<TD valign=”top”><b>Customer
Id</b></TD> <TD
valign=”top”><b>Company</b></TD>
<TD
valign=”top”><b>Contact</b></TD> <TD
valign=”top”><b>Address</b></TD> <TD
valign=”top”><b>City</b></TD> <TD
valign=”top”><b>Phone</b></TD>
</TR>
<TR
bgcolor=”white”>
<TD
valign=”top”>ALFKI</TD>
<TD valign=”top”>Alfreds
Futterkiste</TD> <TD valign=”top”>Maria Anders</TD>
<TD valign=”top”>Obere Str. 57</TD>
<TD valign=”top”>Test</TD>
<TD valign=”top”>030-0074321</TD>
</TR>
<TR
bgcolor=”white”>
<TD
valign=”top”>ANATR</TD>
<TD valign=”top”>Ana Trujillo Emparedados y
helados</TD> <TD valign=”top”>Ana Trujillo</TD>
<TD valign=”top”>Avda. de la Constitución
2222</TD> <TD valign=”top”>México D.F.</TD>
<TD valign=”top”>(5)
555-4729</TD> </TR>
<TR
bgcolor=”white”>
<TD
valign=”top”>ANTON</TD>
<TD valign=”top”>Antonio Moreno
Taquería</TD> <TD valign=”top”>Antonio Moreno</TD>
<TD valign=”top”>Mataderos 2312</TD>
<TD valign=”top”>México D.F.</TD>
<TD valign=”top”>(5)
555-3932</TD> </TR>
<TR
bgcolor=”white”>
<TD
valign=”top”>AROUT</TD>
<TD valign=”top”>Around the Horn</TD> <TD
valign=”top”>Thomas Hardy</TD>
<TD valign=”top”>120 Hanover Sq.</TD>
<TD valign=”top”>London</TD>
<TD valign=”top”>(171) 555-7788</TD>
</TR>
</TABLE>
It is up to the individual browser to figure out how to display the
resulting HTML. Also, some browsers, such as Internet Explorer version 6.0,
will automatically interpret the resulting XML as HTML and display it
appropriately even without the contenttype parameter being explicitly specified.
Template Queries
Another method of retrieving XML result sets from SQL Server 2000 is to
template queries. These are XML files that tell SQL Server how to run queries,
what the root node will be, what XSLT style sheet to apply, and so on. These
files eliminate the need to specify a SELECT statement at the URL level.
In this case, our query (Select *
From Customers), written as a template query,
would appear as shown in Listing 18.7.
LISTING 18.7 Customers1.xml Contains
a Template Query to Return All Customers
from SQL Server 2000 Whose CustomerID Begins with A
<Results
xmlns:sql=”urn:schemas-microsoft-com:xml-sql”> <sql:query>
Select * From Customers Where
CustomerID Like ‘A%’ For XML Auto </sql:query>
</Results>
Also, it returns the result set shown in Listing 18.8.
LISTING 18.8 The
Results Returned from Navigating to the Customers1.xml Template Query
<?xml version=”1.0”?>
<Results>
<Customers
CustomerID=”ALFKI” CompanyName=”Alfreds
➥ Futterkiste” ContactName=”Maria Anders” ContactTitle=
➥ ”Sales Representative” Address=”Obere Str. 57” City=
➥ ”Test” PostalCode=”12209” Country=”Germany” Phone=
➥ ”030-0074321”
Fax=”030-0076545”/>
<Customers
CustomerID=”ANATR” CompanyName=”Ana Trujillo
➥ Emparedados y helados”
ContactName=”Ana Trujillo”
➥ ContactTitle=”Owner” Address=”Avda. de la Constitución ➥ 2222” City=”México D.F.” PostalCode=”05021” Country= ➥ ”Mexico” Phone=”(5) 555-4729” Fax=”(5) 555-3745”/>
<Customers CustomerID=”ANTON”
CompanyName=”Antonio Moreno ➥ Taquería” ContactName=”Antonio
Moreno” ContactTitle=
➥ ”Owner” Address=”Mataderos 2312”
City=”México D.F.”
➥ PostalCode=”05023”
Country=”Mexico” Phone=”(5) 555-3932”/> <Customers CustomerID=”AROUT”
CompanyName=”Around the Horn”
➥ ContactName=”Thomas Hardy” ContactTitle=”Sales
➥ Representative” Address=”120 Hanover Sq.” City=”London” ➥ PostalCode=”WA1 1DP” Country=”UK” Phone=”(171) 555-7788” ➥ Fax=”(171) 555-6750”/>
</Results>
To run this query, save the template as Customers1.xml and store it in the template vir-tual directory beneath the main SQL
Server 2000 virtual directory. Then, simply navigate to http://localhost/sql2000/template/customers1.xml, which returns the XML in the native SQL Server format.
Now let’s replace the keyword AUTO with RAW in our
template query, as shown in Listing 18.9.
LISTING 18.9 Customers2.xml Contains the Revised Query
<Results
xmlns:sql=”urn:schemas-microsoft-com:xml-sql”> <sql:query>
Select * From Customers Where
CustomerID Like ‘A%’ For XML Raw </sql:query>
</Results>
Here’s the result:
<?xml version=”1.0”?>
<Results>
<row
CustomerID=”ALFKI”
CompanyName=”Alfreds Futterkiste”
➥ ContactName=”Maria Anders” ContactTitle=”Sales
➥ Representative”
Address=”Obere Str. 57”
City=”Test”
➥ PostalCode=”12209” Country=”Germany” Phone=”030-0074321” ➥ Fax=”030-0076545”/>
<row
CustomerID=”ANATR”
CompanyName=”Ana Trujillo Emparedados
➥ y helados” ContactName=”Ana Trujillo” ContactTitle= ➥ ”Owner” Address=”Avda. de la Constitución 2222”
➥ City=”México D.F.” PostalCode=”05021” Country=”Mexico” ➥ Phone=”(5) 555-4729” Fax=”(5) 555-3745”/>
<row
CustomerID=”ANTON”
CompanyName=”Antonio Moreno Taquería”
➥ ContactName=”Antonio
Moreno” ContactTitle=”Owner”
➥ Address=”Mataderos 2312” City=”México D.F.” PostalCode= ➥ ”05023” Country=”Mexico” Phone=”(5) 555-3932”/>
<row
CustomerID=”AROUT”
CompanyName=”Around the Horn”
➥ ContactName=”Thomas Hardy” ContactTitle=”Sales
➥ Representative” Address=”120 Hanover Sq.” City=”London” ➥ PostalCode=”WA1 1DP” Country=”UK” Phone=”(171) 555-7788” ➥ Fax=”(171) 555-6750”/>
</Results>
To apply a style sheet to the result set, the template query would
appear as shown in Listing 18.10.
LISTING 18.10 Customers3.xml Contains
the Query to Execute and the Location of
Style Sheet to Use to Transform the Results
<Results
xmlns:sql=”urn:schemas-microsoft-com:xml-sql”
➥ sql:xsl=’../Customers1.xsl’>
<sql:query>
Select
* From Customers
Where CustomerID Like
‘A%’ For XML
Auto
</sql:query>
</Results>
This returns the results shown in Listing 18.11.
LISTING 18.11 The Results from Navigating
to the Customers3.xml Template QUERY
<?xml version=”1.0”?>
<CUSTOMERS>
<CUSTOMER>
<CUSTOMERID>ALFKI</CUSTOMERID>
<COMPANY>Alfreds Futterkiste</COMPANY> <CONTACT>Maria
Anders</CONTACT> <ADDRESS>Obere Str. 57</ADDRESS>
<CITY>Test</CITY> <PHONE>030-0074321</PHONE>
</CUSTOMER>
<CUSTOMER>
<CUSTOMERID>ANATR</CUSTOMERID>
<COMPANY>Ana Trujillo Emparedados y
helados</COMPANY> <CONTACT>Ana Trujillo</CONTACT>
<ADDRESS>Avda. de la Constitución
2222</ADDRESS> <CITY>México D.F.</CITY>
<PHONE>(5)
555-4729</PHONE>
</CUSTOMER>
<CUSTOMER>
<CUSTOMERID>ANTON</CUSTOMERID>
<COMPANY>Antonio Moreno Taquería</COMPANY> <CONTACT>Antonio
Moreno</CONTACT> <ADDRESS>Mataderos 2312</ADDRESS>
<CITY>México D.F.</CITY>
<PHONE>(5)
555-3932</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>AROUT</CUSTOMERID>
<COMPANY>Around the Horn</COMPANY> <CONTACT>Thomas
Hardy</CONTACT> <ADDRESS>120 Hanover Sq.</ADDRESS>
<CITY>London</CITY>
<PHONE>(171)
555-7788</PHONE> </CUSTOMER>
</CUSTOMERS>
As is the case with URL queries, you can format the final results to be
displayed in HTML. In this case, simply change Customers1.xsl to Customers2.xsl. The result is the HTML table created earlier, as shown in Listing
18.12.
LISTING 18.12 The Results from Using the Customers2.xsl Style Sheet Instead in the
Customers3.xml Template Query
<?xml version=”1.0”?>
<TABLE width=”100%”>
<TR bgcolor=”moccasin”>
<TD valign=”top”><b>Customer Id</b></TD>
<TD valign=”top”><b>Company</b></TD>
<TD valign=”top”><b>Contact</b></TD>
<TD valign=”top”><b>Address</b></TD>
<TD valign=”top”><b>City</b></TD>
<TD valign=”top”><b>Phone</b></TD>
</TR>
<TR bgcolor=”white”>
<TD valign=”top”>ALFKI</TD>
<TD valign=”top”>Alfreds Futterkiste</TD>
<TD valign=”top”>Maria Anders</TD>
<TD valign=”top”>Obere Str.
57</TD>
<TD valign=”top”>Test</TD>
<TD valign=”top”>030-0074321</TD>
</TR>
<TR bgcolor=”white”>
<TD valign=”top”>ANATR</TD>
<TD valign=”top”>Ana Trujillo Emparedados y
helados</TD> <TD valign=”top”>Ana Trujillo</TD>
<TD valign=”top”>Avda. de la Constitución
2222</TD> <TD valign=”top”>México D.F.</TD>
<TD valign=”top”>(5)
555-4729</TD> </TR>
<TR
bgcolor=”white”>
<TD
valign=”top”>ANTON</TD>
<TD valign=”top”>Antonio Moreno
Taquería</TD> <TD valign=”top”>Antonio Moreno</TD>
<TD valign=”top”>Mataderos 2312</TD>
<TD valign=”top”>México D.F.</TD>
<TD valign=”top”>(5)
555-3932</TD> </TR>
<TR
bgcolor=”white”>
<TD
valign=”top”>AROUT</TD>
<TD valign=”top”>Around the Horn</TD>
<TD valign=”top”>Thomas Hardy</TD> <TD valign=”top”>120
Hanover Sq.</TD> <TD valign=”top”>London</TD>
<TD valign=”top”>(171)
555-7788</TD> </TR>
</TABLE>
Template queries can also accept parameters to help
filter the result set. Specifying that we only want the customers whose
CustomerID begins with the letter A
is kind of short sighted. It would make a lot more sense to allow the value of
the CustomerID to vary.
Therefore, the template file could be rewritten as
shown in Listing 18.13.
LISTING 18.13 Customers4.xml
Contains a
Parameterized Template QUERY
<Results
xmlns:sql=”urn:schemas-microsoft-com:xml-sql” > <sql:header>
<sql:param
name=’CustomerId’>%</sql:param> </sql:header>
<sql:query>
Select * From Customers Where
CustomerID Like @CustomerId For XML Auto </sql:query>
</Results>
In this example, we specify that the template query
will accept one parameter, CustomerId, and that this parameter has a default value of %, which, in conjunction with the query, will return all records
from the Customers table. To execute this query, we just provide the following
URL:
http://localhost/sql2000/template/customers.xml?CustomerId=A%25
Now we can return any number of records from the Customers table. For
instance, if we supply the URL
http://localhost/sql2000/template/customers.xml?CustomerId=B%25
we’d get the result set shown in Listing 18.14.
LISTING 18.14 The Results from Navigating
to the Customers4.xml Template Query
<Results
xmlns:sql=”urn:schemas-microsoft-com:xml-sql”>
<Customers
CustomerID=”BERGS”
CompanyName=”Berglunds snabbköp”
➥ ContactName=”Christina
Berglund” ContactTitle=
➥ ”Order Administrator” Address=”Berguvsvägen 8” City= ➥ ”Luleå” PostalCode=”S-958 22” Country=”Sweden” Phone= ➥ ”0921-12 34 65” Fax=”0921-12 34 67”/>
<Customers
CustomerID=”BLAUS”
CompanyName=”Blauer See
➥ Delikatessen” ContactName=”Hanna Moos” ContactTitle= ➥ ”Sales Representative” Address=”Forsterstr. 57” City= ➥ ”Mannheim” PostalCode=”68306” Country=”Germany” Phone= ➥ ”0621-08460” Fax=”0621-08924”/>
<Customers
CustomerID=”BLONP”
CompanyName=”Blondesddsl père
➥ et fils” ContactName=”Frédérique Citeaux” ContactTitle= ➥ ”Marketing Manager” Address=”24, place Kléber” City=
➥ ”Strasbourg” PostalCode=”67000” Country=”France” Phone= ➥ ”88.60.15.31” Fax=”88.60.15.32”/>
<Customers
CustomerID=”BOLID”
CompanyName=”Bólido Comidas
➥ preparadas” ContactName=”Martín Sommer” ContactTitle= ➥ ”Owner” Address=”C/ Araquil, 67” City=”Madrid”
➥ PostalCode=”28023” Country=”Spain” Phone= ➥ ”(91) 555 22 82” Fax=”(91) 555 91 99”/>
<Customers
CustomerID=”BONAP”
CompanyName=”Bon app’” ContactName=
➥ ”Laurence Lebihan” ContactTitle=”Owner” Address=
➥ ”12, rue des Bouchers” City=”Marseille” PostalCode= ➥ ”13008” Country=”France” Phone=”91.24.45.40” Fax= ➥ ”91.24.45.41”/>
<Customers
CustomerID=”BOTTM”
CompanyName=”Bottom-Dollar
➥ Markets” ContactName=”Elizabeth Lincoln” ContactTitle= ➥ ”Accounting Manager” Address=”23 Tsawassen Blvd.” City= ➥ ”Tsawassen” Region=”BC” PostalCode=”T2F 8M4” Country= ➥ ”Canada” Phone=”(604) 555-4729” Fax=”(604) 555-3745”/>
<Customers CustomerID=”BSBEV” CompanyName=”B’s
Beverages” ➥ ContactName=”Victoria Ashworth”
ContactTitle=”Sales
➥ Representative” Address=”Fauntleroy Circus” City= ➥ ”London” PostalCode=”EC2 5NT” Country=”UK” Phone= ➥ ”(171) 555-1212”/>
</Results>
XPath Queries
Previously, when SQL Server 2000 initially shipped at the beginning of
2001, support had not been included for annotated XSD schemas. Therefore,
everyone was forced to create annotated XDR schemas. However, with Web Release
2 for SQL Server 2000, support for creating annotated XSD schemas has been
added. Although annotated XDR schemas are still supported for backward
compatibility, the XDR schemas will most likely be phased out in favor of the
XSD schemas.
Two basic attributes and one basic element are needed to author
annotated XSD schemas. The attributes needed are sql:field and sql:relation. The element is sql:relation-ship. The sql:relation attribute is used to map an element to a table. This has the effect of creating one XML
element for every record in the table. The sql:field attribute is used to map a particular attribute or node value to a
field from the related table. The sql:relationship element is used to relate elements within the XML docu-ment to other
elements. It defines the two tables and the join condition necessary to relate
them together.
Using those attributes and elements, an annotated XSD schema can be
authored to return data from SQL Server 2000 in a specific format. The only
required attribute is sql:relation. This attribute refers to a table or view in the database and can be
placed on an
element in the XSD schema. The schema shown in Listing 18.15 is a simple
exam-ple of using an sql:relation attribute in an annotated XSD schema for the Customers table in the
Northwind database.
LISTING 18.15 Customers1.xsd Contains
an Annotated XSD Schema for Customers Within
the Northwind Database
<?xml version=”1.0” encoding=”UTF-8”?>
<xsd:schema
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
➥
xmlns:sql=”urn:schemas-microsoft-com:mapping-schema”> <xsd:element
name=”CUSTOMER” sql:relation=”Customers”>
<xsd:complexType>
<xsd:attribute name=”CustomerID”
type=”xsd:string”/> <xsd:attribute name=”CompanyName”
type=”xsd:string”/> <xsd:attribute name=”ContactName”
type=”xsd:string”/> <xsd:attribute name=”Address” type=”xsd:string”/>
<xsd:attribute name=”City” type=”xsd:string”/> <xsd:attribute
name=”Phone” type=”xsd:string”/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Because the sql:relation attribute is specified on an xsd:element element within our schema, the relation is inherited by all elements
and attributes contained within the ele-ment declaration. This means we do not
need to specify the sql:relation attribute on every <element> or <attribute> element within our schema. Because we defined our attribute names
exactly how they exist in the Northwind database, we don’t need to use the sql:field attribute. Keep in mind that XML
is case sensitive. Therefore, the attribute names defined earlier must match
exactly with the field names defined in the database for this XSD schema to
work. This schema, when used for an XPath query for all customers within the
City of London, returns an XML document whose structure matches that of the one
defined in the schema, as shown here:
<?xml version=”1.0”?>
<Results>
<CUSTOMER
City=”London”
CompanyName=”Around the Horn”
➥ CustomerID=”AROUT”
Address=”120 Hanover Sq.”
➥ ContactName=”Thomas Hardy”
Phone=”(171) 555-7788”/> <CUSTOMER City=”London” CompanyName=”B’s
Beverages”
➥ CustomerID=”BSBEV”
Address=”Fauntleroy Circus”
➥ ContactName=”Victoria Ashworth”
Phone=”(171) 555-1212”/> <CUSTOMER City=”London”
CompanyName=”Consolidated Holdings”
➥ CustomerID=”CONSH” Address=”Berkeley Gardens 12 Brewery” ➥ ContactName=”Elizabeth Brown” Phone=”(171) 555-2282”/>
<CUSTOMER City=”London” CompanyName=”Eastern
Connection” ➥ CustomerID=”EASTC” Address=”35
King George” ContactName= ➥ ”Ann Devon” Phone=”(171)
555-0297”/>
<CUSTOMER
City=”London” CompanyName=”North/South” CustomerID=
➥ ”NORTS” Address=”South House
300 Queensbridge”
➥ ContactName=”Simon Crowther”
Phone=”(171) 555-7733”/> <CUSTOMER City=”London” CompanyName=”Seven Seas
Imports”
➥ CustomerID=”SEVES”
Address=”90 Wadhurst Rd.”
➥ ContactName=”Hari Kumar” Phone=”(171) 555-1717”/> </Results>
The sql:field attribute may be used in conjunction with the sql:relation attribute to create elements or
attributes that do not exactly match their definitions in the database, as
demonstrated by the annotated XSD schema shown in Listing 18.16.
LISTING 18.16 Customers2.xsd Demonstrates
How Fields from the Database Are Mapped
to Attributes Within the Output XML Document
<?xml version=”1.0” encoding=”UTF-8”?>
<xsd:schema xmlns:sql=”urn:schemas-microsoft-com:mapping-schema”
➥
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”> <xsd:element
name=”CUSTOMER” sql:relation=”Customers”>
<xsd:complexType>
<xsd:attribute name=”Id” type=”xsd:string” sql:field=”CustomerID”/>
<xsd:attribute name=”Company” type=”xsd:string”
sql:field=”CompanyName”/> <xsd:attribute name=”Contact” type=”xsd:string”
sql:field=”ContactName”/> <xsd:attribute name=”Address”
type=”xsd:string”/>
<xsd:attribute name=”City”
type=”xsd:string”/> <xsd:attribute name=”Phone” type=”xsd:string”/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
When the schema in Listing 18.16 is used in the same XPath query, it
will return the following XML result set:
<?xml version=”1.0”?>
<Results>
<CUSTOMER
City=”London” Id=”AROUT” Company=”Around the Horn”
➥ Address=”120 Hanover Sq.” Phone=”(171) 555-7788” ➥ Contact=”Thomas Hardy”/>
<CUSTOMER
City=”London” Id=”BSBEV” Company=”B’s
Beverages”
➥ Address=”Fauntleroy Circus” Phone=”(171) 555-1212” ➥ Contact=”Victoria Ashworth”/>
<CUSTOMER
City=”London” Id=”CONSH” Company=”Consolidated
➥ Holdings” Address=”Berkeley Gardens 12 Brewery” ➥ Phone=”(171) 555-2282” Contact=”Elizabeth Brown”/>
<CUSTOMER
City=”London” Id=”EASTC” Company=”Eastern Connection”
➥ Address=”35 King George” Phone=”(171) 555-0297” ➥ Contact=”Ann Devon”/>
<CUSTOMER
City=”London” Id=”NORTS” Company=”North/South”
➥ Address=”South House 300 Queensbridge” Phone= ➥ ”(171) 555-7733” Contact=”Simon Crowther”/>
<CUSTOMER
City=”London” Id=”SEVES” Company=”Seven Seas Imports”
➥ Address=”90 Wadhurst Rd.” Phone=”(171) 555-1717” ➥ Contact=”Hari Kumar”/>
</Results>
Now let’s say we don’t like having the fields mapped to attributes.
Instead, we could use the schema in Listing 18.17 to produce an XML document
with elements for the fields in the Customers table.
LISTING 18.17 Customers3.xsd Demonstrates
How Fields from the Database Can Be Mapped
to Elements Within the Output XML Document
<?xml version=”1.0” encoding=”UTF-8”?>
<xsd:schema
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”
➥
xmlns:sql=”urn:schemas-microsoft-com:mapping-schema”> <xsd:element
name=”CUSTOMER” sql:relation=”Customers”>
<xsd:complexType>
<xsd:all>
<xsd:element name=”CUSTOMERID” type=”xsd:string”
➥ sql:field=”CustomerID”/>
<xsd:element name=”COMPANY” type=”xsd:string” ➥ sql:field=”CompanyName”/>
<xsd:element name=”CONTACT” type=”xsd:string” ➥ sql:field=”ContactName”/>
<xsd:element name=”ADDRESS” type=”xsd:string” ➥ sql:field=”Address”/>
<xsd:element name=”CITY” type=”xsd:string” ➥ sql:field=”City”/>
<xsd:element name=”PHONE” type=”xsd:string” ➥ sql:field=”Phone”/>
</xsd:all>
</xsd:complexType>
</xsd:element>
</xsd:schema>
If we use the preceding annotated XSD schema in the same XPath query as
before, the XML shown in Listing 18.18 is returned by SQL Server 2000.
LISTING 18.18 The
Resulting XML Document from Executing an XPath Query Against the Customers3.xsd Schema
<?xml version=”1.0”?>
<Results>
<CUSTOMER>
<CUSTOMERID>AROUT</CUSTOMERID>
<COMPANY>Around the Horn</COMPANY> <CONTACT>Thomas
Hardy</CONTACT> <ADDRESS>120 Hanover Sq.</ADDRESS>
<CITY>London</CITY>
<PHONE>(171)
555-7788</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>BSBEV</CUSTOMERID>
<COMPANY>B’s Beverages</COMPANY> <CONTACT>Victoria
Ashworth</CONTACT> <ADDRESS>Fauntleroy Circus</ADDRESS>
<CITY>London</CITY>
<PHONE>(171)
555-1212</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>CONSH</CUSTOMERID> <COMPANY>Consolidated
Holdings</COMPANY> <CONTACT>Elizabeth Brown</CONTACT>
<ADDRESS>Berkeley Gardens 12
Brewery</ADDRESS> <CITY>London</CITY>
<PHONE>(171)
555-2282</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>EASTC</CUSTOMERID>
<COMPANY>Eastern Connection</COMPANY> <CONTACT>Ann
Devon</CONTACT> <ADDRESS>35 King George</ADDRESS>
<CITY>London</CITY>
<PHONE>(171)
555-0297</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>NORTS</CUSTOMERID>
<COMPANY>North/South</COMPANY>
<CONTACT>Simon Crowther</CONTACT>
<ADDRESS>South House 300
Queensbridge</ADDRESS> <CITY>London</CITY>
<PHONE>(171)
555-7733</PHONE> </CUSTOMER>
<CUSTOMER>
<CUSTOMERID>SEVES</CUSTOMERID> <COMPANY>Seven
Seas Imports</COMPANY> <CONTACT>Hari Kumar</CONTACT>
<ADDRESS>90 Wadhurst Rd.</ADDRESS> <CITY>London</CITY>
<PHONE>(171)
555-1717</PHONE> </CUSTOMER>
</Results>
In addition to using the sql:relation and sql:field attributes, we can use the sql:relationship
element, which must be used within the <xsd:appinfo> element, to produce nested XML documents in
which elements may contain related child elements. Four attributes of the sql:relationship element must be specified: parent, parent-key, child, and child-key. The parent attribute specifies the parent table, and the par-ent-key attribute specifies the key on
the parent table to use to relate it to a child table. The child attribute specifies the child
table, and the child-key attribute specifies the key on the child table used to relate it to the
parent table. When these four attributes are used in conjunction with the sql:relationship element, SQL Server 2000 is able
to relate and nest XML elements using the values specified in the attributes of
the sql:relationship element,
as shown in the annotated XSD schema in Listing 18.19.
LISTING 18.19 Customers4.xsd Demonstrates
How to Create a Relationship Between Two
Tables
<?xml version=”1.0” encoding=”UTF-8”?>
<xsd:schema
xmlns:sql=”urn:schemas-microsoft-com:mapping-schema”
➥
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”> <xsd:element
name=”CUSTOMER” sql:relation=”Customers”>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”CUSTOMERID” type=”xsd:string”
➥ sql:field=”CustomerID”/>
<xsd:element name=”COMPANY” type=”xsd:string” ➥ sql:field=”CompanyName”/>
<xsd:element name=”CONTACT” type=”xsd:string” ➥ sql:field=”ContactName”/>
<xsd:element name=”ADDRESS” type=”xsd:string” ➥ sql:field=”Address”/>
<xsd:element name=”CITY” type=”xsd:string” ➥ sql:field=”City”/>
<xsd:element name=”PHONE” type=”xsd:string” ➥ sql:field=”Phone”/>
<xsd:element name=”ORDER” maxOccurs=”unbounded” ➥ sql:relation=”Orders”>
<xsd:annotation>
<xsd:appinfo>
<sql:relationship parent=”Customers” parent-key=
➥ ”CustomerID” child=”Orders” child-key=”CustomerID”/>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”ORDERID” type=”xsd:integer” ➥ sql:field=”OrderID”/>
<xsd:element name=”ORDERDATE” type=”xsd:date” ➥ sql:field=”OrderDate”/>
<xsd:element name=”DETAILS”
maxOccurs=”unbounded” ➥ sql:relation=”[Order
Details]”>
<xsd:annotation>
<xsd:appinfo>
<sql:relationship parent=”Orders” parent-key= ➥ ”OrderID” child=”[Order Details]” child-key=”OrderID”/>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=”ORDERID”
type= ➥ ”xsd:integer”
sql:field=”OrderID”/>
<xsd:element name=”PRODUCTID”
type= ➥ ”xsd:integer”
sql:field=”ProductID”/>
<xsd:element
name=”UNITPRICE” sql:field=
➥ ”UnitPrice”>
<xsd:simpleType>
<xsd:restriction
base=”xsd:decimal”> <xsd:fractionDigits value=”2”/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name=”QUANTITY”
type= ➥ ”xsd:positiveInteger”
sql:field=”Quantity”/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Performing an XPath query for the customer with the
CustomerID ALFKI against the preceding annotated XSD schema will produce the
following result shown in Listing 18.20.
LISTING 18.20 The Results from an XPath Query Against Customers4.xsd
<?xml
version=”1.0”?>
<Results>
<CUSTOMER>
<CUSTOMERID>ALFKI</CUSTOMERID>
<COMPANY>Alfreds Futterkiste</COMPANY> <CONTACT>Maria
Anders</CONTACT> <ADDRESS>Obere Str. 57</ADDRESS>
<CITY>Test</CITY> <PHONE>030-0074321</PHONE>
<ORDER>
<ORDERID>10643</ORDERID>
<ORDERDATE>1997-08-25</ORDERDATE> <DETAILS>
<ORDERID>10643</ORDERID>
<PRODUCTID>28</PRODUCTID>
<UNITPRICE>45.6</UNITPRICE>
<QUANTITY>15</QUANTITY>
</DETAILS>
<DETAILS>
<ORDERID>10643</ORDERID>
<PRODUCTID>39</PRODUCTID>
<UNITPRICE>18</UNITPRICE>
<QUANTITY>21</QUANTITY>
</DETAILS>
<DETAILS>
<ORDERID>10643</ORDERID>
<PRODUCTID>46</PRODUCTID>
<UNITPRICE>12</UNITPRICE>
<QUANTITY>2</QUANTITY>
</DETAILS>
</ORDER>
<ORDER>
<ORDERID>10692</ORDERID>
<ORDERDATE>1997-10-03</ORDERDATE> <DETAILS>
<ORDERID>10692</ORDERID>
<PRODUCTID>63</PRODUCTID>
<UNITPRICE>43.9</UNITPRICE>
<QUANTITY>20</QUANTITY>
</DETAILS>
</ORDER>
<ORDER>
<ORDERID>10702</ORDERID>
<ORDERDATE>1997-10-13</ORDERDATE> <DETAILS>
<ORDERID>10702</ORDERID>
<PRODUCTID>3</PRODUCTID>
<UNITPRICE>10</UNITPRICE>
<QUANTITY>6</QUANTITY>
</DETAILS>
<DETAILS>
<ORDERID>10702</ORDERID>
<PRODUCTID>76</PRODUCTID>
<UNITPRICE>18</UNITPRICE>
<QUANTITY>15</QUANTITY>
</DETAILS>
</ORDER>
<ORDER>
<ORDERID>10835</ORDERID>
<ORDERDATE>1998-01-15</ORDERDATE> <DETAILS>
<ORDERID>10835</ORDERID>
<PRODUCTID>59</PRODUCTID>
<UNITPRICE>55</UNITPRICE>
<QUANTITY>15</QUANTITY>
</DETAILS>
<DETAILS>
<ORDERID>10835</ORDERID>
<PRODUCTID>77</PRODUCTID>
<UNITPRICE>13</UNITPRICE>
<QUANTITY>2</QUANTITY>
</DETAILS>
</ORDER>
<ORDER>
<ORDERID>10952</ORDERID>
<ORDERDATE>1998-03-16</ORDERDATE> <DETAILS>
<ORDERID>10952</ORDERID>
<PRODUCTID>6</PRODUCTID>
<UNITPRICE>25</UNITPRICE>
<QUANTITY>16</QUANTITY>
</DETAILS>
<DETAILS>
<ORDERID>10952</ORDERID>
<PRODUCTID>28</PRODUCTID>
<UNITPRICE>45.6</UNITPRICE>
<QUANTITY>2</QUANTITY>
</DETAILS>
</ORDER>
<ORDER>
<ORDERID>11011</ORDERID> <ORDERDATE>1998-04-09</ORDERDATE>
<DETAILS>
<ORDERID>11011</ORDERID>
<PRODUCTID>58</PRODUCTID>
<UNITPRICE>13.25</UNITPRICE>
<QUANTITY>40</QUANTITY>
</DETAILS>
<DETAILS>
<ORDERID>11011</ORDERID>
<PRODUCTID>71</PRODUCTID>
<UNITPRICE>21.5</UNITPRICE>
<QUANTITY>20</QUANTITY>
</DETAILS>
</ORDER>
</CUSTOMER>
</Results>
But wait, why is there so much interest in creating annotated XSD
schemas? Unfortunately, these files have to exist to perform an XPath query.
Basically, to perform an XPath query, the syntax is as follows:
http://servername/sqlvirtualdirectory/schemavirtualdirectory/ ➥ schemafilename/Xpathexpression?Root=RootNodeName
Because we’ve already covered the syntax for XPath expressions in
Chapter 4, “Creating XML Schemas,” we will not go over it again here. The main
difference you need to keep in mind is the exclusion of the root element within
the expression because it is not defined within the schema. For instance, the
following XPath query would result in an error:
http://localhost/sql2000/schema/customers.xsd/Results/CUSTOMER? ➥ Root=Results
Instead, you need to write this XPath query as follows:
http://localhost/sql2000/schema/customers.xsd/CUSTOMER?Root=Results
XML Updategrams
Rather than having to code multiple stored procedures to handle the
inserting, updating, and deleting of records within a database, you can use XML
updategrams instead. These XML documents are posted to SQL Server’s virtual
directory and are intercepted by the SQL ISAPI extension. By using various
elements within an XML updategram, SQL Server can modify the data in the
database accordingly.
The basic premise behind an XML updategram is that it behaves the same
as a template and uses a snapshot of information, both before and after changes
are made to the XML fragment, to determine how SQL Server must proceed. By
using a combination of <sync> elements, which mark the beginning and end of a transaction, and <before> and
<after> elements, SQL Server can
determine whether a new record is being created or an existing record is being
modified or deleted.
The <before> element identifies what the database’s existing state is. The <after> element tells what the
database’s new state will be. The <sync> element indicates what a transaction encompasses. It contains one or
more <before> and <after> elements, and all the pairs
within a <sync> element will be executed as one transaction. Therefore, either
everything within a <sync> element will be performed, or nothing will be performed.
Here’s the basic structure of an XML updategram:
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”> <updg:sync
[mapping-schema= “XDRSchemaFile.xml”]>
<updg:before>
...
</updg:before>
<updg:after>
...
</updg:after>
</updg:sync>
</ROOT>
Note the inclusion of the updategram namespace: urn:schemas-microsoft-com:xml-updategram. This
namespace is required for XML updategrams. However, the actual namespace you decide to use
within your updategrams is completely up to you. For instance, the following is
also a perfectly valid XML updategram structure:
<ROOT
xmlns:eps=”urn:schemas-microsoft-com:xml-updategram”> <eps:sync
[mapping-schema=”XDRSchemaFile.xml”]>
<eps:before>
...
</eps:before>
<eps:after>
...
</eps:after>
</eps:sync>
</ROOT>
An XML updategram determines what function to perform based on the
contents of the <before> and <after> elements, which is outlined as follows:
If a record’s XML definition
appears only in the <before> element with no corre-sponding definition in the <after> element, the XML updategram
performs a delete operation.
If a record’s XML appears only in
the <after> element
with no corresponding XML in the <before> element, an insert operation is performed.
If the XML for a record appears
in the <before> element and has a corresponding definition in the <after> element, an update operation is
performed. In this case, the updategram updates the record instance to the
values specified in the <after> element.
Mapping the XML to the Database
An XML updategram can map the XML back into the database either implicitly
or explicitly. In other words, specifying the XDR schema in the updategram is
optional as long as you follow a few simple rules. First and foremost, remember
that you must use FOR XML AUTO or FOR XML AUTO,ELEMENTS in order to use the default mapping that SQL ISAPI provides.
In simple insert, update, and delete scenarios, implicit mapping may be
enough to per-form the necessary operation on the given XML fragment. SQL ISAPI
will attempt to map the elements and attributes back to the database in a fashion
that’s similar to how it maps the database to an XML fragment using FOR XML AUTO. The key for this approach to
work, however, is that each element, which represents a table, must be named
the same as the table name. Remember, XML is case sensitive. Also, each element
or attribute that represents a field must be named likewise. For instance, the
following XML updategram will insert a new customer into the Customers table of
the Northwind data-base:
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”> <updg:sync >
<updg:before>
</updg:before>
<updg:after>
<Customers CustomerID=”TEST”
CompanyName=”Test insert comp.”/> </updg:after>
</updg:sync>
</ROOT>
By examining the preceding XML updategram, you can see how SQL Server
identifies how it must behave. Given this XML updategram, SQL ISAPI sees that
there is nothing in the <before> element that corresponds to anything in the <after> element, so it deter-mines that
an insert operation must be performed. SQL ISAPI also examines the contents of the
<after> element
and determines from the existence of the <Customers> element that a new record will be inserted into the Customers table.
Furthermore, SQL ISAPI realizes that two fields will have values specified for
them—CustomerID and CompanyName—based on the occurrence of
attributes with those names.
For complex mappings, you can explicitly identify an annotated XSD
schema to use in order to map the elements and attributes back to the
appropriate tables and fields in the database. Each transaction unit,
identified by a <sync> element, can have its own map-ping schema to use to map elements and
attributes back into the database.
Implicit Mapping in Updategrams
An element-centric updategram is comprised of elements that contain
subelements. The elements map to a table in the database, and the subelements
map to fields within that table. Therefore, to use element-centric mapping, we
need an XML document that looks something like this:
<Customers>
<CustomerID>TEST</CustomerID>
<CompanyName>Test insert comp</CompanyName>
</Customers>
In this case, to perform an insert operation, we would construct the
following updategram:
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”> <updg:sync >
<updg:after>
<Customers>
<CustomerID>TEST</CustomerID>
<CompanyName>Test insert comp</CompanyName>
</Customers>
</updg:after>
</updg:sync>
</ROOT>
For attribute-centric mappings, the table element contains attributes that
map to fields within the table. Therefore, the previous example could be
represented in an attribute-centric approach by using an XML document, like
this:
<Customers
CustomerID=”TEST”
CompanyName=”Test insert comp”/>
An XML updategram like this one would also be used:
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”> <updg:sync >
<updg:after>
<Customers CustomerID=”TEST”
CompanyName=”Test insert comp”/> </updg:after>
</updg:sync>
</ROOT>
Interestingly enough, a combination of element-centric and
attribute-centric mappings can be used. As long as the elements and attributes
map back into the database using the default mapping provided by FOR XML AUTO, the two approaches can be
mixed. For instance, imagine the following XML document:
<Customers
CustomerID=”Test”> <CompanyName>Test insert comp</CompanyName>
</Customers>
This record could be inserted into SQL Server by using an XML updategram
like the following:
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”> <updg:sync >
<updg:after>
<Customers
CustomerID=”TEST”> <CompanyName>Test insert comp</CompanyName>
</Customers>
</updg:after>
</updg:sync>
</ROOT>
Explicit Mapping in Updategrams
In the case of complex mappings, an annotated XSD schema can be
specified for each transaction the XML updategram performs by specifying the
name of the corresponding XDR schema in the mapping-schema attribute of the <sync> element. By doing this, explicit mapping is chosen, and every element
and attribute of the XML document must map to the elements and attributes
within the specified XSD schema. For example, in a simple case, an annotated
XSD schema could contain the following:
<?xml version=”1.0” encoding=”UTF-8”?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema” ➥ xmlns:sql=”urn:schemas-microsoft-com:mapping-schema”>
<xsd:element name=”CUSTOMER”
sql:relation=”Customers”> <xsd:complexType>
<xsd:attribute name=”CustomerID”
type=”xsd:string”/> <xsd:attribute name=”CompanyName”
type=”xsd:string”/> <xsd:attribute name=”ContactName”
type=”xsd:string”/> <xsd:attribute name=”Address” type=”xsd:string”/>
<xsd:attribute name=”City” type=”xsd:string”/> <xsd:attribute
name=”Phone” type=”xsd:string”/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Using this schema, an XML document like the following could be placed
into an XML updategram:
<CUSTOMER CustomerID=”TEST” CompanyName=”Test insert
comp”
➥ ContactName=”Test contact” Address=”Some address” ➥ City=”Unknown” Phone=”9999999”/>
To insert this XML document into the Customers table of the Northwind
database, we need to post an updategram like the following to the SQL Server
virtual directory:
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”> <updg:sync
mapping-schema=”SampleSchema1.xml”>
<updg:after>
<CUSTOMER
CustomerID=”TEST” CompanyName=
➥ ”Test insert comp” ContactName=”Test contact” Address= ➥ ”Some address” City=”Unknown” Phone=”9999999”/>
</updg:after>
</updg:sync>
</ROOT>
However, the XSD schemas and the corresponding XML documents that will
be inserted can get quite complex. For instance, the XSD schema shown in
Listing 18.19, maps fields and tables from the Northwind database into a
hierarchical XML document.
Based on the schema in Listing 18.19, an XML document like the following
could be placed into an XML updategram:
<CUSTOMER>
<CUSTOMERID>TEST</CUSTOMERID>
<COMPANY>Test insert comp</COMPANY> <CONTACT>Test
contact</CONTACT> <ADDRESS>Test address</ADDRESS>
<CITY>Test city</CITY> <PHONE>9999999</PHONE>
<ORDER
updg:at-identity=”OrderId”> <ORDERDATE>2001-07-23</ORDERDATE>
<DETAILS>
<ORDERID></ORDERID>
<PRODUCTID>28</PRODUCTID>
<UNITPRICE>45.6</UNITPRICE>
<QUANTITY>15</QUANTITY>
</DETAILS>
</ORDER>
</CUSTOMER>
Given this XML document, the information could be inserted by creating
the XML updategram shown in Listing 18.21.
LISTING 18.21 A Sample XML Updategram
Using a Mapping Schema
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”>
<updg:sync
mapping-schema=”../Schema/Customers4.xsd”>
<updg:after>
<CUSTOMER>
<CUSTOMERID>TEST</CUSTOMERID> <COMPANY>Test insert
comp</COMPANY> <CONTACT>Test contact</CONTACT> <ADDRESS>Test
address</ADDRESS> <CITY>Test city</CITY>
<PHONE>9999999</PHONE>
<ORDER
updg:at-identity=”OrderId”> <ORDERDATE>2001-07-23</ORDERDATE>
<DETAILS>
<ORDERID>OrderId</ORDERID>
<PRODUCTID>28</PRODUCTID>
<UNITPRICE>45.6</UNITPRICE>
<QUANTITY>15</QUANTITY>
</DETAILS>
</ORDER>
</CUSTOMER>
</updg:after>
</updg:sync>
</ROOT>
This example uses a new attribute for the updategram: at-identity. This attribute cap-tures the
identity value for the identity column of the referenced table and stores it in
the specified variable for later use in the updategram, as shown in the <ORDERID> element contained in the <DETAILS> element.
NULL Handling in Updategrams
NULL fields in SQL Server are not returned in the XML document. However,
it is some-times useful to set a field to NULL. Using updategrams, this can be
accomplished by using the nullvalue attribute on a <sync> element. When the nullvalue attribute is specified in an <sync> element, SQL ISAPI can determine that when it encounters the specified
string, it should insert NULL into the field. For instance, to insert a NULL
value into the CompanyName field of the Customers table in the Northwind
database, we could use the following XML updategram:
<ROOT
xmlns:updg=”urn:schemas-microsoft-com:xml-updategram”>
<updg:sync
updg:nullvalue=”.NULL.” >
<updg:before>
<Customers
CustomerID=”ALFKI”/> </updg:before>
<updg:after>
<Customers CustomerID=”ALFKI”
CompanyName=”.NULL.” /> </updg:after>
</updg:sync>
</ROOT>
When SQL ISAPI encounters the .NULL. value in the CompanyName attribute, it inserts NULL into the
CompanyName field.
Executing Updategrams
Knowing how XML updategrams function is one thing, but how do we get SQL
ISAPI to perform the necessary operations? Quite simply, we can post the
updategram to the SQL Server virtual directory. This can be accomplished using
an HTML page or the XMLHTTP COM object available in MSXML2. For instance, we could use the
following code in Visual Basic to post an XML updategram to a SQL Server
virtual directory called local-host/sql2000:
Dim loPost As
New MSXML2.xmlHttp
Dim loXML As
New MSXML2.DOMDocument
loXML.Async=.F. loXML.loadXML MyUpdateGram
‘ Post the
template.
loPost.Open “POST”, “http://localhost/sql2000”, False
loPost.setRequestHeader “Content-type”, “text/xml” loPost.send loXML
We can then query the ResponseText property of the XMLHTTP object to find out whether an error occurred and what the result was.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.