Remembering that your goal is an XML file with a list of authors, you match on the root node ofBooks.xmland output a root element for the resulting document named.. If you think it is od
Trang 1Figure 10-6
There is no end to the number of places you can find and use XML: files, databases, Web sites, and
services Sometimes you will want to manipulate the XML via queries or programmatically, and some-times you will want to take the XML ‘‘tree’’ and transform it into a tree of a different form
XSLT
XSLT is a tree transformation language also written in XML syntax It’s a strange hybrid of a declarative and a programmatic language, and some programmers would argue that it’s not a language at all
Others, who use a number of XSLT scripting extensions, would argue that it is a very powerful language Regardless of the controversy, XSLT transformations are very useful for changing the structure of XML files quickly and easily, often using a very declarative syntax
Trang 2The best way to familiarize yourself with XSLT is to look at an example Remember that theBooks.xml
file used in this chapter is a list of books and their authors The XSLT in Listing 10-18 takes that document
and transforms it into a document that is a list of authors
Listing 10-18: Books.xslt
XSLT
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:element name="Authors">
<xsl:apply-templates select="//book"/>
</xsl:element>
</xsl:template>
<xsl:template match="book">
<xsl:element name="Author">
<xsl:value-of select="author/first-name"/>
<xsl:text> </xsl:text>
<xsl:value-of select="author/last-name"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Remember that XSLT is XML vocabulary in its own right, so it makes sense that it has its own namespace
and namespace prefix XSLT is typically structured with a series of templates that match elements in
the source document The XSLT document doesn’t describe what the result looks like as much as it
declares what steps must occur for the transformation to succeed Remembering that your goal is an
XML file with a list of authors, you match on the root node ofBooks.xmland output a root element
for the resulting document named<Authors> Then<xsl:apply-templates select = "//book"/>
indicates to the processor that it should continue looking for templates that, in this case, match the XPath
expression//book Below the first template is a second template that handles all book matches It outputs
a new element named<Author>
XSLT is very focused on context, so it is often helpful to imagine a cursor that is on a particular element
of the source document Immediately after outputting the<Author>element, the processor is in the
middle of the template match on thebookelement All XPath expressions in this example are relative
to thebookelement So the<xsl:value-of select = "author/first-name">directive searches for the
author’s first name relative to thebookelement The<xsl:text> </xsl:text>directive is interesting
to note because it is explicit and a reminder that a difference exists between significant white space and
insignificant white space It is important, for example, that a space is put between the author’s first and
last names, so it must be called out explicitly
The resulting document is shown in Figure 10-7
This example only scratches the surface of XSLT’s power Although a full exploration of XSLT is beyond
the scope of this book, other books by Wrox Press cover the topic more fully Remember that the NET
Framework implements the 1.0 implementation of XSLT As of this writing, XSLT 2.0 and XPath 2.0 are
W3C Recommendations, and Microsoft is working on CTPs (Community Technology Previews) of XSLT
2 functionality More details are available on the Microsoft XmlTeam blog athttp://blogs.msdn.com/
xmlteam/archive/2007/01/29/xslt-2-0.aspx
Trang 3Figure 10-7
Figure 10-7 shows the resulting XML as theBooks.xslttransformation is applied toBooks.xml You
can apply XSLT transformations in a number of ways, both declarative and programmatic These are
described in the following sections
XslCompiledTransform
TheXslTransformclass was used in the NET Framework 1.x for XSLT transformation In the NET
Framework 2.0, theXslCompiledTransformclass is the new XSLT processor It is such an improvement thatXslTransformis deprecated and marked with theObsoleteattribute The compiler will now advise you to useXslCompiledTransform The system generates MSIL code on the call toCompile()and the
XSLT executes many times faster than previous techniques This compilation technique also includes full debugging support from within Visual Studio, which is covered a little later in this chapter
The XPathDocument is absolutely optimized for XSLT transformations and should
be used instead of the XmlDocument if you would like a 15 to 30 percent performance
gain in your transformations Remember that XSLT contains XPath, and when you
use XPath, use an XPathDocument According to the team’s numbers, XSLT is 400
percent faster in NET Framework 2.0.
XslCompiledTransformhas only two methods:LoadandTransform The compilation happens without any effort on your part Listing 10-19 loads theBooks.xmlfile into anXPathDocumentand transforms it usingBooks.xsltand anXslCompiledTransform Even though there are only two methods, there are
14 overrides forTransformand 6 forLoad That may seem a little daunting at first, but there is a simple explanation
TheLoadmethod can handle loading a stylesheet from a string, anXmlReader, or any class that
implementsIXPathNavigable AnXsltSettingsobject can be passed in optionally with any of the
Trang 4previous three overloads, giving you six to choose from.XsltSettingsincludes options to enable the
document()XSLT–specific function via theXsltSettings.EnableDocumentFunctionproperty or enable
embedded script blocks within XSLT viaXsltSettings.EnableScript These advanced options are
disabled by default for security reasons Alternatively, you can retrieve a pre-populatedXslSettings
object via the static propertyXsltSettings.TrustedXslt, which has enabled both these settings
If you think it is odd that the class that does the work is called the
XslCompiledTransform and not the XsltCompiledTransform , but XsltSettings
includes the t, remember that the t in XSLT means transformation.
Note in Listing 10-19 that theResponse.Outputproperty eliminates an unnecessary string allocation In
the example,Response.Outputis aTextWriterwrapped in anXmlTextWriterand passed directly to the
Executemethod
Listing 10-19: Executing an XsltCompiledTransform
VB
Response.ContentType = "text/xml"
Dim xsltFile As String = Server.MapPath("books.xslt")
Dim xmlFile As String = Server.MapPath("books.xml")
Dim xslt As New XslCompiledTransform()
xslt.Load(xsltFile)
Dim doc As New XPathDocument(xmlFile)
xslt.Transform(doc, New XmlTextWriter(Response.Output))
C#
Response.ContentType = "text/xml";
string xsltFile = Server.MapPath("books.xslt");
string xmlFile = Server.MapPath("books.xml");
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(xsltFile);
XPathDocument doc = new XPathDocument(xmlFile);
xslt.Transform(doc, new XmlTextWriter(Response.Output));
Named arguments may be passed into anXslTransformorXslCompiledTransformif the stylesheet takes
parameters The following code snippet illustrates the use ofXslArgumentList:
XslTransform transformer = new XslTransform();
transformer.Load("foo.xslt");
XslArgumentList args = new XslArgumentList();
args.Add("ID", "SOMEVALUE");
transformer.Transform("foo.xml", args, Response.OutputStream);
Trang 5The XML resulting from an XSLT transformation can be manipulated with any of thesystem.XMLAPIs that have been discussed in this chapter One common use of XSLT is to flatten hierarchical and, some-times, relational XML documents into a format that is more conducive to output as HTML The results of these transformations to HTML can be placed inline within an existing ASPX document
The new XSLTC.exe Command-Line Compiler
Compiled stylesheets are very useful but there is a slight performance hit as the stylesheets are compiled
at runtime, so the NET Framework 3.5 has introducedXSLTC.exe, a command-line XSLT compiler
Usage is simple — you simply pass in as many source XSLT files as you like and specify the assembly
output file From a Visual Studio 2008 command prompt, use the following:
Xsltc /c:Wrox.Book.CompiledStylesheet books.xslt /out:Books.dll
Now, add a reference to the newly createdBooks.dllin your project from Listing 10-19, and change
one line:
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(typeof(Wrox.Book.MyCompiledStyleSheet));
Rather than loading the XSLT from a file, it’s now loaded pre-compiled directly from the generated
assembly Using the XSLT Compiler makes deployment much easier as you can put many XSLTs in a
single assembly, but most important, you eliminate code-generation time
If your XSLT uses msxsl:script elements, that code will be compiled into separate assemblies, one per
language used You can merge these resulting assemblies with ILMerge, located athttp://research
.microsoft.com/∼mbarnett/ILMerge.aspx, as a post-build step.XML Web Server Control
XSLT transformations can also be a very quick way to get information out to the browser as HTML
Consider this technique as yet another tool in your toolbox HTML is a tree, and HTML is a cousin of
XML, so an XML tree can be transformed into an HTML tree A benefit of using XSLT transformations
to create large amounts of static text, like HTML tables, is that the XSLT file can be kept external to the
application You can make quick changes to its formatting without a recompile A problem when using XSLT transformations is that they can become large and very unruly when someone attempts to use
them to generate the entire user interface experience The practice was in vogue in the mid-nineties to
use XSLT transformations to generate entire Web sites, but the usefulness of this technique breaks down when complex user interactions are introduced That said, XSLT has a place, not only for transforming
data from one format to another, but also for creating reasonable chunks of your user interface-as long as you don’t go overboard
In the next example, the output of the XSLT is HTML rather than XML Note the use of the<xsl:output
method = "html">directive When this directive is omitted, the default output of an XSLT transformation
is XML This template begins with a match on the root node It is creating an HTML fragment rather than
an entire HTML document Its first output is the<h3>tag with some static text Next comes a table tag and the header row, and then the<xsl:apply-template>element selects all books within the source
XML document For everybookelement in the source document, the second template is invoked with the responsibility of outputting one table row per book Calls to<xsl:value-of>select each of the book’s subnodes and output them within the<td>tags (see Listing 10-20)
Trang 6Listing 10-20: BookstoHTML.xslt used with the XML Web Server Control
XSLT
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:b="http://example.books.com" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<h3>List of Authors</h3>
<table border="1">
<tr>
<th>First</th><th>Last</th>
</tr>
<xsl:apply-templates select="//b:book"/>
</table>
</xsl:template>
<xsl:template match="b:book">
<tr>
<td><xsl:value-of select="b:author/b:first-name"/></td>
<td><xsl:value-of select="b:author/b:last-name"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
ASPX
<%@ Page Language="VB" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server"><title>HTML/XSLT Transformation</title></head>
<body>
<form id="form1" runat="server">
<div>
<asp:Xml ID="Xml1" Runat="server"
DocumentSource="~/Books.xml"
TransformSource="~/bookstoHTML.xslt"/>
</div>
</form>
</body>
</html>
Notice the use of namespace prefixes in Listing 10-20 The source namespace is declared with the prefixb
as inxmlns:b="http://example.books.com"and thebprefix is subsequently used in XPath expressions
like//b:book The XSLT in Listing 10-20 can use theXSLTCommandto perform this transformation on the
server-side because the entire operation is declarative and requires just two inputs — the XML document
and the XSLT document The XML Web server control makes the transformation easy to perform from
the ASPX page and does not require any language-specific features TheDocumentSourceproperty of the
control holds the path to theBooks.xmlfile, whereas theTransformSourceproperty holds the path to
theBookstoHTML.xsltfile:
<h3>List of Authors</h3>
<table border="1">
<tr>
<th>First</th>
<th>Last</th>
Trang 7<td>Benjamin</td>
<td>Franklin</td>
</tr>
<tr>
<td>Herman</td>
<td>Melville</td>
</tr>
<tr>
<td>Sidas</td>
<td>Plato</td>
</tr>
</table>
The results of this transformation are output inline to this HTML document and appear between the two
<div>tags You see the results of this HTML fragment in the previous code and in the browser’s output shown in Figure 10-8
Figure 10-8
XSLT Debugging
One of the exciting new additions to ASP.NET 2.0 and Visual Studio was XSLT debugging Visual
Studio 2005 enabled breakpoints on XSLT documents and Visual Studio 2008 adds XSLT Debugger Data Breakpoints — the ability to break on nodes within the source XML document However, be aware that XSLT debugging is available only in the Professional and Team System versions of Visual Studio and
only when using theXslCompiledTransformclass
By passing the Boolean valuetrueinto the constructor ofXslCompiledTransform, you can step into and debug your XSLT transformations within the Microsoft Development Environment
Trang 8In Listing 10-19, change the call to the constructor ofXslCompiledTransformto include the valuetrue
and set a breakpoint on theTransformmethod When you reach that breakpoint, press F11 to step into
the transformation Figure 10-9 shows a debugging session of theBooks.xslt/Books.xmltransformation
in process
Figure 10-9
In the past, debugging XSLT was largely an opaque process that required a third-party application to
troubleshoot The addition of debugging XSLT to Visual Studio means that your XML experience is just
that much more integrated and seamless
Databases and XML
You have seen that XML can come from any source whether it be a Web service, a file on disk, an XML
fragment returned from a Web server, or a database SQL server and ADO have rich support for
XML, starting with theExecuteXmlReadermethod of theSystem.Data.SqlCommandclass Additional
support for XML on SQL Server 2000 is included with SQLXML 3.0 and its XML extensions, and SQL
Server 2005 has native XML data type support built right in
Trang 9FOR XML AUTO
You can modify a SQL query to return XML with theFOR XML AUTOclause If you take a simple query
such asselect * from customers, you just change the statement like so:
select * from customers FOR XML AUTO
XML AUTOreturns XML fragments rather than a full XML document with a document element Each row
in the database becomes one element; each column in the database becomes one attribute on the element Notice that each element in the following result set is namedCustomersbecause theselectclause is
from customers:
<Customers CustomerID="ALFKI" CompanyName="Alfreds Futterkiste"
ContactName="Maria Anders" ContactTitle="Sales Representative"
Address="Obere Str 57" City="Berlin" 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 Constitucion 2222" City="Mexico D.F." PostalCode="05021"
Country="Mexico" Phone="(5) 555-4729" Fax="(5) 555-3745" />
If you addELEMENTSto the query like so
select * from customers FOR XML AUTO, ELEMENTS
you get an XML fragment like this:
<Customers>
<CustomerID>ALFKI</CustomerID>
<CompanyName>Alfreds Futterkiste</CompanyName>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
<Address>Obere Str 57</Address>
<City>Berlin</City>
<PostalCode>12209</PostalCode>
<Country>Germany</Country>
<Phone>030-0074321</Phone>
<Fax>030-0076545</Fax>
</Customers>
<Customers>
<CustomerID>ANATR</CustomerID>
<CompanyName>Ana Trujillo Emparedados y helados</CompanyName>
<ContactName>Ana Trujillo</ContactName>
<ContactTitle>Owner</ContactTitle>
<Address>Avda de la Constitucion 2222</Address>
<City>Mexico D.F.</City>
<PostalCode>05021</PostalCode>
<Country>Mexico</Country>
<Phone>(5) 555-4729</Phone>
<Fax>(5) 555-3745</Fax>
</Customers>
Trang 10The previous example is just a fragment with no document element To perform an XSLT transformation,
you need a document element (sometimes incorrectly referred to as the ‘‘root node’’), and you probably
want to change the<Customers>elements to<Customer> By using an alias likeas Customerin the
selectstatement, you can affect the name of each row’s element The queryselect * from Customers
as Customer for XML AUTO, ELEMENTSchanges the name of the element to<Customer>
Now, put together all the things you’ve learned from this chapter and create anXmlDocument, edit and
manipulate it, retrieve data from SQL Server as anXmlReader, and style that information with XSLT into
an HTML table all in just a few lines of code
First, add a document element to the document retrieved by the SQL queryselect * from Customers as
Customer for XML AUTO, ELEMENTS, as shown in Listing 10-21
Listing 10-21: Retrieving XML from SQL Server 2000 using FOR XML AUTO
VB
Dim connStr As String = "database=Northwind;Data Source=localhost;" & _
" User id=sa;pwd=wrox"
Dim x As New XmlDocument()
Dim xpathnav As XPathNavigator = x.CreateNavigator()
Using conn As New SqlConnection(connStr)
conn.Open()
Dim command As New SqlCommand("select * from Customers as Customer " & _
"for XML AUTO, ELEMENTS", conn) Using xw As XmlWriter = xpathnav.PrependChild()
xw.WriteStartElement("Customers") Using xr As XmlReader = command.ExecuteXmlReader() xw.WriteNode(xr, True)
End Using xw.WriteEndElement() End Using
End Using
Response.ContentType = "text/xml"
x.Save(Response.Output)
C#
string connStr = "database=Northwind;Data Source=localhost;User id=sa;pwd=wrox";
XmlDocument x = new XmlDocument();
XPathNavigator xpathnav = x.CreateNavigator();
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
SqlCommand command = new SqlCommand(
"select * from Customers as Customer for XML AUTO, ELEMENTS", conn);
using (XmlWriter xw = xpathnav.PrependChild())
{
xw.WriteStartElement("Customers");
using (XmlReader xr = command.ExecuteXmlReader()) {
xw.WriteNode(xr, true);
}