Second Edition Juli 2008
ISBN 978-0-596-52721-1
Weitere Informationen zu diesem Buch
Inhaltsverzeichnis | Kolophon | Beispiel Code |
Inhaltsverzeichnis
- Chapter 1: Getting Started
- InhaltsvorschauIn this chapter, we review the design rationale behind XSLT and XPath and discuss the basics of XML. We also talk about other web standards and how they relate to XSLT and XPath. We conclude the chapter with a brief discussion of how to set up an XSLT processor on your machine so you can work with the examples throughout the book.XML went from working group to entrenched buzzword in record time. Its flexibility as a language for presenting structured data made it the lingua franca for data interchange. Early adopters used programming interfaces such as the Document Object Model (DOM) and the Simple API for XML (SAX) to parse and process XML documents. As XML became mainstream, however, it was clear that the average web citizen couldn’t be expected to hack Java, Visual Basic, Perl, or Python code to work with documents. What was needed was a flexible, powerful, yet relatively simple language capable of processing XML.What the world needed was XSLT.XSLT, the Extensible Stylesheet Language for Transformations, is an official recommendation of the World Wide Web Consortium (W3C). It provides a flexible, powerful language for transforming XML documents into something else, such as an HTML document, another XML document, a Portable Document Format (PDF) file, a Scalable Vector Graphics (SVG) file, a Virtual Reality Modeling Language (VRML) file, Java code, a flat text file, a JPEG file, or most anything you want. You write an XSLT stylesheet to define the rules for transforming an XML document, and the XSLT processor does the work.The W3C has defined two families of standards for stylesheets. The oldest and simplest is Cascading Style Sheets (CSS), a mechanism used to define various properties of markup elements. Although CSS can be used with XML, it is most often used to style HTML documents. I can use CSS properties to define certain elements to be rendered in blue, or in 58-point type, or in boldface. That’s all well and good, but there are many things that CSS can’t do:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- The Design of XSLT
- InhaltsvorschauXML went from working group to entrenched buzzword in record time. Its flexibility as a language for presenting structured data made it the lingua franca for data interchange. Early adopters used programming interfaces such as the Document Object Model (DOM) and the Simple API for XML (SAX) to parse and process XML documents. As XML became mainstream, however, it was clear that the average web citizen couldn’t be expected to hack Java, Visual Basic, Perl, or Python code to work with documents. What was needed was a flexible, powerful, yet relatively simple language capable of processing XML.What the world needed was XSLT.XSLT, the Extensible Stylesheet Language for Transformations, is an official recommendation of the World Wide Web Consortium (W3C). It provides a flexible, powerful language for transforming XML documents into something else, such as an HTML document, another XML document, a Portable Document Format (PDF) file, a Scalable Vector Graphics (SVG) file, a Virtual Reality Modeling Language (VRML) file, Java code, a flat text file, a JPEG file, or most anything you want. You write an XSLT stylesheet to define the rules for transforming an XML document, and the XSLT processor does the work.The W3C has defined two families of standards for stylesheets. The oldest and simplest is Cascading Style Sheets (CSS), a mechanism used to define various properties of markup elements. Although CSS can be used with XML, it is most often used to style HTML documents. I can use CSS properties to define certain elements to be rendered in blue, or in 58-point type, or in boldface. That’s all well and good, but there are many things that CSS can’t do:
- CSS can’t change the order in which elements appear in a document. If you want to sort certain elements or filter elements based on a certain property, CSS won’t do the job.
- CSS can’t do computations. If you want to calculate and output a value (maybe you want to add up the numeric value of all
<price>elements in a document), CSS won’t do the job.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - XML Basics
- InhaltsvorschauAlmost everything we do in this book deals with XML documents. XSLT stylesheets are XML documents themselves, and they’re designed to transform an XML document into something else. If you don’t have much experience with XML, we’ll review the basics here. For more information on XML, check out Erik T. Ray’s Learning XML (O’Reilly, 2001) and Elliotte Rusty Harold and W. Scott Means’s XML in a Nutshell (O’Reilly, 2001).XML’s heritage is in the Standard Generalized Markup Language (SGML). Created by Dr. Charles Goldfarb in the 1970s, SGML is widely used in high-end publishing systems. Unfortunately, SGML’s perceived complexity prevented its widespread adoption across the industry (SGML also stands for "sounds great, maybe later"). SGML got a boost when Tim Berners-Lee based HTML on SGML. Overnight, the whole computing industry was using a markup language to build documents and applications.The problem with HTML is that its tags were designed for the interaction between humans and machines. When the Web was invented in the late 1980s, that was just fine. As the Web moved into all aspects of our lives, HTML was asked to do lots of strange things. We’ve all built HTML pages with awkward table structures, 1-pixel GIFs, and other nonsense just to get the page to look right in the browser. XML is designed to get us out of this rut and back into the world of structured documents.Whatever its limitations, HTML is the most popular markup language ever created. Given its popularity, why do we need XML? Consider this extremely informative HTML element:
<td>12304</td>
What does this fascinating piece of content represent?- Is it the postal code for Schenectady, New York?
- Is it the number of light bulbs replaced each month in Las Vegas?
- Is it the number of Volkswagens sold in Hong Kong last year?
- Is it the number of tons of steel in the Sydney Harbour Bridge?
The answer: maybe, maybe not. The point of this silly example is that there’s no structure to this data. Even if we include the entire table, it takes intelligence (real, live intelligence, the kind between your ears) to make sense of this. If you saw this cell in a table next to another cell that contained the textEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Installing XSLT Processors
- InhaltsvorschauBefore we dive in to creating stylesheets, we’ll cover how to install four popular XSLT processors.In this section, we’ll go over how to install the Xalan XSLT processor. In the next chapter, we’ll create our first stylesheet and use it to transform an XML document.The installation process is pretty simple, assuming you already have a Java Runtime Environment (JRE) installed on your machine. Although very little of the code we look at in this book uses Java, the Xalan XSLT processor itself is written in Java. Once you’ve installed the JRE, go to http://xml.apache.org/xalan-j/ and download the latest stable build of the code. (If you’re feeling brave, feel free to download last night’s build .)Once the Xalan .zip or .gzip file is downloaded, unpack it and add three files to your
CLASSPATH. The three files include two .jar files for the Xerces parser, and the .jar file for the Xalan stylesheet engine itself. As of this writing, the .jar files are named xalan.jar, xercesImpl.jar, and xml-apis.jar. (There’s a fourth file, bsf.jar, that includes the Bean Scripting Framework, but we’ll use that for extensions only.)To make sure Xalan is installed correctly, go to a command prompt and type the following command:java org.apache.xalan.xslt.Process
This is a Java class, so everything is case-sensitive. You should see an error message like this:java org.apache.xalan.xslt.Process =xslproc options: -IN inputXMLURL [-XSL XSLTransformationURL] [-OUT outputURL] [-LXCIN compiledStylesheetFileNameIn] [-LXCOUT compiledStylesheetFileNameOutOut] ...If you get this message, you’re all set! You’re ready for the next chapter, in which we’ll build our very first XSLT stylesheet.As of this writing, the most complete open source XSLT 2.0 stylesheet processor is Saxon. Written by Michael Kay, the editor of the XSLT 2.0 spec, it is available at http://saxon.sourceforge.net. When you download the file (currently saxonb9-0-0-2j.zip), addEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauIn this chapter, we’ve gone over the basics of XML and talked about DOM and SAX, two standards that are commonly used by XSLT processors. We also talked about other technology standards and how to install several stylesheet processors. At this point, you’ve got everything you need to build and use your first stylesheets, which we’ll do in the next chapter.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 2: The Obligatory Hello World Example
- InhaltsvorschauIn future chapters, we’ll spend a lot of time talking about XSLT, XPath, and various advanced functions used to transform XML documents. First, though, we’ll go through a short example to illustrate how stylesheets work.By the end of this chapter, you should know:
- How to create a basic stylesheet
- How to use a stylesheet to transform an XML document
- How a stylesheet processor uses a stylesheet to transform an XML document
- The structure of an XSLT stylesheet
Continuing the tradition of Hello World examples begun by Brian Kernighan and Dennis Ritchie in The C Programming Language (Prentice Hall, 1988), we’ll transform a Hello World XML document.First, we’ll look at our sample document. This simple XML document, courtesy of the XML 1.0 specification, contains the famous friendly greeting to the world:<?xml version="1.0"?><!-- greeting.xml --> <greeting> Hello, World! </greeting>What we’d like to do is transform this fascinating document into something we can view in an ordinary household browser.Here’s an XSLT stylesheet that defines how to transform the XML document:<?xml version="1.0"?><!-- greeting.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <xsl:apply-templates select="greeting"/> </xsl:template> <xsl:template match="greeting"> <html> <body> <h1> <xsl:value-of select="."/> </h1> </body> </html> </xsl:template> </xsl:stylesheet>We’ll talk about these elements and what they do in just a minute. Keep in mind that the stylesheet is itself an XML document, so we have to follow all of the document rules we discussed in the previous chapter.To transform the XML document using the XSLT stylesheet, run this command if you’re using Xalan:java org.apache.xalan.xslt.Process -in greeting.xml -xsl greeting.xsl -out greeting.html
For Saxon, the command looks like this:java net.sf.saxon.Transform -o greeting.html greeting.xml greeting.xsl
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Goals of This Chapter
- InhaltsvorschauBy the end of this chapter, you should know:
- How to create a basic stylesheet
- How to use a stylesheet to transform an XML document
- How a stylesheet processor uses a stylesheet to transform an XML document
- The structure of an XSLT stylesheet
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Transforming Hello World
- InhaltsvorschauContinuing the tradition of Hello World examples begun by Brian Kernighan and Dennis Ritchie in The C Programming Language (Prentice Hall, 1988), we’ll transform a Hello World XML document.First, we’ll look at our sample document. This simple XML document, courtesy of the XML 1.0 specification, contains the famous friendly greeting to the world:
<?xml version="1.0"?><!-- greeting.xml --> <greeting> Hello, World! </greeting>What we’d like to do is transform this fascinating document into something we can view in an ordinary household browser.Here’s an XSLT stylesheet that defines how to transform the XML document:<?xml version="1.0"?><!-- greeting.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <xsl:apply-templates select="greeting"/> </xsl:template> <xsl:template match="greeting"> <html> <body> <h1> <xsl:value-of select="."/> </h1> </body> </html> </xsl:template> </xsl:stylesheet>We’ll talk about these elements and what they do in just a minute. Keep in mind that the stylesheet is itself an XML document, so we have to follow all of the document rules we discussed in the previous chapter.To transform the XML document using the XSLT stylesheet, run this command if you’re using Xalan:java org.apache.xalan.xslt.Process -in greeting.xml -xsl greeting.xsl -out greeting.html
For Saxon, the command looks like this:java net.sf.saxon.Transform -o greeting.html greeting.xml greeting.xsl
If you’re using the Schema-aware version of Saxon, the name of the Java class is :java com.saxon.Transform -o greeting.html greeting.xml greeting.xsl
The command for the Altova XSLT engine is:altovaxml /xslt1 greeting.xsl /in greeting.xml /out greeting.html
Finally, if you’re using Microsoft’s MSXSL, type this command:msxsl greeting.xml greeting.xsl -o greeting.html
This command transforms the document greeting.xml, using the templates found in the stylesheetEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - How a Stylesheet Is Processed
- InhaltsvorschauNow that we’re giddy with the excitement of having transformed an XML document, let’s discuss the stylesheet and how it works. A big part of the XSLT learning curve is figuring out how stylesheets are processed. To make this clear, we’ll go through the steps taken by the stylesheet processor to create the HTML document we want.Before the XSLT processor can process your stylesheet, it has to read it. Conceptually, it doesn’t matter how the XSLT processor stores the information from your stylesheet. For our purposes, we’ll just assume that the XSLT processor can magically find anything it needs in our stylesheet. (If you really must know, Xalan uses an optimized table structure to represent the stylesheet; other processors may use that approach or something else.)Our stylesheet contains three items: an
<xsl:output>element that specifies HTML as the output format, and two<xsl:template>elements that specify how parts of our XML document should be transformed.Now that the XSLT processor has processed the stylesheet, it needs to read the document it’s supposed to transform. The XSLT processor builds a tree view from the XML source. This tree view is what we’ll keep in mind when we build our stylesheets.Finally, we’re ready to begin the actual work of transforming the XML document. The XSLT processor may set some properties based on your stylesheet (in the previous example, it would set its output method to HTML), then it begins processing as follows:- Do I have any nodes to process? The nodes to process are represented by the context. Initially, the context is the root of the XML document, but it changes throughout the stylesheet. We’ll talk about the context extensively in the next chapter. (Note: all XSLT processors enjoy being anthropomorphized, so I’ll often refer to them this way.)
While any nodes are in the context, do the following:- Get the next node from the context. Do I have any
<xsl:template>s that match it? (In our example, the next node is the root node, represented in XPath syntax by
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Stylesheet Structure
- InhaltsvorschauAs the final part of our introduction to XSLT, we’ll look at the contents of the stylesheet itself. We’ll explain all the things in our stylesheet and discuss other approaches we could have taken.The
<xsl:stylesheet>element is typically the root element of an XSLT stylesheet:<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
First of all, the<xsl:stylesheet>element defines the version of XSLT we’re using, along with a definition of thexslnamespace. To be compliant with the XSLT specification, your stylesheet should always begin with this element, coded exactly as shown here. Some stylesheet processors, notably Xalan, issue a warning message if your<xsl:stylesheet>element doesn’t have these two attributes with these two values. For all examples in this book, we’ll start the stylesheet with this exact element, defining other namespaces as needed.Next, we specify the output method. The XSLT specification defines three output methods:xml,html, andtext. We’re creating an HTML document, so HTML is the output method we want to use. In addition to these three methods, an XSLT processor is free to define its own output methods, so check your XSLT processor’s documentation to see if you have any other options:<xsl:output method="html"/>
A variety of attributes are used with the different output methods. For example, if you’re usingmethod="xml", you can usedoctype-publicanddoctype-systemto define the public and system identifiers to be used in the the document type declaration. If you’re usingmethod="xml"ormethod="html", you can use theindentattribute to control whether or not the output document is indented. The discussion of the element in has all the details.Our first template matches"/", the XPath expression for the document’s root element:<xsl:template match="/"> <xsl:apply-templates select="greeting"/> </xsl:template>
The second<xsl:template>element processes any<greeting>elements in our XML source document:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Sample Gallery
- InhaltsvorschauBefore we get into more advanced topics, we’ll transform our Hello World document in other ways. We’ll look through simple stylesheets that convert our small XML document into the following things:
- A Scalable Vector Graphics (SVG) file
- A PDF file
- A Java program
- A Virtual Reality Modeling Language (VRML) file
Our first example will convert our Hello World document into an SVG file:<?xml version="1.0"?><!-- svg-greeting.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg"> <xsl:template match="/"> <svg:svg width="10cm" height="4cm"> <svg:g> <svg:defs> <svg:radialGradient id="MyGradient" cx="4cm" cy="2cm" r="3cm" fx="4cm" fy="2cm"> <svg:stop offset="0%" style="stop-color:red"/> <svg:stop offset="50%" style="stop-color:blue"/> <svg:stop offset="100%" style="stop-color:red"/> </svg:radialGradient> </svg:defs> <svg:rect style="fill:url(#MyGradient); stroke:black" x="1cm" y="1cm" width="8cm" height="2cm"/> <svg:text x="5.05cm" y="2.25cm" text-anchor="middle" style="font-family:Verdana; font-size:24; font-weight:bold; fill:black"> <xsl:apply-templates select="greeting"/> </svg:text> <svg:text x="5cm" y="2.2cm" text-anchor="middle" style="font-family:Verdana; font-size:24; font-weight:bold; fill:white"> <xsl:apply-templates select="greeting"/> </svg:text> </svg:g> </svg:svg> </xsl:template> <xsl:template match="greeting"> <xsl:value-of select="."/> </xsl:template> </xsl:stylesheet>As you can see from this stylesheet, most of the code here simply sets up the structure of the SVG document. This is typical of many stylesheets; once you learn what the output format should be, you merely extract content from the XML source document and insert it into the output document at the correct spot. When we transform the Hello World document with this stylesheet, here are the results:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauAlthough our stylesheets here are trivial, they are much simpler than the corresponding procedural code (written in Visual Basic, C++, Java, etc.) to transform any
<greeting>elements similarly. We’ve gone over the basics of what stylesheets are and how they work.As we go through this book, we’ll demonstrate the incredible range of things you can do in XSLT stylesheets, including:- Using logic, branching, and control statements
- Sorting and grouping elements
- Linking and cross-referencing elements
- Creating master documents that embed other XML documents, then sort, filter, group, and format the combined documents.
- Adding new functions to the XSLT stylesheet processor with XSLT’s extension mechanism
XSLT has an extremely active user community. To see just how active, visit the XSL-List site at http://www.mulberrytech.com/xsl/xsl-list/index.html.Before we dive in to those topics, we need to talk about XPath, the syntax that describes what parts of an XML document we want to transform into all of these different things.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 3: XPath: A Syntax for Describing
- InhaltsvorschauXPath is a syntax used to describe parts of an XML document. With XPath, you can refer to the first
<para>element, thequantityattribute of the<part-number>element, all<first-name>elements that contain the text"Joe", and many other variations. In a stylesheet, the XSLT patterns in thematchandselectattributes of various elements use XPath syntax to indicate how a document should be transformed. In this chapter, we’ll discuss XPath in all its glory.XPath is designed to be used inside an attribute in an XML document. The syntax is a mix of basic programming language expressions (such as$x*6) and Unix-like path expressions (such as/sonnet/author/last-name). In addition to the basic syntax, XPath provides a set of useful functions that allow you to find out various things about the document.One important point, though: XPath works with the parsed version of your XML document. That means that some details of the original document aren’t accessible to you from XPath. For example, entity references are resolved by the XSLT processor before instructions in our stylesheet are evaluated. CDATA sections are converted to text as well. That means we have no way of knowing whether a text node in an XPath tree was in the original XML document as text, as an entity reference, or as part of a CDATA section. As you get used to thinking about your XML documents in terms of XPath expressions, this situation won’t be a problem, but it may confuse you at first.[2.0] XPath has undergone enormous changes for version 2.0. Everything that worked in XPath 1.0 still works in XPath 2.0, but there are new capabilities and operators that can greatly simplify your life if you’re using an XSLT 2.0 processor. There are three major XPath 2.0 topics that we’ll discuss separately in this chapter:- In XPath 2.0’s view of the world, everything is a sequence. A sequence replaces the concept of node-sets used in XPath 1.0. The main difference is that a sequence can contain atomic values (more on those in a minute). Be aware that nodes in the sequence (a document node, for example) can still have children. When we’re working with parts of a document, it’s common that our sequence is an element node with children and attributes; that one item sequence works just like the trees you know and love from XPath 1.0.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The XPath Data Model
- InhaltsvorschauXPath 1.0 views an XML document as a tree of nodes. This tree is very similar to a Document Object Model (DOM) tree, so if you’re familiar with the DOM, you should have some understanding of how to build basic XPath expressions. (To be precise, this is a conceptual tree; an XSLT processor or anything else that implements the XPath standard doesn’t have to build an actual tree.)[2.0] XPath 2.0 views everything as a sequence. A sequence can contain all of the nodes we cover here as well as atomic values. Whenever we’re working with parsed data from an XML document, the sequences we’re using are most likely nodes from the document tree, so we won’t have to worry about atomic values. For now, just be aware that the underlying data model in XPath 2.0 is different; we’ll cover those differences in great detail later in this chapter.There are seven kinds of nodes in XPath:
- The document node (one per document)
- Element nodes
- Attribute nodes
- Text nodes
- Comment nodes
- Processing instruction nodes
- Namespace nodes
We’ll talk about all the different node types in terms of the following document:<?xml version="1.0"?> <?xml-stylesheet href="sonnet.xsl" type="text/xsl"?> <!DOCTYPE sonnet [ <!ELEMENT sonnet (auth:author, title, lines)> <!ATTLIST sonnet public-domain CDATA "yes" type (Shakespearean | Petrarchan) "Shakespearean"> <!ELEMENT auth:author (last-name,first-name,nationality, year-of-birth?,year-of-death?)> <!ELEMENT last-name (#PCDATA)> <!ELEMENT first-name (#PCDATA)> <!ELEMENT nationality (#PCDATA)> <!ELEMENT year-of-birth (#PCDATA)> <!ELEMENT year-of-death (#PCDATA)> <!ELEMENT title (#PCDATA)> <!ELEMENT lines (line,line,line,line, line,line,line,line, line,line,line,line, line,line)> <!ELEMENT line (#PCDATA)> ]> <!-- Default sonnet type is Shakespearean, the other allowable --> <!-- type is "Petrarchan." --> <sonnet type='Shakespearean'> <auth:author xmlns:auth="http://www.authors.com/"> <last-name>Shakespeare</last-name> <first-name>William</first-name> <nationality>British</nationality> <year-of-birth>1564</year-of-birth> <year-of-death>1616</year-of-death> </auth:author> <!-- Is there an official title for this sonnet? They're sometimes named after the first line. --> <title>Sonnet 130</title> <lines> <line>My mistress' eyes are nothing like the sun,</line> <line>Coral is far more red than her lips red.</line> <line>If snow be white, why then her breasts are dun,</line> <line>If hairs be wires, black wires grow on her head.</line> <line>I have seen roses damasked, red and white,</line> <line>But no such roses see I in her cheeks.</line> <line>And in some perfumes is there more delight</line> <line>Than in the breath that from my mistress reeks.</line> <line>I love to hear her speak, yet well I know</line> <line>That music hath a far more pleasing sound.</line> <line>I grant I never saw a goddess go,</line> <line>My mistress when she walks, treads on the ground.</line> <line>And yet, by Heaven, I think my love as rare</line> <line>As any she belied with false compare.</line> </lines> </sonnet> <!-- The title of Sting's 1987 album "Nothing like the sun" is --> <!-- from line 1 of this sonnet. -->Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Location Paths
- InhaltsvorschauOne of the most common uses of XPath is to create location paths. A location path describes the location of something in an XML document. The pattern
/addressbook/address/citydescribes the location of the elements we want to select. We’ll use location paths as patterns to find parts of the XML document, then we’ll use XPath expressions to manipulate them. But before we dive in to the wonders of location paths, we need to discuss the context.One of the most important concepts in XPath is the context. Everything we do in XPath is interpreted with respect to the context. You can think of an XML document as a hierarchy of directories in a filesystem. In our sonnet example, we could imagine thatsonnetis a directory at the root level of the filesystem. Thesonnetdirectory would, in turn, contain directories namedauth:author,title, andlines. In this example, the context would be the current directory. If I go to a command line and execute a particular command (such asdir *.xsl), the results I get vary depending on the current directory. Similarly, the results of evaluating an XPath expression will probably vary based on the context.[1.0] The XPath 1.0 context
Most of the time, we can think of the context as the node in the tree from which any expression is evaluated. To be completely accurate, the context consists of five things:- The context node (the “current directory”). The XPath expression is evaluated from this node.
- Two integers, the context position and the context size. These integers are important when we’re processing a group of nodes. For example, we could write an XPath expression that selects all of the
<li>elements in a given document. The context size refers to the number of<li>items selected by that expression, and the context position refers to the position of the<li>we’re currently processing. - A set of variables. This set includes names and values of all variables that are currently in scope.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Attribute Value Templates
- InhaltsvorschauAlthough they’re technically defined in the XSLT specification (in XSLT 1.0 section 7.6.2 and XSLT 2.0 section 5.6), we’ll discuss attribute value templates here. An attribute value template (sometimes abbreviated as AVT) is an XPath expression that is evaluated, and the result of that evaluation replaces the attribute value template. For example, we could create an HTML
<table>element like this:<table border="{@size}"/>In this example, the XPath expression@sizeis evaluated, and its value, whatever that happens to be, is inserted into the output tree as the value of theborderattribute. Attribute value templates can be used in any literal result elements in your stylesheet (for HTML elements and other things that aren’t part of the XSLT namespace, for example). You can also use attribute value templates in the following XSLT attributes:- The
nameandnamespaceattributes of the element - The
nameandnamespaceattributes of the element - The
format,lang,letter-value,grouping-separator, andgrouping-sizeattributes of the element - The
nameattribute of the element - The
lang,data-type,order, andcase-orderattributes of the element
[2.0] XSLT 2.0 can use AVTs in several additional places:- The
regexandflagsattributes of the new element - The
name,namespace, andseparatorattributes of the element (just as in XSLT 1.0) - The
nameandnamespaceattributes of the element (just as in XSLT 1.0) - The
collationattribute of the new element - The
terminateattribute of the element - The
nameattribute of the element - The
format,lang,letter-value,ordinal,grouping-separator, andgrouping-sizeattributes of the element (ordinalis new in XSLT 2.0; all the others are unchanged from XSLT 1.0) - The
nameattribute of the element - The
format,href,method,byte-order-mark,cdata-section-elements,doctype-public,doctype-system,encoding,escape-uri-attributes,include-content-type,indent,media-type,normalization-form,omit-xml-declaration,standalone,undeclare-prefixes, andoutput-version
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Datatypes
- InhaltsvorschauOne of the major additions to XPath 2.0 is support for the XML Schema datatype system. The XPath 1.0 and 2.0 data models are so different we’ll discuss them in separate sections. In general, most statements that worked in XPath 1.0 still work in XSLT 2.0. On the other hand, any XPath 2.0 statement that uses the new datatyping features won’t work at all in XPath 1.0.In XPath 1.0, an expression returns one of four datatypes:
node-set- Represents a set of nodes. The set can be empty or it can contain any number of nodes.
boolean- Represents the value
trueorfalse. Be aware that thetrueorfalsestrings have no special meaning or value in XPath; see ” in for a more detailed discussion of these. number- Represents a floating-point number. All numbers in XPath and XSLT are implemented as floating-point numbers; the
integer(orint) datatype does not exist in XPath and XSLT. Specifically, all numbers are implemented as IEEE 754 floating-point numbers, which is the same standard used by the Javafloatanddoubleprimitive types. In addition to ordinary numbers, there are five special values for numbers: positive and negative infinity, positive and negative zero, andNaN, the special symbol for anything that is not a number. string- Represents zero or more characters, as defined in the XML specification.
These datatypes are usually simple, and with the exception of node-sets, converting between types is usually straightforward. We won’t discuss these datatypes in any more detail here; instead, we’ll discuss datatypes and conversions as we need them to do specific tasks.The XPath 2.0 data model is perhaps the most significant change to writing XSLT version 2.0 stylesheets. We’ll cover the datatypes supported by XPath 2.0. XPath 2.0 supports all of the basic datatypes defined in XML Schema, and a schema-aware XSLT 2.0 processor lets you create your own datatypes. We’ll start with the basic datatypes;Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - XPath Operators
- InhaltsvorschauXPath supports a number of operators that make your expressions more powerful. We’ll look at each of them here.[1.0] The first two sections here cover all of the XPath 1.0 operators except the vertical bar (
|), the union operator. Only the vertical bar is supported in XPath 1.0; the newunionkeyword is supported only in XPath 2.0. See the section ” later in this chapter for the details of the union operator (|) and theunionkeyword.[2.0] In XPath 2.0, some operators work with dates, times, and durations. For example, you can add 12 hours to anxs:dayTimeDurationif you want. We cover the operators and features specific to XPath 2.0 after looking at the features common to XPath 1.0 and 2.0.The mathematical operators available in XPath are pretty limited. We’ll use two stylesheets to illustrate how the operators work; the first indicates how an operator works in XSLT 1.0 and the second indicates how it works in XSLT 2.0. We’ll cover the stylesheets in detail for the first operator (the plus sign), then simply refer to those examples throughout this section.Addition (+)
The plus sign adds two numbers.[1.0] In an XSLT 1.0 stylesheet, the processor attempts to convert each operand to a number. The following XPath expressions all work in XPath 1.0:<?xml version="1.0"?><!-- addition-1_0.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>Tests of addition in XPath 1.0
</xsl:text> <xsl:text>
 9 + 3 = </xsl:text> <xsl:value-of select="9 + 3"/> <xsl:text>
 9 + 3.8 = </xsl:text> <xsl:value-of select="9 + 3.8"/> <xsl:text>
 9 + '4' = </xsl:text> <xsl:value-of select="9 + '4'"/> <xsl:text>
 9 + 'Q' = </xsl:text> <xsl:value-of select="9 + 'Q'"/> <xsl:text>
 9 + true() = </xsl:text> <xsl:value-of select="9 + true()"/> <xsl:text>
 9 + false() = </xsl:text> <xsl:value-of select="9 + false()"/> </xsl:template> </xsl:stylesheet>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] Comments in XPath Expressions
- InhaltsvorschauAnother addition to the XPath 2.0 syntax is the ability to add comments. Using delightfully happy syntax, a comment begins with
(:and ends with:). We’ll use a stylesheet with a complicatedifstatement:<?xml version="1.0"?><!-- comments.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:for-each select="cars/make"> <xsl:text>
 Car: </xsl:text> <xsl:value-of select="."/> <xsl:text> - </xsl:text> <xsl:value-of select="(: Most of our cars are from North America, so we look there first :) if (@geography = 'North America') then 'Domestic car' (: Next, see if the car is from Europe :) else if (@geography = 'Europe') then 'Import from Europe' (: Check for Asia :) else if (@geography = 'Asia') then "It's from Asia" (: If it's anything else, just say 'We don't know' :) else 'We don''t know!'"/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
The stylesheet has threeifstatements that check the value of thegeographyattribute of an element. We’ve used spacing and comments liberally here to make the code more legible. In the last comment, you can see that we don’t have to escape quote marks inside the comment, although we do have to handle them appropriately outside the comment. For one quote that contains an apostrophe, we wrap the text in double quotes ("It's from Asia"). For the next quote, we use a doubled apostrophe ('We don''t know!') to display the text.Here’s the XML document we’ll transform:<?xml version="1.0"?><!-- carlist-geography.xml --> <cars> <make geography="Europe">Alfa Romeo</make> <make geography="Europe">Bentley</make> <make geography="North America">Chevrolet</make> <make geography="North America">Dodge</make> <make geography="North America">GMC</make> <make geography="Asia">Honda</make> <make geography="Asia">Isuzu</make> <make geography="?">Quantum</make> </cars>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] Types of XSLT 2.0 Processors
- InhaltsvorschauThe XSLT 2.0 spec defines two types of XSLT 2.0 processors:
- Schema-aware processors
- A schema-aware XSLT 2.0 processor supports user-defined schemas. In other words, we can use XML Schema to define our own datatypes and document structures, then ask the processor to validate values or nodes against that schema.
- Basic processors
- A basic XSLT 2.0 processor supports only the datatypes defined in the XML Schema Datatypes spec, with a few extra datatypes added by the XPath 2.0 and XQuery 1.0 Data Model spec. We covered all of those datatypes earlier in this chapter.
For a brief introduction to XML Schema, as well as a short discussion of how schemas are used in XSLT 2.0 stylesheets, see .Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The XPath View of an XML Document
- InhaltsvorschauBefore we leave the subject of XPath, we’ll look at a stylesheet that generates a pictorial view of a document. The stylesheet has to distinguish between all of the different XPath node types, including any
namespacenodes.shows the output of our stylesheet. In this graphical view of the document, the nested HTML tables illustrate which nodes are contained inside of others, as well as the sequence in which these nodes occur in the original document. In the section of the document visible in , the root of the document contains, in order, two processing instructions and two comments, followed by the<sonnet>element and two more comments. The<sonnet>element, in turn, contains two attributes and an<auth:author>element. The<auth:author>element contains a namespace node and .Be aware that if you throw a very large XML document at this stylesheet, you’ll get an HTML file with hundreds, perhaps thousands of tables. It’s possible that your XSLT processor will run out of memory before it’s finished with the document. For example, using this stylesheet to process the XML source of the Function Reference appendix creates an HTML file with more than 17,000 tables.
Figure : XPath tree view of an XML documentNow we’ll take a look at the stylesheet and how it works. The stylesheet creates a number of nested tables to illustrate the XPath view of the document. We begin by writing the basic HTML elements to the output stream, defining some CSS styles and creating a legend for our nested tree view. Having created the legend for our document, we select all the different types of nodes and represent them:<xsl:for-each select="*|comment()|processing-instruction()|text()"> ... </xsl:for-each>It’s very important to understand the difference between the XPath document root and the XML root element. In our XML sonnet, there are processing instructions and comments outside the root element. The document root contains those processing instructions and comments in addition to theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauWe’ve covered the basics of XPath. Hopefully, at this point you’re comfortable with the idea of writing XPath expressions to describe parts of an XML document. As we go through the following chapters, you’ll see XPath expressions used in a variety of ways, all of which build on the basics we’ve discussed here. When you’re debugging a stylesheet, you’ll probably spend most of your time making sure your XPath expressions select the right data. Very few of the things we’ll do in the rest of the book are possible without precise XPath expressions.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 4: Creating Output
- InhaltsvorschauBy the end of this chapter, you should know how to:
- Generate text
- Number things, including numbering at multiple levels
- Format numbers
- [2.0] Format dates and times
- Use
<xsl:copy>and<xsl:copy-of>to copy nodes from the input document to the output document - Deal with whitespace
The first thing we’ll cover is how to put text in the output. Just putting some text out there is simple enough, but we’ll look at some more advanced techniques that we’ll explore throughout the book. We’ll look at two elements in particular:<xsl:text>and<xsl:value-of>. We’ll use these to create an HTML document that contains a table of contents for an XML document. Here’s the XML document we’ll use:<?xml version="1.0"?><!-- toc_source.xml --> <article> <title>Creating output</title> <body> <heading1>Generating text</heading1> <heading1>Numbering things</heading1> <heading1>Formatting numbers</heading1> <heading1>Copying nodes from the input document to the output</heading1> <heading1>Handling whitespace</heading1> </body> </article>There are many times you need to write some text to the output. In the first example we’ll build in this chapter, we want to create HTML that looks like this:<h1>Table of Contents</h1> <h2>Generating text</h2> <h2>Numbering things</h2> <h2>Formatting numbers</h2> <h2>Copying nodes from the input document to the output</h2> <h2>Handling whitespace</h2>
In this output document, the text of each item in the table is the text of a particular element in the XML source. The textTable of Contents, however, is the same each time. To generate this text, we’ll use the<xsl:text>element. We’ll start our stylesheet by generating that text:<xsl:template match="/"> <h1> <xsl:text>Table of Contents</xsl:text> </h1> ... </xsl:template>All we did here was insert a string in our output document. To make things even simpler, we could have done this:<xsl:template match="/"> <h1>Table of Contents</h1> ... </xsl:template>
For any non-XSLT element in a stylesheet (Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Goals of This Chapter
- InhaltsvorschauBy the end of this chapter, you should know how to:
- Generate text
- Number things, including numbering at multiple levels
- Format numbers
- [2.0] Format dates and times
- Use
<xsl:copy>and<xsl:copy-of>to copy nodes from the input document to the output document - Deal with whitespace
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Generating Text
- InhaltsvorschauThe first thing we’ll cover is how to put text in the output. Just putting some text out there is simple enough, but we’ll look at some more advanced techniques that we’ll explore throughout the book. We’ll look at two elements in particular:
<xsl:text>and<xsl:value-of>. We’ll use these to create an HTML document that contains a table of contents for an XML document. Here’s the XML document we’ll use:<?xml version="1.0"?><!-- toc_source.xml --> <article> <title>Creating output</title> <body> <heading1>Generating text</heading1> <heading1>Numbering things</heading1> <heading1>Formatting numbers</heading1> <heading1>Copying nodes from the input document to the output</heading1> <heading1>Handling whitespace</heading1> </body> </article>There are many times you need to write some text to the output. In the first example we’ll build in this chapter, we want to create HTML that looks like this:<h1>Table of Contents</h1> <h2>Generating text</h2> <h2>Numbering things</h2> <h2>Formatting numbers</h2> <h2>Copying nodes from the input document to the output</h2> <h2>Handling whitespace</h2>
In this output document, the text of each item in the table is the text of a particular element in the XML source. The textTable of Contents, however, is the same each time. To generate this text, we’ll use the<xsl:text>element. We’ll start our stylesheet by generating that text:<xsl:template match="/"> <h1> <xsl:text>Table of Contents</xsl:text> </h1> ... </xsl:template>All we did here was insert a string in our output document. To make things even simpler, we could have done this:<xsl:template match="/"> <h1>Table of Contents</h1> ... </xsl:template>
For any non-XSLT element in a stylesheet (<h1>, for example), XSLT’s default behavior is to simply pass that element to the output. Normally we’ll use<xsl:text>when we need complete control over whitespace or when we’re creating text output instead of a marked-up document such as an HTML file.In these examples, we simply wrote text to our output document; most often we’ll combine text with values from our source document. For example, we might want to generate an HTML document that looks like this:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Numbering Things
- InhaltsvorschauXSLT provides the
<xsl:number>element to number the parts of a document. (It can also be used to format a numeric value; more on that later.) In general,<xsl:number>counts something. We’ll look at a variety of examples here.To fully illustrate how<xsl:number>works, we’ll need an XML document with some things to count. We’ll reuse our list of cars from the previous section:<?xml version="1.0" encoding="utf-8"?><!-- cars.xml --> <cars> <manufacturer name="Chevrolet"> <car>Cavalier</car> <car>Corvette</car> <car>Impala</car> <car>Malibu</car> </manufacturer> <manufacturer name="Ford"> <car>Pinto</car> <car>Mustang</car> <car>Taurus</car> </manufacturer> <manufacturer name="Volkswagen"> <car>Beetle</car> <car>Jetta</car> <car>Passat</car> <car>Touraeg</car> </manufacturer> </cars>We’ll use<xsl:number>in several different ways to illustrate the various options we have in numbering things. We’ll start with something simple:<?xml version="1.0" encoding="utf-8"?><!-- number1.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title>Automobile manufacturers and their cars</title> </head> <body> <xsl:for-each select="cars/manufacturer"> <p> <xsl:number format="1. "/> <xsl:value-of select="@name"/> </p> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet>We get this HTML document:<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Automobile manufacturers and their cars</title> </head> <body> <p>1. Chevrolet</p> <p>2. Ford</p> <p>3. Volkswagen</p> </body> </html>This is about the simplest example of<xsl:number>that you can write. (You could leave off theformatattribute, but you’d get paragraphs such as<p>1Chevrolet</p>—probably not what you want.) Changing the stylesheet to useEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Formatting Decimal Numbers
- InhaltsvorschauWe’ve already seen several ways of formatting decimal numbers using
<xsl:number>. However, if we’re going to work with numbers, we’ll almost certainly have to deal with decimals. XSLT defines theformat-number( )function and the<xsl:decimal-format>element to do just that. We’ll use<xsl:decimal-format>to define a pattern for formatting numbers, and then we’ll useformat-number( )to apply a pattern to a number.This stylesheet has several examples of<xsl:decimal-format>andformat-number( ):<?xml version="1.0" encoding="utf-8"?><!-- decimal-format.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <!-- This format has no name, so it's assumed to be the default. --> <xsl:decimal-format decimal-separator="," grouping-separator="."/> <xsl:decimal-format name="us_default"/> <xsl:decimal-format name="other_options" NaN="[not a number]" infinity="unfathomably huge"/> <xsl:decimal-format name="hash_mark" digit="!"/> <xsl:template match="/"> <xsl:text>
Tests of <xsl:decimal-format> and </xsl:text> <xsl:text>format-number():</xsl:text> <xsl:text>

 1. format-number(3728493.3882, </xsl:text> <xsl:text>'#.###,##') : </xsl:text> <xsl:value-of select="format-number(3728493.3882, '#.###,##')"/> <xsl:text>

 2. format-number(3728493.3882, </xsl:text> <xsl:text>'#,###.##', 'us_default') : </xsl:text> <xsl:value-of select="format-number(3728493.3882, '#,###.##', 'us_default')"/> <xsl:text>

 3. format-number(number(1) div 0, '#.#') : </xsl:text> <xsl:value-of select="format-number(number(1) div 0, '#.#')"/> <xsl:text>

 4. format-number(number(1) div 0, '#.#', </xsl:text> <xsl:text>'other_options') : 
 </xsl:text> <xsl:value-of select="format-number(number(1) div 0, '#.#', 'other_options')"/> <xsl:text>

 5. format-number(number('blue') * </xsl:text> <xsl:text>number('orange'), '#') : </xsl:text> <xsl:value-of select="format-number(number('blue') * number('orange'), '#')"/> <xsl:text>

 6. format-number(number('blue') * </xsl:text> <xsl:text>number('orange'), '#', 'other_options') : </xsl:text> <xsl:text>
 </xsl:text> <xsl:value-of select="format-number(number('blue') * number('orange'), '#', 'other_options')"/> <xsl:text>

 7. format-number(42, '#!', </xsl:text> <xsl:text>'hash_mark') : </xsl:text> <xsl:value-of select="format-number(42, '#!', 'hash_mark')"/> </xsl:template> </xsl:stylesheet>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] Formatting Dates and Times
- InhaltsvorschauXSLT 2.0 adds three new formatting functions,
format-date( ),format-time( ), andformat-dateTime( ). We’ll takexs:date,xs:time, andxs:dateTimevalues and format them in some useful way.You can call each of these functions in two ways. The simplest is to pass the function a value and a formatting string. If you need more detail, the second way of calling these functions requires you to specify a language, a calendar, and a country as well. The XSLT 2.0 specification lists more than 25 different calendars used around the world, and there are hundreds of combinations of language and country codes. Look at the documentation for your XSLT processor to see which calendars, languages, and countries it supports.Our first example is pretty simple. We’ll create a stylesheet that uses the XPath functionscurrent-date( ),current-time( ), andcurrent-dateTime( ):<?xml version="1.0" encoding="utf-8"?><!-- datetime1.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>
Tests of date and time formatting:
</xsl:text> <xsl:text>
 The current date is </xsl:text> <xsl:value-of select="format-date(current-date(), '[M01]/[D01]/[Y0001]')"/> <xsl:text>
 The current time is </xsl:text> <xsl:value-of select="format-time(current-time(), '[H01]:[m01] [z]')"/> <xsl:text>
 It's currently </xsl:text> <xsl:value-of select="format-dateTime(current-dateTime(), '[h1]:[m01] [P] on [MNn] [D].')"/> </xsl:template> </xsl:stylesheet>This stylesheet produces this text:Tests of date and time formatting: The current date is 03/08/2006 The current time is 22:27 GMT-5 It's currently 10:27 p.m. on March 8.
In this stylesheet,M01produces the two-digit month,D01produces the two-digit day, andY0001produces the four-digit year.H01produces the 2-digit hour in a 24-hour clock,m01produces the 2-digit minutes,Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using <xsl:copy> and <xsl:copy-of>
- InhaltsvorschauAs you transform your XML input document into something else, you’ll often want to just copy a given element to the output document. XSLT provides two elements that do this:
<xsl:copy>and<xsl:copy-of>. We’ll discuss them here and go through several stylesheets that use these elements to create output.To start our examples, we’ll look at a stylesheet that generates a document equal to the input document. (This is sometimes called an identity transform.) The stylesheet is short and sweet:<?xml version="1.0"?><!-- copy-of.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <xsl:copy-of select="*"/> </xsl:template> </xsl:stylesheet>That’s all we have to do. Our template simply says to start with the document element of the input document and copy it to the output.<xsl:copy-of>does a deep copy of a node, so the root node and all of its children are copied to the output. If any of the root node’s descendants are element nodes with attributes, the attributes are copied as well. (Remember, an element’s attributes aren’t considered children.)We’ll test our stylesheet against this document:<?xml version="1.0"?><!-- sonnet.xml --> <sonnet type='Shakespearean'> <auth:author xmlns:auth="http://www.authors.com/"> <last-name>Shakespeare</last-name> <first-name>William</first-name> <nationality>British</nationality> <year-of-birth>1564</year-of-birth> <year-of-death>1616</year-of-death> </auth:author> <!-- Is there an official title for this sonnet? They're sometimes named after the first line. --> <title>Sonnet 130</title> <lines> <line>My mistress' eyes are nothing like the sun,</line> <line>Coral is far more red than her lips red.</line> <line>If snow be white, why then her breasts are dun,</line> <line>If hairs be wires, black wires grow on her head.</line> <line>I have seen roses damasked, red and white,</line> <line>But no such roses see I in her cheeks.</line> <line>And in some perfumes is there more delight</line> <line>Than in the breath that from my mistress reeks.</line> <line>I love to hear her speak, yet well I know</line> <line>That music hath a far more pleasing sound.</line> <line>I grant I never saw a goddess go,</line> <line>My mistress when she walks, treads on the ground.</line> <line>And yet, by Heaven, I think my love as rare</line> <line>As any she belied with false compare.</line> </lines> </sonnet>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Dealing with Whitespace
- InhaltsvorschauOne of the challenges of working with any XML document is processing whitespace, especially when want want to generate output other than HTML. As we noted earlier, an HTML browser renders both of these paragraphs the same way:
<p> This document contains 5 chapters. </p> <p>This document contains 5 chapters.</p>
If we generated these two paragraphs as text, however, they would appear as differently in print as they do in the HTML source. We’ll look at several techniques for controlling whitespace in this section.Before we begin, it’s worth defining the four characters that the XML spec defines as whitespace:- The tab character (
	) - The newline character (

) - The carriage return character (

) - The space character (
 )
We’ll use this modified version of our car list to illustrate how XML parsers and XSLT processors work with whitespace:<?xml version="1.0" encoding="utf-8"?><!-- carlist_whitespace.xml --> <cars> <manufacturer name=" Chevrolet "> <car>Cavalier</car> <car>Corvette</car> <car>Impala</car> <car>Monte Carlo</car> </manufacturer> </cars>From an XML parser’s perspective, there are a number of whitespace-only nodes (nodes that contain only whitespace characters) in this document. The<cars>element contains a whitespace-only node with the newline character and the tab or spaces before the<manufacturer>tag, the node for the<manufacturer>element, and a whitespace-only node with the newline character after the</manufacturer>tag. Similarly, the<manufacturer>element contains whitespace-only nodes between the various<car>.The XML parser doesn’t remove any whitespace-only nodes, so we can always use them in our stylesheets. Put another way, the data model used by the XSLT processor contains the whitespace-only nodes from the XML source. The one exception to this is in an XSLT 2.0 processor that validates the XML source against a schema. If the schema indicates that an element can only contain other elements, any whitespace-only nodes contained in those elements are removed.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauThis chapter has covered the various ways you can generate output from your XSLT stylesheets. You’ll use those basic techniques in every stylesheet you write. The main challenge as we go forward is learning how to select and organize the elements you want to process. You might need logic to select elements that have certain properties or you might need to sort or group elements before you process them. You might need to use special functions not defined in XSLT or XPath. You might need to write output to more than one document. Future chapters will address all of those topics.Whatever your stylesheet does, you’ll ultimately use the output methods in this chapter.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 5: Branching and Control Elements
- InhaltsvorschauSo far, we’ve done some straightforward transformations and we’ve been able to do some reasonably sophisticated things. To do truly useful work, though, we’ll need to use logic in our stylesheets. In this chapter, we’ll discuss the XSLT elements that allow you to do just that. Although you’ll see several XML elements that look like constructs from other programming languages, they’re not exactly the same. As we go along, we’ll discuss what makes XSLT different and how to do common tasks with your stylesheets.By the end of this chapter, you should:
- Know the XSLT elements used for branching and control
- Understand the differences between XSLT’s branching elements and similar constructs in other programming languages
- Know how to invoke XSLT templates by name and how to pass parameters to them, if you want
- Know how to use XSLT variables
- Understand how changes in XSLT 2.0 affect the way parameters and variables work
- Understand how to use recursion to get around the “limitations” of XSLT’s branching and control elements
Three XSLT elements are used for branching:<xsl:if>,<xsl:choose>, and<xsl:for-each>. The first two are much like theifandcasestatements you may be familiar with from other languages, but thefor-eachelement is significantly different from theforordo-whilestructures in other languages. We’ll discuss all of them here.The<xsl:if>element looks like this:<xsl:if test="count(zone) > 2"> <xsl:text>Applicable zones: </xsl:text> <xsl:apply-templates select="zone"/> </xsl:if>
The<xsl:if>element, surprisingly enough, implements anifstatement. The element has only one attribute:test. If the value oftestevaluates to the boolean valuetrue, then all elements inside the<xsl:if>are processed. Iftestevaluates tofalse, then the contents of the<xsl:if>element are ignored. (If you want to implement an if-then-else statement, see the section ” later in this chapter.)Notice that we used the character>in the value of thetestattribute. If you need to use the less-than operator (Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Goals of This Chapter
- InhaltsvorschauBy the end of this chapter, you should:
- Know the XSLT elements used for branching and control
- Understand the differences between XSLT’s branching elements and similar constructs in other programming languages
- Know how to invoke XSLT templates by name and how to pass parameters to them, if you want
- Know how to use XSLT variables
- Understand how changes in XSLT 2.0 affect the way parameters and variables work
- Understand how to use recursion to get around the “limitations” of XSLT’s branching and control elements
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Branching Elements of XSLT
- InhaltsvorschauThree XSLT elements are used for branching:
<xsl:if>,<xsl:choose>, and<xsl:for-each>. The first two are much like theifandcasestatements you may be familiar with from other languages, but thefor-eachelement is significantly different from theforordo-whilestructures in other languages. We’ll discuss all of them here.The<xsl:if>element looks like this:<xsl:if test="count(zone) > 2"> <xsl:text>Applicable zones: </xsl:text> <xsl:apply-templates select="zone"/> </xsl:if>
The<xsl:if>element, surprisingly enough, implements anifstatement. The element has only one attribute:test. If the value oftestevaluates to the boolean valuetrue, then all elements inside the<xsl:if>are processed. Iftestevaluates tofalse, then the contents of the<xsl:if>element are ignored. (If you want to implement an if-then-else statement, see the section ” later in this chapter.)Notice that we used the character>in the value of thetestattribute. If you need to use the less-than operator (<), you’ll have to use the<entity. The same holds true for the less-than-or-equal operator (<=).Converting to boolean values
The<xsl:if>element is pretty simple, but it’s the first time we’ve had to deal with boolean values. These values will come up later, so we might as well discuss them here. Attributes such as thetestattribute of the<xsl:if>element convert whatever their values happen to be into a boolean value. If that boolean value istrue, the<xsl:if>element is processed. (The<xsl:when>element, which we’ll discuss in the section ” later in this chapter, has atestattribute as well.)[1.0] Here’s the rundown of how various datatypes are converted to boolean values:- number
- If a number is positive or negative zero, it is
false. If a numeric value isNaN(not a number; if I try to use the string “blue” as a number, the result isNaN), it isfalse. If a number has any other value, it is
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Invoking Templates by Name
- InhaltsvorschauUp to this point, we’ve always used XSLT’s
<xsl:apply-templates>element to invoke other templates. You can think of this as a limited form of polymorphism; a single instruction is invoked a number of times, and the XSLT processor uses each node in the node-set to determine which<xsl:template>to invoke. Most of the time, this is what we want. However, sometimes we want to invoke a particular template. XSLT allows us to do this with the<xsl:call-template>element.To invoke a template by name, two things have to happen:- The template you want to invoke has to have a
name. - You use the
<xsl:call-template>element to invoke the named template.
Here’s how to do this. Say we have a template named createMasthead that creates the masthead of a web page. Whenever we create an HTML page for our web site, we want to invoke the createMasthead template to create the masthead. Here’s what our stylesheet would look like:<xsl:template name="createMasthead"> <!-- interesting stuff that generates the masthead goes here --> </xsl:template> ... <xsl:template match="/"> <html> <head> <title><xsl:value-of select="title"/></title> </head> <body><xsl:call-template name="createMasthead"/> ...Named templates are extremely useful for defining commonly used markup. For example, say you’re using an XSLT stylesheet to create web pages with a particular look and feel. You can write named templates that create the header, footer, navigation areas, or other items that define how your web page will look. Every time you need to create a web page, simply use<xsl:call-template>to invoke those templates and create the look and feel you want.Even better, if you put those named templates in a separate stylesheet and import the stylesheet (with either<xsl:import>or<xsl:include>), you can create a set of stylesheets that generate the look and feel of the web site you want. If you decide to redesign your web site, redesign the stylesheets that define the common graphical and layout elements. Change those stylesheets, regenerate your web site, and voila! You will see an instantly updated web site.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Parameters
- InhaltsvorschauThe XSLT
<xsl:param>and<xsl:with-param>elements allow you to pass parameters to a template. You can pass templates with either the<call-template>element or the<apply-templates>element; we’ll discuss the details in this section.To define a parameter in a template, use the<xsl:param>element. Here’s an example of a template that defines two parameters:<xsl:template name="calcuateArea"> <xsl:param name="width"/> <xsl:param name="height"/> <xsl:value-of select="$width * $height"/> </xsl:template>
Conceptually, this is a lot like writing code in a traditional programming language, isn’t it? Our template here defines two parameters,widthandheight, and outputs their product.If you want, you can define a default value for a parameter. There are two ways to define a default value; the simplest is to use aselectattribute on the<xsl:param>element:<template name="addTableCell"> <xsl:param name="bgColor" select="'blue'"/> <xsl:param name="width" select="150"/> <xsl:param name="content"/> <td width="{$width}" bgcolor="{$bgColor}"> <xsl:apply-templates select="$content"/> </td> </template>In this example, the default values of the parametersbgColorandwidthare'blue'and150, respectively. If we invoke this template without specifying values for these parameters, the default values are used. Also notice that we generated the values of thewidthandbgcolorattributes of the HTML<td>tag with attribute value templates, the values in curly braces. For more information, see the section ” in .One thing to note about this example is that thecontentparameter doesn’t have a default value here; we’re assuming thatcontentcontains the nodes to be processed and put inside the table cell. If the value ofcontentis an empty string, calling<xsl:apply-templates select="$content"/>causes an error. To be on the safe side, we could add an<xsl:if>element here to create an empty table cell ifcontentis an empty string. As an exercise for the reader, feel free to make this code more robust....Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Variables
- InhaltsvorschauIf we use logic to control the flow of our stylesheets, we’ll probably want to store temporary results along the way. In other words, we’ll need to use variables. XSLT provides the
<xsl:variable>element, which allows you to store a value and associate it with a name.The<xsl:variable>element can be used in three ways. The simplest form of the element creates a new variable whose value is an empty string (""). Here’s how it looks:<xsl:variable name="x"/>
This element creates a new variable namedx, whose value is an empty string. (Please hold your applause until the end of the section.)You can also create a variable by adding aselectattribute to the<xsl:variable>:<xsl:variable name="favouriteColour" select="'blue'"/>
In this case, we’ve set the value of the variable to be the string “blue”. Notice that we put single quotes around the value. These quotes ensure that the literal valueblueis used as the value of the variable. If we had left out the single quotes, this would mean the value of the variable is the node-set (or sequence) of all the<blue>elements in the context node, which definitely isn’t what we want here.Be aware that single quotes around numeric values are significant. The value35represents a numeric value (it’s a number in XSLT 1.0, and anxs:integerin XSLT 2.0), while the value'35'represents the string35. That might seem like a minor distinction, but it has a major impact on how your stylesheet works, especially in XSLT 2.0.The third way to use the<xsl:variable>element is to put content inside it. Here’s a brief example:<xsl:variable name="y"> <xsl:choose> <xsl:when test="$x > 7"> <xsl:text>13</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>15</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:variable>In this more complicated example, the content of the variableydepends on the test attribute of the<xsl:when>element. This is the equivalent of this procedural programming construct:int y; if (x > 7) y = 13; else y = 15;
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using Recursion to Do Most Anything
- InhaltsvorschauWriting an XSLT stylesheet is different from programming in other languages. If you didn’t believe that before, you probably do now. We’ll finish this chapter with a couple of examples that demonstrate how to use recursion to solve the kinds of problems that you’re probably used to solving with procedural programming languages. We’ll also look at some new features of XSLT 2.0 and XPath 2.0 that allow you to avoid recursion in some situations.To demonstrate how to use recursion to solve problems, we’ll write a string replace function. This is sometimes useful when you need to escape certain characters or substrings in your output. The stylesheet we’ll develop here transforms an XML document into a set of SQL statements that will be executed at a Windows command prompt. We have to do several things:
- Put a caret (
^) in front of all ampersands (&) - On the Windows NT and Windows 2000 command prompt, the ampersand means that the current command has ended and another is beginning. For example, this command creates a new directory called xslt and changes the current directory to the newly created one:
mkdir xslt & chdir xslt
If we create a SQL statement that contains an ampersand, we’ll need to escape the ampersand so it’s processed as a literal character, not as an operator. If we insert the valueJones & Sonas the value of the company field in a row of the database, we need to change it toJones ^& Sonbefore we try to run the SQL command. - Put a caret (
^) in front of all vertical bars (|) - The vertical bar is the pipe operator on Windows systems, so we need to escape it if we want it interpreted as literal text instead of an operator.
- Replace any single quote (
') with two single quotes ('') - This is a requirement of our database system.
Procedural design
Three functions we could use in our template areconcat( ),substring-before( ), andsubstring-after( ). To replace an ampersand with a caret and an ampersand, this would do the trick:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Put a caret (
- A Stylesheet That Emulates a for Loop
- InhaltsvorschauWe stressed earlier that the
xsl:for-eachelement is not aforloop; it’s merely an iterator across a group of nodes. However, if you simply must implement aforloop, there’s a way to do it. (Get ready to use recursion, though.)Our design here is to create a named template that will take some arguments, and then act as aforloop processor. If you think about a traditionalforloop, it has several :- One or more initialization statements
- These statements are processed before the
forloop begins. Typically the initialization statements refer to an index variable that is used to determine whether the loop should continue. - An increment statement
- This statement specifies how the index variable should be updated after each pass through the loop.
- A boolean expression
- If the expression is
true, the loop continues; if it is everfalse, the loop exits.
Let’s take a sample from the world of Java and C++:for (int i=0; i<length; i++)
In this scintillating example, the initialization statement isi=0, the index variable (the variable whose value determines whether we’re done or not) isi, the boolean expression we use to test whether the loop should continue isi<length, and the increment statement isi++.For our purposes here, we’re going to make several simplifying assumptions. (Feel free, dear reader, to make the example as complicated as you wish.) Here are the shortcuts we’ll take:- Rather than use an initialization statement, we’ll require the caller to set the value of the local variable
iwhen it invokes ourforloop processor. This value is passed as a parameter, so it can be calculated by an XPath expression. - Rather than specify an increment statement such as
i++, we’ll require the caller to set the value of the local variableincrement. The default value for this variable is1; it can be any negative or positive integer, however. The value of this variable will be added to the current value of
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauWe’ve covered a lot of ground in this chapter, haven’t we? We’ve gone over all of the basic elements you need to add logic and branching to your stylesheets. We discussed some of the similarities between XSLT and other programming languages you might know; more importantly, we discussed how XSLT is different from most of the code you’ve probably written. In particular, the use of recursion and the principles of variables that don’t change takes some getting used to. Despite the learning curve, most of the common tasks you’ll need to do will be similar to the exercises we’ve gone through in this chapter. Now that we’ve covered these basic elements, we’ll talk about links and references, discovering ways to build links between different parts of an XML .Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 6: Creating Links and Cross-References
- InhaltsvorschauIf you’re creating a web site, publishing a book, or processing an XML-based purchase order, chances are many pieces of information will refer to other things. This chapter discusses several ways to link XML elements. It reviews three techniques:
- Using the XML
ID,IDREF, andIDREFSdatatypes - Doing more advanced linking with the
key( )function - Generating links in unstructured documents
Our first attempt at linking will be with the XPathid( )function. This useful function helps us find the element that has anIDattribute with a particular value.Three of the basic datatypes that are supported by XML Document Type Definitions (DTDs) and XML Schemas areID,IDREF, andIDREFS. TheIDandIDREFdatatypes work according to two rules:- Every attribute of datatype
IDmust be unique. - Every value of datatype
IDREFmust match a value of an attribute of datatypeIDsomewhere in the document.
An attribute with a datatype ofIDREFScontains one or more space-separated values, each of which must match a value of anIDelsewhere in the document. TheIDREFSdatatype is a list ofIDREFvalues, just as its name implies.Here is a simple DTD fragment that uses theIDandIDREFdatatypes:<?xml version="1.0"?><!-- parts-list1.xml --> <!DOCTYPE parts-list [ <!ELEMENT parts-list (component+, part+)> <!ELEMENT component (name, partref+)> <!ATTLIST component component-id ID #REQUIRED> <!ELEMENT name (#PCDATA)> <!ELEMENT partref EMPTY> <!ATTLIST partref refid IDREF #REQUIRED> <!ELEMENT part (name)> <!ATTLIST part part-id ID #REQUIRED> ]> <parts-list> ... </parts-list>
Here is the XML Schema definition of the same document type:<?xml version="1.0" encoding="UTF-8"?><!-- parts-list.xsd --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="parts-list"> <xs:complexType> <xs:sequence> <xs:element ref="component" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="part" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="component"> <xs:complexType> <xs:sequence> <xs:element ref="name" minOccurs="1" maxOccurs="1"/> <xs:element ref="partref" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using the XML ID, IDREF, and IDREFS Datatypes
- InhaltsvorschauOur first attempt at linking will be with the XPath
id( )function. This useful function helps us find the element that has anIDattribute with a particular value.Three of the basic datatypes that are supported by XML Document Type Definitions (DTDs) and XML Schemas areID,IDREF, andIDREFS. TheIDandIDREFdatatypes work according to two rules:- Every attribute of datatype
IDmust be unique. - Every value of datatype
IDREFmust match a value of an attribute of datatypeIDsomewhere in the document.
An attribute with a datatype ofIDREFScontains one or more space-separated values, each of which must match a value of anIDelsewhere in the document. TheIDREFSdatatype is a list ofIDREFvalues, just as its name implies.Here is a simple DTD fragment that uses theIDandIDREFdatatypes:<?xml version="1.0"?><!-- parts-list1.xml --> <!DOCTYPE parts-list [ <!ELEMENT parts-list (component+, part+)> <!ELEMENT component (name, partref+)> <!ATTLIST component component-id ID #REQUIRED> <!ELEMENT name (#PCDATA)> <!ELEMENT partref EMPTY> <!ATTLIST partref refid IDREF #REQUIRED> <!ELEMENT part (name)> <!ATTLIST part part-id ID #REQUIRED> ]> <parts-list> ... </parts-list>
Here is the XML Schema definition of the same document type:<?xml version="1.0" encoding="UTF-8"?><!-- parts-list.xsd --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="parts-list"> <xs:complexType> <xs:sequence> <xs:element ref="component" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="part" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="component"> <xs:complexType> <xs:sequence> <xs:element ref="name" minOccurs="1" maxOccurs="1"/> <xs:element ref="partref" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> <xs:attribute name="component-id" type="xs:ID" use="required"/> </xs:complexType> </xs:element> <xs:element name="part"> <xs:complexType> <xs:sequence> <xs:element ref="name" minOccurs="1" maxOccurs="1"/> </xs:sequence>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - XSLT’s Key Facility
- InhaltsvorschauNow that we’ve covered the
id( )function in great detail, we’ll move on to XSLT’skey( )function and the<xsl:key>element. Each<xsl:key>element effectively creates an index of the document. You can then use that index to find all elements that have a particular property. Once the key is created, we can use thekey( )function to retrieve parts of the document.For example, if you have a database of (U.S. postal) addresses, you might want to index that database by the people’s last names, by the states in which they live, by their zip codes, etc. Each index takes a certain amount of time to build, but it saves processing time later. (Be aware that it can take a significant amount of memory to create a key, particularly for very large documents.) If you want to find all the people who live in the state of Idaho, you can use the index to find all those people directly; you don’t have to search the entire database.We’ll discuss the details of how the key facility works, and then we’ll compare it to theid( )function.You define akey( )function with the<xsl:key>element:<xsl:key name="supplier-by-country" match="supplier" use="@country"/> <xsl:key name="part-by-supplier" match="part" use="@supplier"/>
The key has three attributes:name- This attribute is used to refer to this particular key. When you want to find parts of your XML document, use the
nameto indicate the key you want to use. match- Containing an XPath expression, this attribute specifies what part of the document you want to index. In our sample here, we’ve created two keys: one for retrieving
<supplier>s and one for retrieving<part>s. use- Containing another XPath expression, this attribute is interpreted in the context of the
matchattribute. In other words, the first<xsl:key>element here, namedsupplier-by-country, creates an index of all the<supplier>elements, and uses thecountryattribute to retrieve them. The second
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Generating Links in Unstructured Documents
- InhaltsvorschauBefore we leave the topic of linking, we’ll discuss one more useful technique. So far, all of this chapter’s examples have been structured nicely. When there was a relationship between two pieces of information, we had an
IDandIDREFpair to match them. What happens if the XML document you’re transforming isn’t written that way? Fortunately, we can use thekey( )function and thegenerate-id( )function to create structure where there isn’t any.For our example here, we’ll take out all of theidandrefidattributes that have served us well so far. This is a contrived example, but it demonstrates how we can use thekey( )andgenerate-id( )functions to generate links between parts of our document.In our new sample document, we’ve stripped out the references that tied things together so neatly before:<?xml version="1.0"?><!-- parts-list4.xml --> <parts-list> <component> <name>Turnip Twaddler</name> <partref>Paring Knife</partref> <partref>Spanner</partref> <partref>Feather Duster</partref> <partref>Grommet</partref> <description> If you've got turnips to twaddle, this is the tool for you! Comes with a <partref>Feather Duster</partref>. </description> </component> ... <part> <name>Pitter</name> <description> Removes pits from olives and cherries in no time at all. </description> </part> <part> <name>Patter</name> <description> We're not sure what these things do, but people seem to like 'em. </description> </part> ... </parts-list>We’ve removed all of theIDs andIDREFs in the document. For elements such as<partref>that formerly used attributes to link parts of the document together, we simply use the text of the item we’re referring to. To generate the cross-references we created before, we’ll need to do three things:- Define two keys for all parts and components. One key lets us get the
<part>that matches a given name, and the other lets us find a
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauIn this chapter, we’ve examined several ways to generate links and cross-references between different parts of a document. If your XML document has a reasonable amount of structure, you can use the
id( )andkey( )functions to define many different relationships between the parts of a document. Even if your XML document isn’t structured, you may be able to usekey( )andgenerate-id( )to create simple references. In the next chapter, we’ll look at sorting and grouping—two more ways to organize the information in our XML documents.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 7: Sorting and Grouping Elements
- InhaltsvorschauBy now, I hope you’re convinced that you can use XSLT to convert big piles of XML data into other useful things. Our examples to this point have pretty much gone through the XML source in what’s referred to as document order. We’d like to go through our XML documents in a couple of other common ways, though:
- We could sort some or all of the XML elements, then generate output based on the sorted elements.
- We could group the data, selecting all elements that have some property in common, then sorting the groups of elements.
We’ll give several examples of these operations in this chapter.The simplest way to rearrange our XML elements is to use the<xsl:sort>element. This element temporarily rearranges a collection of elements based on criteria we define in our stylesheet.For our first example, we’ll have a set of U.S. postal addresses that we want to sort. (No chauvinism is intended here; obviously every country has different conventions for mailing addresses. We just needed a short sample document that can be sorted in many useful ways.) Here’s our original document:<?xml version="1.0"?><!-- names.xml --> <addressbook> <address> <name> <title>Mr.</title> <first-name>Chester Hasbrouck</first-name> <last-name>Frisby</last-name> </name> <street>1234 Main Street</street> <city>Sheboygan</city> <state>WI</state> <zip>48392</zip> </address> <address> <name> <first-name>Mary</first-name> <last-name>Backstayge</last-name> </name> <street>283 First Avenue</street> <city>Skunk Haven</city> <state>MA</state> <zip>02718</zip> </address> <address> <name> <title>Ms.</title> <first-name>Natalie</first-name> <last-name>Attired</last-name> </name> <street>707 Breitling Way</street> <city>Winter Harbor</city> <state>ME</state> <zip>00218</zip> </address> <address> <name> <first-name>Harry</first-name> <last-name>Backstayge</last-name> </name> <street>283 First Avenue</street> <city>Skunk Haven</city> <state>MA</state> <zip>02718</zip> </address> <address> <name> <first-name>Mary</first-name> <last-name>McGoon</last-name> </name> <street>103 Bryant Street</street> <city>Boylston</city> <state>VA</state> <zip>27318</zip> </address> <address> <name> <title>Ms.</title> <first-name>Amanda</first-name> <last-name>Reckonwith</last-name> </name> <street>930-A Chestnut Street</street> <city>Lynn</city> <state>MA</state> <zip>02930</zip> </address> </addressbook>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Sorting Data with <xsl:sort>
- InhaltsvorschauThe simplest way to rearrange our XML elements is to use the
<xsl:sort>element. This element temporarily rearranges a collection of elements based on criteria we define in our stylesheet.For our first example, we’ll have a set of U.S. postal addresses that we want to sort. (No chauvinism is intended here; obviously every country has different conventions for mailing addresses. We just needed a short sample document that can be sorted in many useful ways.) Here’s our original document:<?xml version="1.0"?><!-- names.xml --> <addressbook> <address> <name> <title>Mr.</title> <first-name>Chester Hasbrouck</first-name> <last-name>Frisby</last-name> </name> <street>1234 Main Street</street> <city>Sheboygan</city> <state>WI</state> <zip>48392</zip> </address> <address> <name> <first-name>Mary</first-name> <last-name>Backstayge</last-name> </name> <street>283 First Avenue</street> <city>Skunk Haven</city> <state>MA</state> <zip>02718</zip> </address> <address> <name> <title>Ms.</title> <first-name>Natalie</first-name> <last-name>Attired</last-name> </name> <street>707 Breitling Way</street> <city>Winter Harbor</city> <state>ME</state> <zip>00218</zip> </address> <address> <name> <first-name>Harry</first-name> <last-name>Backstayge</last-name> </name> <street>283 First Avenue</street> <city>Skunk Haven</city> <state>MA</state> <zip>02718</zip> </address> <address> <name> <first-name>Mary</first-name> <last-name>McGoon</last-name> </name> <street>103 Bryant Street</street> <city>Boylston</city> <state>VA</state> <zip>27318</zip> </address> <address> <name> <title>Ms.</title> <first-name>Amanda</first-name> <last-name>Reckonwith</last-name> </name> <street>930-A Chestnut Street</street> <city>Lynn</city> <state>MA</state> <zip>02930</zip> </address> </addressbook>We’d like to generate a list of these addresses, sorted byEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] The <xsl:perform-sort> Element
- InhaltsvorschauAs we discussed in , XSLT 2.0 introduces the concept of a sequence, which is a group of nodes or atomic values. That sequence is typically created during stylesheet processing, usually as a variable. You can use the
<xsl:perform-sort>element to sort a sequence. Everything we’ve discussed about sorting applies to<xsl:perform-sort>; we’ll look at some examples here.There are two ways to use<xsl:perform-sort>: you can give it an existing sequence and use<xsl:perform-sort>to sort that sequence, or you can use<xsl:perform-sort>to both create the sequence and sort it. For our first example, we’ll create a sequence of all the<city>elements and use<xsl:perform-sort>to sort it:<?xml version="1.0"?><!-- perform-sort1.xsl --> <xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:variable name="sortedCities" as="xs:string*"> <xsl:perform-sort select="addressbook/address/city"> <xsl:sort select="."/> </xsl:perform-sort> </xsl:variable> <xsl:text>Our customers live in these cities:

</xsl:text> <xsl:value-of select="$sortedCities" separator="
"/> </xsl:template> </xsl:stylesheet>
Theselectattribute of<xsl:perform-sort>defines the sequence to be sorted. When we use this stylesheet against our address book, here are the results:Our customers live in these cities: Boylston Lynn Sheboygan Skunk Haven Skunk Haven Winter Harbor
We can also use the new<xsl:sequence>element to create the sequence inside<xsl:perform-sort>:<?xml version="1.0"?><!-- perform-sort2.xsl --> <xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:variable name="sortedCities" as="xs:string*"> <xsl:perform-sort> <xsl:sort select="."/> <xsl:sequence select="addressbook/address/city"/> </xsl:perform-sort> </xsl:variable> <xsl:text>Our customers live in these cities:

</xsl:text> <xsl:value-of select="$sortedCities" separator="
"/> </xsl:template> </xsl:stylesheet>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Grouping Nodes
- InhaltsvorschauWhen grouping nodes, we sort things to get them into a certain order, and then we group all items that have the same value for the sort key (or keys). We’ll use
xsl:sortfor this grouping, and then use variables or functions such askey( )orgenerate-id( )to finish the job.[2.0] XSLT 2.0 has new elements and functions that make grouping much easier. If you’re using XSLT 2.0, feel free to skip ahead to the section ” later in this chapter.For our first example, we’ll take our list of addresses and group them. We’ll look for all unique values of the<zip>element and list the addresses that match each one. We’ll sort the list by zip code, then go through the list. If a given item doesn’t match the previous zip code, we’ll print out a heading; if it does match, we’ll just print out the address. Here’s our first attempt:<?xml version="1.0"?><!-- namegrouper1.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>Addresses grouped by zip code 
</xsl:text> <xsl:for-each select="addressbook/address"> <xsl:sort select="zip"/> <xsl:if test="zip!=preceding-sibling::address[1]/zip"> <xsl:text>
Zip code </xsl:text> <xsl:value-of select="zip"/> <xsl:text> (</xsl:text> <xsl:value-of select="city"/> <xsl:text>, </xsl:text> <xsl:value-of select="state"/> <xsl:text>): 
</xsl:text> </xsl:if> <xsl:if test="name/title"> <xsl:value-of select="name/title"/> <xsl:text> </xsl:text> </xsl:if> <xsl:value-of select="name/first-name"/> <xsl:text> </xsl:text> <xsl:value-of select="name/last-name"/> <xsl:text>
</xsl:text> <xsl:value-of select="street"/> <xsl:text>

</xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>Our approach in this stylesheet consists of two steps:- Sort the addresses by zip code:
<xsl:sort select="zip"/>
- For each address, if its zip code doesn’t match the previous one, print out a heading, and then print out the addresses that match it:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] New Grouping Syntax in XSLT 2.0
- InhaltsvorschauIn 2001, the XSL Working Group released a document entitled “XSLT Requirements Version 2.0.” More than half of the document came under the heading “Must Simplify Grouping.” (I can’t imagine how the group would have met a requirement named “Must Make Grouping More Complicated and Confusing.”) We’ll take a look at those changes in this section.XSLT 2.0’s grouping functions are built around the
<xsl:for-each-group>element. Within this element, we’ll use the new XSLT functionscurrent-group( )andcurrent-grouping-key( )to work with the data we’re grouping. There are four mutually exclusive attributes for the<xsl:for-each-group>element, each of which performs a different style of grouping:group-by- This is the most common type of grouping. We use an XPath expression to define what identifies a group (all of the
<address>elements that have the same<zip>code, for example), so we can then iterate through each group. group-adjacent- This approach is useful when you want to build a group containing all the adjacent nodes that match an XPath expression. As an example, we’ll take all the adjacent
<p>elements in a document, convert each one to an<li>element, and put<ul>and</ul>tags around the entire group. group-starting-with- The
group-starting-withattribute defines an XPath expression that identifies the start of a group. Once a group starts, every element is added to the group until the start of another group is found.group-starting-withandgroup-ending-withare most often used when adding structure to an HTML document. group-ending-with- This defines an XPath expression that identifies the end of a group. When using
group-ending-with,<xsl:for-each-group>creates a new group as it begins processing nodes. Whenever the end of a group is found, the XSLT processor closes that group and starts another.
Keep in mind that everything you can do with grouping in XSLT 2.0 is possible in XSLT 1.0—it’s just that the markup you’ll have to write and maintain in XSLT 1.0 is much more complicated. If you already have a working XSLT 1.0 stylesheet that uses the Muench method to do grouping, there’s no reason to change the stylesheet if you don’t want to.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauIn this chapter, we’ve gone over all of the common techniques used for sorting and grouping elements, including the new features available in XSLT 2.0. Regardless of the kinds of stylesheets you’ll need to write in your XML projects, you’ll probably use these techniques in everything you do. Now that we’ve covered how to sort and group elements, the next chapter will talk about how to work with multiple documents; that topic builds on what we’ve covered here.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Chapter 8: Combining Documents
- InhaltsvorschauOne of XSLT’s most powerful features is the
document( )function, which lets you combine documents. You can use parts of a document (specified with XPath expressions, of course) to identify other documents. You can then open those documents and perform stylesheet functions on the combination of those documents. In this chapter, we’ll cover thedocument( )function in all its glory.[2.0] XSLT 2.0 and XPath 2.0 provide three new functions for combining documents:doc( ),collection( ), andunparsed-text( ). Thedoc( )function, defined by XPath 2.0, is similar to thedocument( )function, though less powerful. Thecollection( )function, also defined by XPath 2.0, allows us to add collections of nodes provided by an XSLT processor. The kinds of nodes provided can vary from one processor to the next. Finally, theunparsed-text( )function lets us add raw text to the data we’re processing in our stylesheet. When combined with features such as tokenization and regular expressions,unparsed-text( )gives us many new ways of manipulating data. We’ll look at these new functions at the end of this chapter.A common task in writing stylesheets is combining data from different documents. We’ll start by using thedocument( )function to parse and process multiple XML documents. We’ll start our discussion with XML-tagged purchase orders that look like this:<?xml version="1.0"?><!-- po38295.xml --> <purchase-order id="38295"> <date year="2001" month="9" day="8"/> <customer id="4738" level="Basic"> <address type="business"> <name> <title>Ms.</title> <first-name>Amanda</first-name> <last-name>Reckonwith</last-name> </name> <street>930-A Chestnut Street</street> <city>Lynn</city> <state>MA</state> <zip>02930</zip> </address> <address type="ship-to"/> </customer> <items> <item part-no="23813-03-CDK"> <name>Cucumber Decorating Kit</name> <qty>1</qty> <price>29.95</price> </item> </items> </purchase-order>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The document( ) Function
- InhaltsvorschauA common task in writing stylesheets is combining data from different documents. We’ll start by using the
document( )function to parse and process multiple XML documents. We’ll start our discussion with XML-tagged purchase orders that look like this:<?xml version="1.0"?><!-- po38295.xml --> <purchase-order id="38295"> <date year="2001" month="9" day="8"/> <customer id="4738" level="Basic"> <address type="business"> <name> <title>Ms.</title> <first-name>Amanda</first-name> <last-name>Reckonwith</last-name> </name> <street>930-A Chestnut Street</street> <city>Lynn</city> <state>MA</state> <zip>02930</zip> </address> <address type="ship-to"/> </customer> <items> <item part-no="23813-03-CDK"> <name>Cucumber Decorating Kit</name> <qty>1</qty> <price>29.95</price> </item> </items> </purchase-order>If we had a few dozen documents like this, we might want to view the collection of purchase orders in a number of ways. We could view them sorted (or even grouped) by customer, by part number, by the amount of the total order, by the state to which they were shipped, etc. One way to do this would be to write code that worked directly with the Document Object Model. We could parse each document, retrieve its DOM tree, and then use DOM functions to order and group the various DOM trees, display certain parts of the DOM trees, etc. Because this is an XSLT book, though, you probably won’t be surprised to learn that XSLT provides a function to handle most of the heavy lifting for us.We’ll start with a simple example that uses thedocument( )function. We’ll assume that we have several purchase orders and that we want to combine them into a single report document. One thing we can do is create a master document that references all the purchase orders we want to include in the report. Here’s what that master document might look like:<?xml version="1.0"?><!-- polist.xml --> <report> <title>Selected Purchase Orders</title> <po filename="po38292.xml"/> <po filename="po38293.xml"/> <po filename="po38294.xml"/> <po filename="po38295.xml"/> </report>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The document( ) Function and Sorting
- InhaltsvorschauUp to now, we’ve written a simple XML document that contains references to other XML documents, then we created a stylesheet that combines all those referenced XML documents into a single output document. That’s all well and good, but we’ll probably want to do more advanced things. For example, it might be useful to generate a document that lists all items ordered across all purchase orders. It might also be useful to sort all the purchase orders by the state to which they were shipped or by the last name of the customer. We’ll go through some of these scenarios to illustrate the design challenges we face when generating documents from multiple input files.Our first challenge will be to generate a listing of all purchase orders and sort them by state, then by city within state. This isn’t terribly difficult; we’ll simply use the
<xsl:sort>element in conjunction with thedocument( )function. Here’s the heart of our new stylesheet:<?xml version="1.0"?><!-- masterdox2.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> ... <xsl:apply-templates select="document(/report/po/@filename)/purchase-order"> <xsl:sort select="customer/address/state"/> <xsl:sort select="customer/address/city"/> </xsl:apply-templates>Here we’re selecting all of the<purchase-order>elements and sorting them by the values of their<state>and<city>elements. shows our output document, sorted by the value of the<state>element (the state abbreviation) in each purchase order.
Figure : Purchase orders sorted by state abbreviationNotice that we’re sorting purchase orders by the state abbreviation, not the actual state name; we’ll address that in our next example.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Implementing Lookup Tables
- InhaltsvorschauWe mentioned earlier that calling the
document( )function with an empty string enabled us to access the nodes in the stylesheet itself. We can use this behavior to implement a lookup table. As an example, we’ll create a lookup table that associates an abbreviation such asMEwith the state nameMaine. We can then use the value from the lookup table as the sort key. More attentive readers might have noticed in our previous example that although the abbreviationMAdoes indeed sort before the abbreviationME, a sorted list of the state names themselves would putMaine(abbreviationME) beforeMassachusetts(abbreviationMA).First, we’ll create our lookup table. We’ll use the fact that a stylesheet can have any element as a top-level element, provided that element is namespace-qualified to it from thexsl:namespace reserved for stylesheets. Here’s the namespace prefix definition and part of the lookup table that uses it:<?xml version="1.0"?><!-- masterdox3.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:states="http://www.usps.com/ncsc/lookups/abbreviations.html" exclude-result-prefixes="states"> <states:name abbrev="AL">Alabama</states:name> <states:name abbrev="AK">Alaska</states:name> <states:name abbrev="AS">American Samoa</states:name> <!-- Many state names deleted for brevity --> <states:name abbrev="WV">West Virginia</states:name> <states:name abbrev="WI">Wisconsin</states:name> <states:name abbrev="WY">Wyoming</states:name>(The namespace mapped to thestatesprefix is the URL for the official list of state abbreviations from the United States Postal Service, although it could be any string.)To look up values in our table, we’ll use thedocument( )function to return the root node of our stylesheet, then we’ll look for a<states:name>element with aabbrevattribute that matches the value of the current<state>element in the purchase order we’re currently processing. Here’s the somewhat convoluted syntax that performs this magic:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Grouping Across Multiple Documents
- InhaltsvorschauOur final task will be to group our collection of purchase orders. We’ll create a new listing that groups all the purchase orders by the state to which they were shipped. We’ll use the grouping technique we used earlier in .We’ll define an XSLT
key( )for all of the<state>values in our set of purchase orders. We’ll also create a variable that stores all of these orders. By reading all of the purchase orders into a variable, we won’t have to call thedocument( )function every time we need to access a particular purchase order. With those two structures in place, we’ll be ready to do grouping just as we did in the last chapter.To get things started, here’s how we define thekey( ):<xsl:key name="po-key" match="purchase-order" use="customer/address/state"/>
And here’s how we load all of the purchase order documents into a variable:<xsl:variable name="purchase-orders" select="document(/report/po/@filename)/purchase-order"/>
Now that we have a variable that contains all of the nodes from all of the purchase orders, we’re ready to process them. We’ll go through these steps:- Start an
<xsl:for-each>element to process all of the nodes in the variable$purchase-orders. - Sort the purchase orders by state name. As with our previous stylesheet, this means using the
document('')function to retrieve the state name that matches the abbreviation in the purchase order. - Save the value of the current
<state>in a variable. - Use the
key( )function to save into a variable all of the purchase orders from the current state. - If this is the first time we’ve seen this particular state (we’ll use
generate-id( )here), use<xsl:apply-templates>to process all the purchase orders that match the current state. When we call<xsl:apply-templates>, we’ll sort all the purchase orders for that state by city before we process them.
Here’s the significant portion of the stylesheet; the template for processing the<purchase-order>element is unchanged from our previous stylesheets:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] Using XSLT 2.0 to Simplify Things
- InhaltsvorschauWe’ve mentioned several times in this chapter that XSLT 2.0 has capabilities that can greatly simplify our stylesheet. We’ll look at those techniques in this section.The XSLT 1.0 stylesheet we’ve developed here has several areas ripe for improvement:
- We have to use the XSLT 1.0 grouping technique. We can avoid this clumsiness by using XSLT 2.0’s
<xsl:for-each-group>to do the grouping for us. The XSLT processor does the work of finding all of the unique state values, simplifying our lives significantly. - We have to use recursion to calculate the total of each purchase order. We can use new features of XPath 2.0 to calculate the total in one simple expression.
- Although the
document('')technique we used works, it’s a convoluted way of doing things. We can replace it with an XSLT function that takes a state abbreviation as input and returns the full name of that state. This gives us a much simpler syntax. CallinggetStateName( )is much easier to understand and maintain thandocument('')/*/states:name[@abbrev=$next-state]. - It’s a minor point, but we have to use an
<xsl:choose>element in a couple of places. We can use theifoperator defined in the XPath 2.0 and XQuery 1.0 Functions and Operators spec to simplify the stylesheet. Instead of<xsl:choose>,<xsl:when>, and<xsl:otherwise>, we’ll useif,then, andelse. - Another minor point is that the date of each purchase order is stored in the XML source as a set of three attributes. We can use XSLT 2.0’s support for XML Schema to create an
xs:date, and then use the power of theformat-date( )function to format the date more elegantly.
With these things in mind, we’ll start simplifying our stylesheet.One problem in our final XSLT 1.0 stylesheet is that we have to find all the distinct state values in all the purchase orders. We use the Muench method to do this, but the code is more difficult to write and maintain. To simplify things, we can useEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] The doc( ) and doc-available( ) Functions
- InhaltsvorschauXSLT 2.0 provides a new function,
doc( ), that is very similar to thedocument( )function, but that is simpler in a couple of ways. First of all, thedocument( )function can take a node-set or sequence as its first argument, whereasdoc( )takes a single string. In our earlier stylesheets, we created a variable containing all of the nodes from all of the documents referenced in our list of purchase orders:<xsl:variable name="purchase-orders" select="document(/report/po/@filename)/purchase-order"/>
This returns a sequence ofpurchase-ordernodes, each of which has the structure defined in the purchase order. We can use the variable$purchase-ordersin an<xsl:for-each>or<xsl:for-each-group>element. A stylesheet that contains this markup raises an error if there is more than one<po>element in the source document:<!-- This doesn't work with our sample document --> <xsl:variable name="purchase-orders" select="doc(/report/po/@filename)/purchase-order"/>
If we want to use thedoc( )function, there are several things we could do. We could specify a particular<po>element:<xsl:variable name="purchase-orders" select="doc(/report/po[2]/@filename)/purchase-order"/>
A more practical solution would be to put thedoc( )function into an<xsl:for-each>element:<xsl:for-each select="/report/po"> <xsl:variable name="purchase-orders" select="doc(@filename)/purchase-order"/> </xsl:for-each>We could also change our input document so that it has only a single<po>element; although that’s hardly a worthwhile solution, thedoc( )function would in fact work.To contrast the two functions, thedoc( )function returns the document node of a single XML document, while thedocument( )function can return a set of nodes from multiple documents. In most cases, you’ll want to use the more flexibledocument( )function instead.Second, we mentioned that thedocument( )function has an optional second argument to set a base URI for resolving relative URLs. Thedoc( )function doesn’t have this optionEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] The collection( ) Function
- InhaltsvorschauThe
collection( )function takes a string as its argument and returns a collection of nodes. Defined as part of the XPath 2.0 spec, it gives us the ability to use a URI to retrieve a collection of documents. How those documents are stored (or whether they’re really documents at all) is implementation-dependent. In particular, the spec mentions accessing data in a relational database as a possible implementation of thecollection( )function. The fact that the string passed to the function can be generated and can contain parameters makescollection( )very flexible.We’ll look at a short example here. Here’s the document we’ll pass to thecollection( )function:<?xml version="1.0"?><!-- polist.xml --> <collection> <doc href="po38292.xml"/> <doc href="po38293.xml"/> <doc href="po38294.xml"/> <doc href="po38295.xml"/> </collection>This is very similar to the list of purchase orders we worked with earlier in this chapter. The stylesheet that invokes thecollection( )function looks like this:<?xml version="1.0"?><!-- collection.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>
A test of the collection() function:</xsl:text> <xsl:variable name="docPile" as="node()*" select="collection('polist.xml')"/> <xsl:text>

 The customers in the </xsl:text> <xsl:text>collection are: 
 </xsl:text> <xsl:for-each select="$docPile/purchase-order/customer"> <xsl:sort select="address/name/last-name"/> <xsl:value-of select="address/name/title, address/name/first-name, address/name/last-name" separator=" "/> <xsl:text> 
 </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
The stylesheet extracts the nodes from thecollection( )function and stores them in the variable$docPile. Once we have the nodes from the collection, we sort all of the customers in all of those purchase orders by last name, and then write them out. The results look like this:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [2.0] The unparsed-text( ) and unparsed-text-available( ) Functions
- InhaltsvorschauThe last new function for combining documents is the
unparsed-text( )function. This lets you read in text from a URL. That text is not parsed, letting you read in text , comma-separated values, or even HTML documents that aren’t well-formed XML. What’s more, you can combineunparsed-text( )with other new features such as thetokenize( )function or the<xsl:analyze-string>element to process that text and transform it in a useful way.As an example, we’ll read in a file of comma-separated values and output them as an HTML table of addresses. Here’s the comma-separated file, unparsed-text.csv:Mr.,Chester Hasbrouck,Frisby,1234 Main Street,Sheboygan,WI,48392 Ms.,Natalie,Attired,707 Breitling Way,Winter Harbor,ME,00218 Ms.,Amanda,Reckonwith,930-A Chestnut Street,Lynn,MA,02930 Mrs.,Mary,Backstayge,283 First Avenue,Skunk Haven,MA,02718
We’ll go through three simple steps to process this data. First, we’ll use thetokenize( )function to get each line of the file. Next, we’ll usetokenize( )to get each comma-separated value. Finally, we’ll take each value and transform it appropriately. Using the comma-separated file we’ve listed here, the third comma-separated value in each line is the customer’s last name, the seventh value is the zip code, and so forth.To process the file one line at a time, we’ll use this technique, courtesy of the XSLT 2.0 spec:<xsl:for-each select="tokenize(unparsed-text('addresses.csv'), '\r?\n')">The<xsl:for-each>element processes the file one line at a time, while the regular expression\r?\nmatches a line end. (As the spec points out,unparsed-text( )doesn’t normalize line endings, so we have to allow for an optional carriage return, indicated by\r?.)Within<xsl:for-each>, we tokenize each line. This is easy because we’re simply looking for the values between the commas. Thetokenize( )function returns a sequence, so we put that sequence into a variable:<xsl:variable name="tokens" select="tokenize(., ',')"/>
Before we process the comma-separated values, we use theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauThis chapter completes our tour of the XSLT and XPath functions that work with multiple documents. These powerful functions allow us to generate an output document containing elements from many different input documents. In our examples here, we generated several views of those input documents, but many more combinations might be useful. The biggest benefit of these functions is that they allows us to define views of multiple documents that are separate from those documents themselves. As we need to define other views, we don’t have to change our input documents.We also looked at using the new
unparsed-text( )function to read non-XML data and add it to our result documents. The functions we’ve discussed here can save you a tremendous amount of development time in generating reports and other summarizing documents.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 9: Extending XSLT
- InhaltsvorschauTo this point, we’ve spent a lot of time learning how to use the built-in features of XSLT and XPath to get things done. We’ve also talked about the somewhat unusual processing model that makes life challenging for programmers from the world of procedural languages (a.k.a. Earth). But what do you do if you still can’t do everything with XSLT and XPath?In this chapter, we’ll discuss the XSLT extension mechanism that allows you to add new functions and elements to the language. The XSLT standard doesn’t define all of the details about how these things should work, so there are some differences between processors. The good news is that if you write an extension function or element that works with your favorite processor, another vendor can’t do something sinister to prevent your functions or elements from working. The less good news is that if you decide to change XSLT processors, you’ll probably have to change your code.Along the way, we’ll also discuss the EXSLT project, whose goals are to provide a common library of extension functions that work across different XSLT .The examples in this chapter are written for the Java-based Saxon and Xalan processors, and for the .NET framework (using C#). We’ll discuss how to write stylesheets that can work with multiple processors, and we’ll briefly look at the differences between the various APIs supported by those processors. In addition, the Xalan-J processor supports Apache’s Bean Scripting Framework (BSF), which means we can write extensions in Jython (also known as JPython), JavaScript, Jacl, and any other language supported by the BSF.The XSLT standard defines two kinds of extensions: extension elements and extension functions. The spec also defines fallback processing, a way for stylesheets to respond gracefully when extension elements and functions aren’t available. (Fallback processing also applies when we ask an XSLT 1.0 processor to process an XSLT 2.0 stylesheet.) We’ll talk about these items briefly, and then we’ll move on to some examples that illustrate the full range of extensions and fallback processing.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- The XSLT Extension Mechanism
- InhaltsvorschauThe XSLT standard defines two kinds of extensions: extension elements and extension functions. The spec also defines fallback processing, a way for stylesheets to respond gracefully when extension elements and functions aren’t available. (Fallback processing also applies when we ask an XSLT 1.0 processor to process an XSLT 2.0 stylesheet.) We’ll talk about these items briefly, and then we’ll move on to some examples that illustrate the full range of extensions and fallback processing.Keep in mind that the XSLT specs define how the extension mechanism should work; they do not define how it should be implemented. As we’ll see throughout this chapter, different XSLT processors implement extensions in different ways. For example, a Java-based XSLT processor might use a Java class to implement an extension function or extension element, while a .NET XSLT processor might use a .NET class to do the same thing. How those classes are specified varies from one processor to the next.An extension element is an element that should be processed by a piece of code external to the XSLT processor. The implementation details vary from one XSLT processor to the next, as you’d expect. We’ll discuss how an extension element can access the XPath representation of our XML source document, how (or if) it can process attribute value templates, how it can generate output, and how (or if) it can move through the XPath tree to manipulate the source document. We’ll demonstrate various APIs to do all of these things; the APIs, of course, vary quite a bit between processors. Finally, although XSLT processors typically provide an extension writer with access to the XML source, the standard doesn’t define a set of functions or access methods that must be supported.As you might guess, an extension function is defined in a piece of code accessed from the XSLT stylesheet. In some cases, that function is written in a scripting language in the stylesheet itself. In those instances, the scripting code is contained in an XML element that is not in the XSLT namespace. In other cases, the function is in a separate file that is loaded by the XSLT processor at runtime. The code for the function might be written in a scripting language or it might be written in a compiled language.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- [2.0] Creating New Functions with <xsl:function>
- InhaltsvorschauXSLT 2.0 adds the
<xsl:function>element. This lets you define your own functions in the stylesheet itself. This is the simplest extension that we’ll examine in this chapter; the extension itself is in the same file and same syntax as the stylesheet, and the standard is very clear on how the function is defined and invoked. We’ll use a simple stylesheet that creates a table in which the background color of each cell cycles through four different colors. Given the position of the current item, our function will return one of the four values.To define a function, there are several things we have to do: define a (non-XSLT) namespace for the function, name the function, define what datatype it returns, and define the name and datatype of any parameters the function has. Defining a namespace is simple enough, although we need to remember to put our namespace prefix in theexclude-result-prefixesattribute of<xsl:stylesheet>. We’ll call our functiongetBackgroundColor, and it will return anxs:stringnaming the background color of each table cell. Finally, the input to our function is anxs:integerof the position of the current item. The function looks like this:<xsl:function name="sample:getBackgroundColor" as="xs:string"> <xsl:param name="pos" as="xs:integer"/> <xsl:value-of select="$colors[($pos mod count($colors)) + 1]"/> </xsl:function>
The function is in thesamplenamespace, it returns a string, and it takes an integer as its only parameter. It references the variable$colorsto retrieve a color name. Rather than use an XML document for input, we’ll create a sequence of numbers and put each one in a table cell. Here’s the stylesheet:<?xml version="1.0" encoding="utf-8"?><!-- simple-function.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:sample="http://www.oreilly.com/catalog/xslt" exclude-result-prefixes="xs sample"> <xsl:output method="html" include-content-type="no"/> <xsl:variable name="colors" as="xs:string *" select="('green', 'grey', 'blue', 'red')"/>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Example: Generating Multiple Output Files
- InhaltsvorschauThe whole point of extensions is to allow you to add new capabilities to the XSLT processor. One of the most common needs is the ability to generate multiple output documents. As we saw earlier, the
document( )function allows you to have multiple input documents—but XSLT 1.0 doesn’t give us any way to create these. Saxon’s support for XSLT 2.0 includes the<xsl:result-document>element, which lets us generate multiple output documents. Although Xalan doesn’t support XSLT 2.0, it does support an extension element (<redirect:write>) that does the same thing. We’ll look at a stylesheet that uses<xsl:fallback>to generate useful results regardless of the processor we’re using. If we’re using Saxon or Xalan, we’ll get multiple output documents that are hyperlinked together; if we’re using any other processor, we’ll get a single HTML file that contains the same information.Here’s the source document we’ll use:<?xml version="1.0"?><!-- chapters.xml --> <book> <title>XSLT Topics</title> <chapter> <title>XPath</title> <para>If this chapter had any text, it would appear here.</para> </chapter> <chapter> <title>Stylesheet Basics</title> <para>If this chapter had any text, it would appear here.</para> </chapter> ... <chapter> <title>Combining XML Documents</title> <para>If this chapter had any text, it would appear here.</para> </chapter> </book>In addition to the<xsl:fallback>element, our stylesheet also uses theelement-available( )function to determine what elements are available. If we can’t generate multiple output documents (i.e., the elements we need aren’t available), we create a single HTML file. If the elements are available, we first create a single HTML file with hyperlinks to the individual HTML files that we’ll create later in the stylesheet. When we create the individual files, we’ll use the<xsl:result-document>and<redirect:write>elements with<xsl:fallback>to handle with XSLT processors that don’t support those elements.Let’s go through the relevant parts of this example. To begin with, ourEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating Custom Collations
- InhaltsvorschauThe XSLT 2.0 spec uses collations in several places. A collation defines how characters are sorted and compared. English doesn’t have any accented characters or character sequences that sort as separate letters, so that’s not an issue if all your documents are in English. Even if English is your native language, it’s likely you’ll need to work with documents written in other languages. In that case, characters such as the Spanish ch (considered a separate letter, the letter che) or accented characters such as the German umlaut-u, which can be written as ü or ue, become important in sorting and comparing words.As with extension functions, the XSLT 2.0 spec defines attributes that can be used to indicate where custom collations can be used, but it doesn’t define how to identify a particular piece of code that does the work. Because Saxon has taken the lead in implementing these functions, we’ll focus on accessing custom collations in Saxon here. We’ll look at two of these collations. The first sorts Spanish words so that ch sorts as a separate letter between c and d. The second collation compares German words so that Müller and Mueller are considered identical.Your author is in no way a speaker of Spanish or German, so please pardon any incorrect statements about the languages themselves. The point here is to illustrate how to create extensions that implement custom collations and then use those extensions for sorting and comparing text in your stylesheets.The traditional Spanish collation, the one we’ll implement here, treats ch, ll, and ñ as separate letters that sort after c, l, and n respectively. However, much of the Spanish speaking world now uses the modern Spanish collation, defined by the Association of Spanish Language Academies (La Asociación de Academias de Lingua Española). The modern Spanish collation doesn’t treat
chorllas special characters; they sort as they would in English. The letterEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Generating Hidden Word Graphics
- InhaltsvorschauA frequent abuse of the Web is scripts that attempt to create dozens of email accounts or buy hundreds of concert tickets by parsing HTML forms and responding to them. To counteract this, many web sites now feature hidden word graphics that contain a word along with visual noise (in our case, lines drawn through the text) so that only a human can read the word. This ensures that only a human can use the form. We’ll look at an XSLT extension function that, given a word, generates a hidden word graphic and a web page.Given a secret word, our extension function creates a graphic containing that word and an HTML form that displays the graphic and asks the user to type the word hidden in the graphic. (Obviously, a complete solution would generate the server-side code, transient cookies, and other things to process the form, but that’s beyond what we’ll cover here. Our focus is on how to create the XSLT extension that creates the graphic.)Our stylesheet looks like this:
<?xml version="1.0"?><!-- hidden-word-test.xsl --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="java:com.oreilly.xslt.HiddenWord" xmlns:xalan="xalan://com.oreilly.xslt.HiddenWord" xmlns:ora="http://www.oreilly.com/xslt" extension-element-prefixes="saxon xalan ora"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title> Test of hidden word generator </title> </head> <body style="font-family: sans-serif;"> <h1>Test of hidden word generator</h1> <xsl:comment> This <form> doesn't have a method or action attribute; a real form would, of course... </xsl:comment> <xsl:variable name="createGraphic"> <xsl:choose> <xsl:when test="function-available('saxon:createJPEG')"> <xsl:value-of select="saxon:createJPEG('hidden.jpg', 'giraffe', 48, 200, 100)"/> </xsl:when> <xsl:when test="function-available('xalan:createJPEG')"> <xsl:value-of select="xalan:createJPEG('hidden.jpg', 'monkey', 48, 200, 100)"/> </xsl:when> <xsl:when test="function-available('ora:createJPEG')"> <xsl:value-of select="ora:createJPEG('hidden.jpg', 'okapi', 48, 200, 100)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="1"/> </xsl:otherwise> </xsl:choose> </xsl:variable>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Example: Generating an SVG Pie Chart
- InhaltsvorschauAs we outlined the functions and operators available in XPath and XSLT, you probably noticed that the mathematical functions at your disposal are rather limited, even in XSLT 2.0. In this example, we’ll write an extension that provides a variety of trigonometric functions. We’ll do this in several ways:
- We’ll use the extension mechanisms in Xalan and Saxon to call static methods in the
java.lang.Mathclass. - We’ll use the trigonometric functions in the EXSLT
mathlibrary (more on EXSLT later). - We’ll use the Bean Scripting Framework, an interesting piece of code from the Apache Jakarta project that lets us write extension functions in a variety of scripting languages, including JRuby, JavaScript, Jython, and Jacl.
- We’ll use classes from the .NET library to extend the Microsoft XSLT processor.
We’ll start this section by building the stylesheet once, and then we’ll discuss what’s different in each iteration. Our scenario is that we want to generate a Scalable Vector Graphics (SVG) pie chart from an XML document. This document contains the sales figures for different stores of a company; we need to calculate the dimensions of the various slices of the pie graph for our SVG document. Here’s the XML source we’ll be working with:<?xml version="1.0" encoding="utf-8"?><!-- chocolate-sales.xml --> <report month="8" year="2006"> <caption> <heading>Chocolate bar sales</heading> <subheading>(units)</subheading> </caption> <store> <name>Carrboro</name> <brand name="Lindt">27408</brand> <brand name="Callebaut">8203</brand> <brand name="Valrhona">22101</brand> <brand name="Perugina">14336</brand> <brand name="Ghirardelli">19268</brand> </store> <store> <name>Chapel Hill</name> <brand name="Lindt">28503</brand> <brand name="Valrhona">7287</brand> <brand name="Perugina">12077</brand> <brand name="Ghirardelli">8392</brand> <brand name="Callebaut">17294</brand> </store> ... </store> </report>Our goal is to create an SVG file that looks like .Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Writing Extensions in Other Languages
- InhaltsvorschauOne of the nice features of Xalan-J’s extension mechanism is that it supports the Bean Scripting Framework (BSF), an open source library from the Apache Software Foundation that allows you to execute code written in a variety of scripting languages. We’ll take the SVG stylesheet we just discussed and implement it again, writing the extension functions in a variety of other languages. For our first example, we’ll look at all the details of defining and invoking BSF extension functions; for the subsequent examples, we’ll simply highlight the differences.The Bean Scripting Framework supports many languages, including JRuby, Jython, Groovy, Jacl, NetRexx, PerlScript, Tcl, and VBScript. If you’re using a Microsoft platform, BSF also supports Windows Script Technologies, so you may have even more choices if you’re running some flavor of Windows.Using the BSF requires two files on your
CLASSPATH—bsf.jar, which is available at http://jakarta.apache.org/bsf/index.html, and commons-logging-1.1.jar, which is available at http://jakarta.apache.org/commons/logging/—in addition to the JAR files for the language you’re using. We’ll point out those requirements as we go. Also be aware that system requirements can change; earlier versions of the BSF did not require the logging .We’ll start our tour of BSF-supported languages with Jython, an implementation of Python written in Java. As you would expect, we must do several things to identify our extension code to Xalan. We’ll cover them, and then look at the source of the extension functions. First we need to define the namespace prefixes we’ll use:<!-- piechart-jython.xsl --><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:svg="http://www.w3.org/2000/svg" xmlns:months="http://www.oreilly.com/xslt/months" xmlns:lxslt="http://xml.apache.org/xslt" xmlns:jython-extension="http://www.jython.org" extension-element-prefixes="jython-extension" exclude-result-prefixes="lxslt">
We’re generating SVG markup, so we need to define theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using Extension Functions from the EXSLT Library
- InhaltsvorschauEarlier we mentioned the EXSLT project, an effort to define a common set of XSLT extension functions. For our next example, we’ll use functions from the EXSLT library. Both Saxon and Xalan have EXSLT support built in, so it’s very easy to use extensions from the EXSLT library.Although a number of XSLT processors support EXSLT, be aware that EXSLT is implemented inconsistently between processors. Not all processors support all functions, and not all functions have the same signature or results.EXSLT provides eight categories of functions:
- Common
- Common functions for data typing and for working with node-sets. These are in the
http://exslt.org/commonnamespace. - Dates and times
- Functions for manipulating dates and times. These are in the
http://exslt.org/dates-and-timesnamespace. - Dynamic
- Functions to dynamically evaluate XPath expressions. These are in the
http://exslt.org/dynamicnamespace. - Functions
- Extension elements and functions that allow you to define your own functions. These are in the
http://exslt.org/functionsnamespace. - Math
- Functions for trigonometry, exponentiation, logarithms, and other miscellaneous mathematical functions. These are in the
http://exslt.org/mathnamespace. - Random
- A single function (
random-sequence( )) that generates a sequence of random values between0and1. It is in thehttp://exslt.org/randomnamespace. - Regular expressions
- Functions that work with regular expressions. These are in the
http://exslt.org/regular-expressionsnamespace. - Sets
- Functions to calculate the difference and intersection between sets. These are in the
http://exslt.org/setsnamespace. - Strings
- Functions for manipulating strings. These are in the
http://exslt.org/stringsnamespace.
Many of the EXSLT functions and elements have been added as part of the language for XSLT 2.0. The EXSLT effort represents the most requested features missing in XSLT 1.0, so it’s not surprising that EXSLT would have a strong impact on the design and features of XSLT 2.0.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Accessing a Database with an Extension Element
- InhaltsvorschauThe first edition of this book included an extension element that accessed an SQL database. Since that time, the Saxon and Xalan processors have added extension libraries that do this for us. We’ll look at how to use those extensions here.Our example here uses the open source Apache Derby database, available at http://db.apache.org/derby/. Here are the Derby commands and SQL statements that create and populate the database:
connect 'jdbc:derby://localhost:1527/books;create=true'; create schema doug; set schema doug; create table compbks (ISBN varchar(10) primary key, title varchar(50), author varchar(50), pages int, price double, publisher varchar(50)); insert into compbks values ('0596527217', 'XSLT', 'Doug Tidwell', 800, 49.95, 'O''Reilly'); insert into compbks values ('0974152129', 'DocBook XSL: The Complete Guide', 'Bob Strayton', 560, 49.95, 'Sagehill Enterprises'); insert into compbks values ('1565925807', 'DocBook: The Definitive Guide', 'Norman Walsh and Leonard Muellner', 652, 39.95, 'O''Reilly'); insert into compbks values ('0596009747', 'XSLT Cookbook', 'Sal Mangano', 751, 49.95, 'O''Reilly'); insert into compbks values ('0596003277', 'Learning XSLT', 'Michael Fitzgerald', 352, 34.95, 'O''Reilly');We create a database namedbooksand a table namedcompbks, then we insert five rows into the table.Saxon’s SQL support requires a username that must match the database schema; that’s why we create the database schemadougand associate it with the database. It also requires a password value, which must be at least one character; we’ll look at those details in just a minute.The Saxon XSLT processor provides a set of extension elements that provide SQL functions. There are extension elements to connect and disconnect from a database, to run a database query, and to do updates, inserts, and deletes on database tables. To keep our example simple, we’ll use<sql:connection>element to connect to a database, then we’ll use<sql:query>to select items from the database andEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating a Photo Album with an Extension Element
- InhaltsvorschauAs a final example, we’ll create an extension element that generates an HTML table that displays all of the photographs in a given directory. The extension element takes three parameters: the directory, how many images are displayed on each row of the table, and whether the filename should be displayed under the photograph. The generated table displays a reduced version of each photograph; each small photo is a link to the actual file. The generated file looks like .
Figure : A photo album generated by an extension elementWe’ll look at three versions of this extension here. The first two are written in Java, one version for Xalan and one version for Saxon. These two processors use different mechanisms to access the code; they also have different mechanisms to return the tree of HTML elements back to the stylesheet. The third version is written in C# for the .NET platform. The .NET version is written as an extension function rather than an element, although it still returns the tree of HTML elements we need. The HTML generated by the three implementations is the same.All of the versions of our extension use this XML source file:<?xml version="1.0"?><!-- photo-album.xml --> <photo-album directory="c:\photos" imagesPerRow="5" includeFilenames="yes"/>The XML source contains the three parameters we need for our extension: the directory that contains the images, the number of images per row, and whether to include the filenames in the table. As we’ll see, the extension code varies widely in the three examples, but the input data and the HTML output is the same.The overall flow of the code is the same in all three extensions:- Get the attributes from the extension element. In some cases, we’ll do that in the stylesheet; in others, the extension element will be able to get its own parameters.
- See whether the requested directory exists. If it doesn’t, create a table that includes a message such as “Directory doesn’t exist.”
- Assuming the directory exists, see whether there are any images inside it. If it doesn’t exist, create a table that includes a message such as “Directory doesn’t contain any images.”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Summary
- InhaltsvorschauIn this chapter, we’ve run the gamut of extension functions and extension elements, demonstrating how to add sophisticated processing power to our stylesheets. We’ve generated many output files from a stylesheet, created JPEGs dynamically, created interactive graphics, interacted with databases, and generated HTML files created with data retrieved from the filesytem.In terms of XSLT itself, we’ve created both extension elements and extension functions, and we’ve returned simple values as well as trees of DOM objects. Most importantly, we’ve demonstrated how to access the XML source document and the extension code in a variety of ways, using different platforms, languages, and XSLT processors. If you master these techniques, there’s practically nothing you can’t do in your stylesheets.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Appendix : XSLT Reference
- InhaltsvorschauThis chapter is a complete reference to all the elements defined in the XSLT specification. To keep the examples simple, most of them generate plain text instead of XML, HTML, or XHTML. That allows us to focus on the XSLT itself instead generating CSS properties, HTML tables, or other details. Where an XML, HTML, or XHTML example is more instructive, we’ll use it of course, but most stylesheets are as simple as possible.
Reference For: [2.0] Attributes common to all XSLT elements
Reference For: [2.0]
<xsl:analyze-string>Reference For:
<xsl:apply-imports>Reference For:
<xsl:apply-templates>Reference For:
<xsl:attribute>Reference For:
<xsl:attribute-set>Reference For:
<xsl:call-template>Reference For: [2.0]
<xsl:character-map>Reference For:
<xsl:choose>Reference For:
<xsl:comment>Reference For:
<xsl:copy>Reference For:
<xsl:copy-of>Reference For:
<xsl:decimal-format>Reference For: [2.0]
<xsl:document>Reference For:
<xsl:element>Reference For:
<xsl:fallback>Reference For:
<xsl:for-each>Reference For: [2.0]
<xsl:for-each-group>Reference For: [2.0]
<xsl:function>Reference For:
<xsl:if>Reference For:
<xsl:import>Reference For: [2.0 – Schema]
<xsl:import-schema>Reference For:
<xsl:include>Reference For:
<xsl:key>Reference For: [2.0]
<xsl:matching-substring>Reference For:
<xsl:message>Reference For: [2.0]
<xsl:namespace>Reference For:
<xsl:namespace-alias>Reference For: [2.0]
<xsl:next-match>Reference For: [2.0]
<xsl:non-matching-substring>Reference For:
<xsl:number>Reference For:
<xsl:otherwise>Reference For:
<xsl:output>Reference For: [2.0]
<xsl:output-character>Reference For:
<xsl:param>Reference For: [2.0]
<xsl:perform-sort>Reference For:
<xsl:preserve-space>Reference For:
<xsl:processing-instruction>Reference For: [2.0]
<xsl:result-document>Reference For: [2.0]
<xsl:sequence>Reference For:
<xsl:sort>Reference For:
<xsl:strip-space>Reference For:
<xsl:stylesheet>Reference For:
<xsl:template>Reference For:
<xsl:text>Reference For:
<xsl:transform>Reference For:
<xsl:value-of>Reference For:
<xsl:variable>Reference For:
<xsl:when>Reference For:
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix : XPath Reference
- InhaltsvorschauThis appendix contains reference information from the XPath specification, including node types, axes, operators, and datatypes.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- XPath Node Types
- InhaltsvorschauThere are seven types of nodes in XPath. (They’re called node kinds in XPath 2.0.) We’ll stick to the reference material here; for more information on the different node types, see our earlier discussion of ” in .The root node is the root of the tree. Unlike all other nodes, it does not have a parent. Its children are the root element for the document, as are any comments or processing instructions that appear outside the document element. The root node does not have an expanded name. It is known as the document node in XPath 2.0.Each element in the original XML document is represented by an element node. The expanded name of the element is its local name, combined with any namespace that is in effect for the element. You can access the different parts of the element name with the
name( ),local-name( ), andnamespace-uri( )functions. Here is an element from an XML document:<xyz:report xmlns:xyz="http://www.xyz.com/">
The values of the three functions for this element node are:name( )xyz:reportlocal-name( )reportnamespace-uri( )http://www.xyz.com/
Attributes of elements in the XML document become XPath attribute nodes. An attribute has an expanded name, just as an element node has. The attribute nodes of a given element node are the attributes explicitly coded on the XML element and any attributes defined with default values in the DTD.Taking a different approach from the Document Object Model, an element node is the parent of its attributes, although the attributes are not the children of the element. In other words, selecting all the children of an element node does not select any attribute nodes that the element node might have.Text nodes simply contain text from an element. If the original text in the XML document contained character or entity references, they are resolved before the XPath text node is created. Similarly, any existing CDATA sections appear as text nodes. You have no way of knowing if a given portion of a text node was originally a character or entity reference or a CDATA section.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - XPath Node Tests
- InhaltsvorschauXPath defines several node tests that can be used to select nodes from the source tree. These node tests allow you to select nodes that can’t be selected any other way. (Although they look and work like functions, they are technically node tests.) The node tests are described here:
text( )- Selects all the text-node children of the context node.
comment( )- Selects all the comment-node children of the context node.
processing-instruction( )- Selects all the processing-instruction children of the context node. Unlike the other node tests defined here,
processing-instruction( )can have an optional argument;processing-instruction('xml-stylesheet')selects all processing instructions with a name ofxml-stylesheet. node( )- Returns all nodes, regardless of type. Using this node test selects all element nodes, attribute nodes, processing-instruction nodes, etc. (Be aware that using
node( )on the child axis does not return any attribute nodes, because attributes are not considered child nodes.) - [2.0]
attribute( ) - Returns any attribute. When used with an attribute name (
attribute(public-domain)), it returns all attributes with the specified name. When used with an attribute name and a datatype (attribute(public-domain, xs:boolean)), it returns all attributes with that specified name and datatype. Finally, when used with a wildcard for the attribute name (attribute(*, xs:boolean)), it returns all attributes with the specified datatype. - [2.0]
element( ) - Returns any element. When used with an element name (
element(author)), it returns all elements with the specified name. When used with an element name and a datatype (element(year-of-birth, xs:gYear)), it returns all elements with that specified name and datatype. Finally, when used with a wildcard for the element name (element(*, xs:gYear)), it returns all elements with the specified datatype.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - XPath Axes
- InhaltsvorschauThe XPath specification defines 13 different axes; each axis contains various nodes. The nodes that are in a given axis depend on the context node. All 13 axes, excerpted from our more involved discussion in ” in , are listed here.
childaxis- Contains the children of the context node. As we’ve already mentioned, the XPath expressions
child::lines/child::lineandlines/lineare equivalent. If an XPath expression (such assonnet) doesn’t have an axis specifier, thechildaxis is used by default. parentaxis- Contains the parent of the context node, if there is one. (If the context node is the root node, the
parentaxis returns an empty node-set.) As a step in an XPath expression, theparentaxis can be abbreviated with the double period (..); this moves up to the current node’s parent. If the<first-name>and<last-name>elements are both children of the<author>element, and the context node is the<first-name>element, the expressions../last-name,parent::author/last-nameandparent::*/last-nameare equivalent. If the context node does not have a parent, this axis returns an empty node-set. selfaxis- Contains the context node itself. As a step in an XPath expression, the
selfaxis can be abbreviated with a single period (.). The expressions.,self::node( ), andself::*are equivalent in XSLT 1.0.[2.0] In XSLT 2.0, theselfaxis selects the context item, which might not be a node. If the context item is an atomic value, the expressionsself::node( )andself::*cause the XSLT processor to raise an error. In this case, the only way to access theselfaxis is with a period. If the context item is a node, theselfaxis works just as it did in XSLT 1.0. attributeaxis- Contains the attributes of the context node. If the context node is not an element node, this axis is empty. The
attributeaxis can be abbreviated with the at sign (
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - The XPath Context
- InhaltsvorschauThe context in an XPath expression consists of several things:
- Context node
- The node currently being evaluated. [2.0] If the context item is a node, the context node is the same as the context item. If the context item is an atomic value, the context node is undefined.
- [2.0] Context item
- The item currently being evaluated. This is the equivalent of the context node in XPath 1.0; the name reflects the fact that the context can be focused on an atomic value instead of a node.
- Context position
- A nonzero positive integer that indicates the position of the context node within the set of context nodes. The XPath function
position( )returns the context . - Context size
- A nonzero positive integer that indicates the number of nodes in the current context. The XPath function
last( )returns the context size. - Variable bindings
- A set of variables that are in scope for the current context. Each one is represented by a variable name and an object that represents its value.
- Functions
- A set of functions visible to the current context. Each function is represented by a mapping between a function name and the actual code to be invoked. Each function takes zero or more arguments and returns a single result. XPath defines a number of core functions that are always available; XSLT defines additional that go beyond those defined in the XPath specification. Any extension functions defined in the stylesheet are visible as well.
- Namespace declarations
- The set of namespace declarations visible to the current context. Each one consists of a namespace prefix and the URI with which it is associated.
- [2.0] Default namespace
- The default namespace is defined by the
xpath-default-namespaceattribute. If no such attribute exists on any elements that enclose the context item, the default namespace is null, regardless of any default namespace declarations (xmlns="..."
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - XPath 1.0 Datatypes
- InhaltsvorschauXPath 1.0 and XSLT 1.0 define five datatypes, described in the list that follows. The
result tree fragmenttype is defined by XSLT 1.0 and is specific to transformations; the other four are defined by XPath and are generic to any technology that uses XPath. The four XPath datatypes are tersely defined in section 1 of the XPath specification; section 11.1 of the XSLT specification defines result tree fragments.node-set- A set of nodes. The set can be empty or it can contain any number of nodes.[2.0] In XSLT 2.0, the
node-sethas been replaced by the sequence. boolean- The value
trueorfalse. Be aware that the stringstrueandfalsehave no special meaning or value in XPath. If you need to use the boolean values themselves, use the functionstrue( )andfalse( ). number- A floating-point number. All numbers in XPath and XSLT 1.0 are implemented as floating-point numbers; the
integerorintdatatype does not exist in XPath and XSLT 1.0. To be specific, all numbers are implemented as IEEE 754 floating-point numbers, the same standard used by the Javafloatanddoubleprimitive types. In addition to ordinary numbers, there are five special values for numbers: positive and negative infinity, positive and negative zero, andNaN, the special symbol for anything that is not a number. string- Zero or more characters, as defined in the XML specification.
result tree fragment- A temporary tree. You can create one with an
<xsl:variable>element that uses content (instead of theselectattribute) to initialize its value. A result tree fragment can be copied to the result tree with the<xsl:copy-of>element. It may also be converted to a string with the<xsl:value-of>element.[2.0] In XSLT 2.0, theresult tree fragmentdatatype no longer exists. There is no difference between a tree constructed from an input document and a tree constructed using a variable.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - XPath 2.0 Datatypes
- InhaltsvorschauXML Schema defines 19 primitive datatypes, and five others (
xs:anyAtomicType,xs:untyped,xs:untypedAtomic,xs:dayTimeDuration, andxs:yearMonthDuration) were added to the XML Schema namespace by the XQuery 1.0 and XPath 2.0 Data Model spec. We’ll review those briefly here.XPath 1.0 used thenode-setdatatype as its basic data structure; XPath 2.0 uses sequences. Like anode-set, a sequence can contain the node types we covered earlier in this appendix, but it can also contain atomic values of the types listed here.Here are the 24 datatypes:xs:anyAtomicType- The base type for all primitive atomic types, such as
xs:integerorxs:string. This datatype was added by XQuery 1.0 and XPath 2.0. xs:anyURI- A Uniform Resource Identifier. The value can be absolute or relative, and it can also have a fragment reference identifier. The value should follow the rules for URI syntax as defined in RFC 2396 and amended in RFC 2732.
xs:base64Binary- Arbitrary binary data represented using the Base64 alphabet defined in RFC 2045. Legal characters are the basic alpha characters and digits
[a-zA-Z0-9], along with the plus sign (+), the forward slash (/), and the equals sign (=). Anxs:base64Binaryvalue can also contain any number of whitespace characters. xs:boolean- The value
trueorfalse. In XSLT and XPath, the strings"true"and"false"have no special meaning. To generate boolean values, use the functionstrue( )andfalse( )instead. xs:date- A date with four components: year, month, day, and an optional timezone. The format of a complete
xs:datevalue is1995-04-21-05:00, where1995is the year,04is the month,21is the day, and-05:00is the timezone. An optional minus sign can appear before the year, indicating a date before the current era.Be aware that the values for month and day must be two digits long, and the value for the year must be at least four digits long. The value1995-4-21
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Operators and Keywords
- InhaltsvorschauHere is the complete list of operators and keywords in XPath:
!=(not equal)- Compares its two operands and returns
trueif the first operand is not equal to the second. (Complete details on how comparisons work are in the section ” in .) ( )- Contains a parenthesized expression. In addition to using parentheses in mathematical expressions, parentheses are required around test conditions in the
if. *(occurrence indicator)- Represents zero or more of an item.
*(multiplication)- Multiplies its two operands together. In XPath 1.0, the two operands must be numbers or values that can be converted to numbers.[2.0] In XPath 2.0, we can multiply
xs:yearMonthDurations andxs:dayTimeDurationsby numeric values. Valid combinations are:xs:yearMonthDuration * xs:doublexs:dayTimeDuration * xs:double
+(occurrence indicator)- Represents zero or one of an item.
+(addition)- Adds its two operands. In XPath 1.0, the two operands must be numbers or values that can be converted to numbers.[2.0] In XPath 2.0, we can add dates, times, and durations in addition to numeric values. Valid combinations are:
xs:yearMonthDuration + xs:yearMonthDurationxs:dayTimeDuration + xs:dayTimeDurationxs:dateTime + xs:yearMonthDurationxs:dateTime + xs:dayTimeDurationxs:date + xs:yearMonthDurationxs:date + xs:dayTimeDurationxs:time + xs:dayTimeDuration
+(unary plus)- Returns its operand with the sign unchanged. This operator doesn’t change its operand at all.
- [2.0]
,(sequence operator) - The comma operator concatenates items into a sequence. For example, using
select="((1, 2, 3), (4, 5), 6)"creates the new sequence(1, 2, 3, 4, 5, 6). –(unary minus)- Returns the negation of its operand.
–(subtraction)- Subtracts its second operand from the first. In XPath 1.0, the two operands must be numbers or values that can be converted to numbers.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Operator Precedence—XPath 1.0
- InhaltsvorschauHere is the precedence of operators in XPath 1.0, arranged from lowest to highest:
orand=,!=,<,<=,>,>=+(addition),–(subtraction)*(multiplication),div,mod|–(unary minus),+(unary plus)/,//[ ],( ),{ }
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Operator Precedence—XQuery 1.0 and XPath 2.0
- InhaltsvorschauHere is the precedence of operators in XQuery 1.0 and XPath 2.0, arranged from lowest to highest:
,(comma)for,some,every,iforandeq,ne,lt,le,gt,ge,=,!=,<,<=,>,>=,is,<<,>>to+(addition),–(subtraction)*(multiplication),div,idiv,modunion,|intersect,exceptinstance oftreat ascastable ascast as–(unary minus),+(unary plus)?,*(occurrence indicator),+(occurrence indicator)/,//[ ],( ),{ }
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix : XSLT, XPath, and XQuery
- InhaltsvorschauThis section lists all functions defined by XSLT 1.0 and 2.0, XPath 1.0 and 2.0, and XQuery 1.0.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Kinds of Functions
- InhaltsvorschauIncluding the new functions added by XSLT 2.0 and XPath 2.0, there are now more than 100 useful functions. The following presents a categorized list of them.XPath 2.0 provides accessor functions to expose certain properties of items, sequences, and documents:These functions work with Boolean values:There are two functions for creating
xs:dateTimeandxs:QNamevalues:The XPath context has a number of properties. These functions allow us to access those :The functions , , and are actually defined in XSLT 2.0.These functions help you resolve unique identifiers and references between elements and attributes:These functions let you work with date, time and duration values. These are the XML Schema typesxs:date,xs:dateTime,xs:dayTimeDuration,xs:duration,xs:time, andxs:yearMonthDuration:The , , and functions are defined in XSLT 2.0.These functions perform operations on nodes:These functions work with numeric values. Some of them work with a single number, while others work with node-sets or sequences:These functions work with QNames (the XML Schema datatypexs:QName):These functions are part of the regular expression support in XSLT 2.0 and XPath 2.0:These functions work with [1.0] node-sets or [2.0] sequences:These functions help you manipulate strings:Here are functions that don’t fit under any other category:There are several functions that allow you to specify a collation function that compares or sorts text based on the conventions of specific languages. (All of these have been listed previously as string or sequence functions. This subset contains all the functions that work with collations.)[2.0]abs( )Returns the absolute value of a numeric argument.Syntaxnumeric?abs(numeric?)
InputA numeric value.OutputThe absolute value of the given numeric value.Defined inXQuery 1.0 and XPath 2.0 Functions and Operators section 6.4, “Functions on Numeric Values.”ExampleEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix : XML Schema Overview
- InhaltsvorschauThis appendix is a brief overview of XML Schema. For in-depth information about XML Schemas, I highly recommend Eric van der Vlist’s XML Schema, published by O’Reilly. The XML Schema Primer at the W3C is very useful as well.We’ll cover three topics in this appendix. First, we’ll look at how to declare elements and attributes in XML Schema. Next we’ll go through the many ways to create types. Finally, we’ll look at how to use XML Schemas in XSLT stylesheets. The focus here is on the aspects of XML Schema that apply to XSLT. A schema-aware XSLT processor can use a schema to validate a document or element. If we’re working with types declared in an XML Schema, a schema-aware processor can use those datatypes just like
xs:string,xs:date, or any other basic datatype.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Declaring Elements and Attributes
- InhaltsvorschauThe most common task in XML Schema is declaring elements and attributes. We’ll start with an empty element, then move on to more sophisticated things.Here’s how we create an empty element:
<?xml version="1.0" encoding="UTF-8"?><!-- empty1.xsd --> <xs:schema xmlns="http://www.oreilly.com/xslt" targetNamespace="http://www.oreilly.com/xslt" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="empty1"> <xs:complexType/> </xs:element> </xs:schema>
That’s it. The empty<xs:complexType>means that our element can’t have any attributes and it can’t have any content. It’s not terribly useful, but that’s how it works. An XML document that uses this schema looks like this:<?xml version="1.0" encoding="utf-8"?><!-- empty1.xml --> <empty1 xmlns="http://www.oreilly.com/xslt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.oreilly.com/xslt empty1.xsd"/>Although we said our empty element couldn’t contain attributes, it looks like we have three of them here. The first two (xmlnsandxmlns:xsi) are actually namespace declarations, not attributes. Thexsi:schemaLocationattribute (it actually is an attribute) associates the XML Schema with our document. In the schema, thetargetNamespaceattribute defines the namespace used by this schema; it’s also the default namespace (xmlns="http://www.oreilly.com/xslt") in the schema and the XML document. To tie everything together, thexsi:schemaLocationattribute in our XML document tells the XML parser where to find the schema that defines what a valid document looks like.There are other ways of using namespaces, but we won’t cover them in any detail here. For example, our XML document could look like this:<ora:empty1 xmlns:ora="http://www.oreilly.com/xslt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.oreilly.com/xslt empty1.xsd"/>
We took out the default namespace and declared a namespace prefix that matches the namespace in the XML Schema. Because the XML document doesn’t have a default namespace, we have to qualify all of the elements with the namespace prefix that matches the target namespace of the schema. That’s why our element is nowEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Defining Datatypes
- InhaltsvorschauSome of the elements and attributes we’ve created to this point use the built-in XML Schema datatypes. The ability to define our own types is a powerful feature of the language. Custom datatypes are the feature most directly related to XSLT. With a schema-aware processor, we can use our own datatypes for validation. We’ll cover the ways to create datatypes in the next section.We don’t cover the basic datatypes (
xs:string,xs:integer, etc.) used by XML Schema here. See the discussion of ” in for all the details on those datatypes.Everything we’ve done to this point has used anonymous types. That means we used<xs:simpleType>or<xs:complexType>, but we didn’t give those types a name. That was OK for our simple schemas because we didn’t want to reuse those datatypes outside the element in which they were defined. From now on, we’ll give our datatypes a name so we can use them whenever we need to. Here’s the difference between an anonymous type and a named type:<?xml version="1.0" encoding="UTF-8"?><!-- content4.xsd --> <xs:schema xmlns="http://www.oreilly.com/xslt" targetNamespace="http://www.oreilly.com/xslt" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="content4a"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="color" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:complexType name="content4b-type"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="color" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:element name="content4b" type="content4b-type"/> </xs:schema>
The first element in the schema,<content4a>, uses an anonymous type. The second element has the exact same structure, but it uses the named datatype we created. The difference, of course, is that we can use the named datatype anywhere, while the mous type exists only inside the declaration of elementEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using an XML Schema in a Stylesheet
- InhaltsvorschauNow that we’ve covered how schemas work, we’ll take a look at how to use them in XSLT. The
<xsl:import-schema>element lets us import an XML Schema into our stylesheet directly. In addition to<xsl:import-schema>, an XML document can reference a schema with thexsi:noNamespaceSchemaLocationorxsi:schemaLocationattributes. If our stylesheet is set up correctly, the XSLT processor can use the referenced schema to validate data.The<xsl:import-schema>element allows you to import an XML Schema. The schema is imported and processed before any input documents are processed. This allows you to define datatypes and validation rules before the XSLT processor begins to transform the input document. This element is only supported by schema-aware XSLT 2.0 .The element has two optional parameters:namespace, which defines the namespace URI for the schema, andschema-location, which contains the URI of the schema file itself.<xsl:import-schema>can useschema-locationto import a file, or it can contain the actual XML Schema within the stylesheet. We’ll look at a couple of examples here; for more complete examples, see the discussion of the element.The simplest way to import a schema into a stylesheet is to use the URI:<?xml version="1.0"?><!-- import-schema.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:po="http://www.oreilly.com/xslt"> <xsl:import-schema namespace="http://www.oreilly.com/xslt" schema-location="po.xsd" /> <xsl:output method="text"/> <xsl:template match="schema-element(po:purchase-order)"> <xsl:text>
This is a test of the <xsl:import-</xsl:text> <xsl:text>schema> element.

</xsl:text> <xsl:text>Here are all the items in this purchase </xsl:text> <xsl:text>order:
</xsl:text> <xsl:for-each select="po:items/po:item"> <xsl:text> * </xsl:text> <xsl:value-of select="po:partname"/> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:template> <xsl:template match="*"> <xsl:message terminate="yes"> <xsl:text>This is not a valid purchase order!</xsl:text> </xsl:message> </xsl:template> </xsl:stylesheet>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix : [2.0] Regular Expressions
- InhaltsvorschauThe regular expression language used by XSLT 2.0, XPath 2.0, and XQuery 1.0 is a superset of the XML Schema regular expression language. Regular expressions are used in the XSLT 2.0 element and the XPath 2.0 and XQuery 1.0 functions , , and .This appendix defines the syntax and capabilities of regular expressions in XSLT 2.0, XPath 2.0, and XQuery 1.0. The details of regular expressions are defined in XQuery 1.0 and XPath 2.0 Functions and Operators section 7.6, “String Functions that Use Pattern Matching.”[XPath] The Functions and Operators spec extends the XML Schema regular expression in several ways. Features unique to the XPath 2.0 and XQuery 1.0 regular expression language are indicated with the text [XPath].Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Simple Expressions
- InhaltsvorschauThe simplest regular expression is just a string of text. The regular expression
abcmatches the stringabc. We’re merely searching for a series of characters inside some data. For this case,contains('abc', 'abc')does the same thing.Regular expressions exist to do far more than search for a literal string; they help us find data that matches a pattern. We can use character sets to specify groups of characters. The regular expression[abc]dmatches two characters in which the first character isa,b, orc, followed by the characterd.We can also negate a character set, asking for all the characters not in the character set. To do this, add a caret (^) to the start of the character set. The regular expression[^abc]dmatches two characters in which the first character is anything excepta,b, orc, followed byd.Ranges give us a shorthand way of defining character sets. The character set[0-9]specifies the digits 0 through 9, while the character set[a-zA-Z]specifies all of the unaccented letters used in Western European languages. A range can be negated just like any other character set;[^0-9]specifies anything except the digits.Ranges can also be subtracted from each other. The range[A-Z-[IOQ]]matches any unaccented uppercase letter exceptI,O, orQ.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Subexpressions
- InhaltsvorschauIt’s often useful to split a regular expression into subexpressions. A subexpression is surrounded by parentheses, and can be modified by a quantifier to define how often (or if) an expression can occur. For example, this regular expression matches a phone number in the format
999-999-9999:([0-9]{3})-([0-9]{3})-([0-9]{4})The regular expression has three subexpressions, each of which matches a group of digits. XSLT 2.0 provides theregex-group( )function to retrieve the part of the analyzed string that matches a particular subexpression. Here’s an example:<?xml version="1.0" encoding="utf-8"?><!-- subexpressions1.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:analyze-string select="'Call me at 919-555-1212, please.'" regex="([0-9]{{3}})-(\p{{Nd}}{{3}})-([0-9]{{4}})"> <xsl:matching-substring> <xsl:text>The matching substring is '</xsl:text> <!-- <xsl:value-of select=”."/> does the same thing here --> <xsl:value-of select="regex-group(0)"/> <xsl:text>'
</xsl:text> <xsl:text>The formatted string is '</xsl:text> <xsl:value-of select="('(', regex-group(1), ') ', regex-group(2), '-', regex-group(3), '''')" separator=""/> </xsl:matching-substring> </xsl:analyze-string> </xsl:template> </xsl:stylesheet>
(The curly braces in this example are doubled so that the XSLT processor knows this is not an attribute value template.) Notice that the regular expression contains two hyphens that are not part of any subexpression. The functionregex-group(0)returns the entire portion of the string that matches. That means everything from the first character that matches the regular expression to the last character that matches the regular expression. In our test string here,regex-group(0)returns919-555-1212, but not any of the other characters in the string. (Asking for the context item does the same thing.) That includes the two hyphens that aren’t in any of the subexpressions. Here are the results of the stylesheet:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Quantifiers
- InhaltsvorschauA quantifier specifies how many times (or if) something occurs. There are three quantifier characters and a syntax for specifying quantities more explicitly. For example,
(a|b)?cmatchesac,bc, andc, because the question mark indicates zero or one instances of a pattern. Here are all the quantifiers and their syntax:?- Zero or one of a pattern.
*- Zero or more of a pattern.
+- One or more of a pattern.
{x}- The pattern must occur exactly
xtimes. The pattern(a|b){3}matchesaaaandabb, but notab. {x,}- The pattern must occur at least
xtimes. The pattern(a|b){3,}matchesaaaandaaaaaaaaa, but notaa. {x,y}- The pattern must occur at least
xtimes, but no more thanytimes. The pattern(a|b){2,5}matchesaaandaaa, but notaaaaaa.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [XPath] Reluctant Quantifiers
- InhaltsvorschauBy default, a regular expression or subexpression matches the longest possible string. The quantifiers
+,*, and?match as many characters as possible. Adding a question mark to the end of a quantifier causes the expression or subexpression to match the shortest possible string. The quantifiers are modified as follows:a+?- Matches
aonce a??- Matches
a, either once or not at all (works only in thematches( )function; more on this later in this section) a*?- Matches
a, zero times or once (works only in thematches( )function; more on this later in this section) a{x}?- Matches
a, exactlyxtimes (in this case the reluctant qualifier doesn’t change ) a{x,}?- Matches
aexactlyxtimes (the comma is irrelevant—a reluctant quantifier matches only the minimum length) a{x,y}?- Matches
aexactlyxtimes (the second number,y, is irrelevant—a reluctant quantifier matches only the minimum length)
As an example, we’ll use thereplace( )function. We’ll put square brackets around each match in the original string. The normal quantifier and the reluctant quantifier work differently, as we’ll see. Here’s the stylesheet:<?xml version="1.0" encoding="utf-8"?><!-- reluctant.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>Original string: 'Call me at 19195551212'
</xsl:text> <xsl:text> replace($x, '([0-9]+)', '[$1]'):
 </xsl:text> <xsl:value-of select="replace('Call me at 19195551212', '([0-9]+)', '[$1]')"/> <xsl:text>
</xsl:text> <xsl:text> replace($x, '(([0-9])+?)', '[$1]'):
 </xsl:text> <xsl:value-of select="replace('Call me at 19195551212', '(([0-9])+?)', '[$1]')"/> <xsl:text>
</xsl:text> <xsl:text> replace($x, '(([0-9]){2,4}?)', '[$1]'):
 </xsl:text> <xsl:value-of select="replace('Call me at 19195551212', '(([0-9]){2,4}?)', '[$1]')"/>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Processing Modes
- InhaltsvorschauThere are four flags that change how regular expressions are evaluated:
s- Regular expressions are evaluated in what the specs refer to as “dot-all” mode. When this flag is used, the dot operator (
.) matches any character. Under normal processing (without thesflag), the dot operator matches any character except the newline character (#xA). This flag is useful when you want to match strings that might include a newline character.Perl and other languages refer to this as “single-line” mode; that’s why the abbreviation for “dot-all” mode iss. m- Regular expressions are evaulated in multiline mode. By default, the (
^) matches the start of the entire string, while$matches the end of the entire string. In multiline mode,^matches the start of any line within the string, and$matches the end of any line within the string. i- Regular expressions are evaluated in case-insensitive mode. The regular expression
"a"matches both"a"and"A".Note that Unicode issues can complicate this greatly. For example, the XQuery 1.0 and XPath 2.0 Functions and Operators spec gives the example of the Unicode sign for degrees Kelvin (K), which is the letter"K". The combination ofregex="k"andflags="i"matches the Kelvin sign as well as the letters"k"(k) and"K"(K).Other Unicode characters don’t convert to letters. For example, the Unicode symbol for the Roman numeralI(Ⅰ) looks like the letterI, but does not convert to one. x- All whitespace characters (
#x9,#xA,#xDand#x20) are removed from the regular expression before any comparison is done. In other words, with thexflag, the regular expressions"John Smith"and"JohnSmith"are the same. This flag is useful when you want to break a long regular expression into multiple lines to make it easier to read.
The flags can be combined in any order. The attributesEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - [XPath] Anchors
- InhaltsvorschauIn XML Schema, regular expressions are anchored; in other words, the regular expression is assumed to start at the beginning of the text and end at the end of the text. That means the expression
abcmatches only the three-character stringabc. If there are any extra characters before or after the lettersabc, XML Schema does not consider the string a match.The regular expression language in XPath 2.0 doesn’t work that way. When we use any of the regular expression functions or elements, a string matches if it contains the regular expression anywhere inside it. In other words, using XPath’s regular expression language, bothabcandI know my abc'smatch the expressionabc. XPath provides the traditional anchor operators used in other regular expression languages. The caret (^) matches the start of the string, while the dollar sign ($) matches the end of the string. If multiline mode is on (-m), the caret matches the start of the string and any character immediately following a newline. Similarly, in multiline mode, the dollar sign matches the end of the string and any character immediately before a newline.Here’s an example that illustrates how the anchors work:<?xml version="1.0" encoding="utf-8"?><!-- anchors.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>matches('abcdefghij', 'cde'): </xsl:text> <xsl:value-of select="if (matches('abcdefghij', 'cde')) then 'It''s a match!' else 'No match'"/> <xsl:text>
matches('abcdefghij', 'cde$'): </xsl:text> <xsl:value-of select="if (matches('abcdefghij', 'cde$')) then 'It''s a match!' else 'No match'"/> <xsl:text>
matches('abcdefghij', 'hij$'): </xsl:text> <xsl:value-of select="if (matches('abcdefghij', 'hij$')) then 'It''s a match!' else 'No match'"/> <xsl:text>
matches('ab&#xA;cdefghij', '^cde', 'm'): </xsl:text> <xsl:value-of
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Back-references
- InhaltsvorschauA back-reference allows you to refer to a previously matched subexpression within the regular expression itself. As an example, say you want to find words that begin and end with the same two letters. The expression
([a-z]{2})(.*)\1does the trick. The\1represents whatever two characters matched the first subexpression. The\2represents the match for the second subexpression,\3represents the match for the third subexpression, and so on. (Notice that although the references go backwards, counting subexpressions goes from left to right.)Here’s a sample stylesheet:<?xml version="1.0" encoding="utf-8"?><!-- back-reference.xsl --> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:text>Using back-references to find words that begin 
</xsl:text> <xsl:text> and end with the same two letters:

</xsl:text> <xsl:text> replace($x, '([a-z]{2})(.*)\1', '$1--$2--$1')
</xsl:text> <xsl:text> edited: </xsl:text> <xsl:value-of select="replace('edited', '([a-z]{2})(.*)\1', '$1--$2--$1')"/> <xsl:text>
 editor: </xsl:text> <xsl:value-of select="replace('editor', '([a-z]{2})(.*)\1', '$1--$2--$1')"/> <xsl:text>
 educated: </xsl:text> <xsl:value-of select="replace('educated', '([a-z]{2})(.*)\1', '$1--$2--$1')"/> <xsl:text>
 orator: </xsl:text> <xsl:value-of select="replace('orator', '([a-z]{2})(.*)\1', '$1--$2--$1')"/> </xsl:template> </xsl:stylesheet>
The stylesheet generates these results:Using back-references to find words that begin and end with the same two letters: replace($x, '([a-z]{2})(.*)\1', '$1--$2--$1') edited: ed--it--ed editor: editor educated: ed--ucat--ed orator: or--at--orFor the wordsedited,educated, andorator, the regular expression matches. Thereplace( )function writes out the two letters at the start and end of the word, with whatever was in between them offset by double hyphens. The wordEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Metacharacters
- InhaltsvorschauWithin a regular expression, most characters represent themselves. For example, the regular expression
Arepresents a capital A. There are, of course, special characters that are processed differently:.- By default, this matches any character except the newline character. In dot-all mode, this matches the newline character as well.
^- By default, this represents the beginning of the string literal. In multiline mode, this represents the beginning of a line within the string.[XPath] Use of the caret to indicate that the beginning of a string or line is an addition to the regular expression syntax defined by XML Schema.The caret can also be used inside a character class expression to indicate the negation of that character set. For example,
[a-f]represents the lettersathroughf, while[^a-f]represents every character except the lettersathroughf. $- [XPath] By default, this represents the end of the string literal. In multiline mode, this represents the end of a line within the string.
\- Escapes the following character.
|- The union operator. The expression
A|Bmatches bothAandB. It does not matchAB. ?- Zero or one of a pattern. For example,
A[A-Z]?ZmatchesAZandABZ, but notABCZ. *- Zero or more of a pattern. For example,
A[A-Z]*matches any string of uppercase basic Latin characters that starts with A and is followed by zero or more uppercase Latin characters. The stringsA,ABC,AA, andAREALLYLONGSTRINGall match this . +- One or more of a pattern. For example,
A[A-Z]+matches any string of uppercase basic Latin characters that starts with A and is followed by one or more uppercase characters. The stringsAA,AD, andADDmatch this expression, butAdoes not. (- Starts a subexpression. For example, in the expression
A(BCD)+, the parentheses define the subexpressionBCD, which can appear once or not at all. This expression matchesAandABCD. )- Ends a subexpression.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Single-Character Escapes
- InhaltsvorschauThe regular expression language provides escapes for some special characters. They are:
\n- The newline character (

) \r- The return character (

) \t- The tab character (
	) \\- The backslash character (
\) \|- The vertical bar character (
|) \.- A period (
.) \-- The hyphen or minus character (
-) \^- The circumflex accent (
^) \?- A question mark (
?) \*- An asterisk (
*) \+- The plus sign (
+) \{- A left curly bracket (
{) \}- A right curly bracket (
}) \(- A left parenthesis (
() \)- A right parenthesis (
)) \[- A left square bracket (
[) \]- A right square bracket (
])
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Multiple-Character Escapes
- InhaltsvorschauThere are also escapes that represent multiple characters. They are:
\s- Any whitespace character
\S- Anything other than a whitespace character
\d- Any digit
\D- Anything other than a digit
\w- Any word character. Word characters are all characters except the punctuation, separator and other characters (the character groups defined with P, Z and C).
\W- Anything other than a word character.
\i- Any character that can be the first letter of an XML name. That includes the (
_), the colon (:), and characters of all the world’s languages defined as letters in the XML specification. \I- Anything other than a character that can be the first letter of an XML name.
\c- Any character that can be used in an XML name. That includes all of the characters that can appear as the first character (
\i), plus the period (.), hyphen (–), and the characters defined as digits, combining characters and extenders in the XML . \C- Anything other than a character that can be used in an XML name.
\p- A character in the following named character group. For example,
\p{Nd}matches a numeric digit, while\p{IsThai}matches a Thai character. \P- Anything other than a character in the following named character group. For example,
\P{Nd}matches anything except a numeric digit, while\P{IsThai}matches anything except a Thai character.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Character Groups
- InhaltsvorschauFor convenience, we can use character groups to stand for groups of characters. Specifying
Lis simpler than specifying all letters, particularly if you have to allow for the many thousands of characters defined in the Unicode standard. The character groups are used with the\pand\Poperators;\p{L}means all letters, while\P{L}means except letters. The character groups and their names are defined in the Character Database, available online here: http://www.unicode.org/Public/UNIDATA/UCD.html.The following lists are the character groups.L- All letters.
Lu- All uppercase letters.
Ll- All lowercase letters.
Lt- Letters in titlecase, such as
C5;, which is a single character that combines a capital letter D with a small z that has a caron. Lm- Modifiers (characters such as
ª, which is the feminine ordinal indicator [ª]). Lo- Other letters, including ideographs. The Hebrew letter alef (
א) is an example.
M- All marks.
Mn- Nonspacing marks (characters such as
́, which is the Unicode combining acute ). Mc- Spacing combining marks.
Me- Enclosing marks.
N- All numbers, including alternate forms such as circled (Unicode character
①, which is the circled digit one) and parenthesized (Unicode characterপ, the parenthesized digit one). Nd- Decimal digits (as opposed to
Ⅶ, which is the Unicode character for the Roman numeral seven). Nl- Numbers as letters (as opposed to digits; the aforementioned Unicode character
Ⅶcharacter applies here). No- Other numeric characters, such as
½, which is the single character for the fraction½.
P- All punctuation characters.
Pc- Connector characters, such as
_, which is the underscore character. Pd- Dashes, such as the hyphen-minus character,
-. Ps- Opening (start) characters, such as a left curly bracket (
{). Pe- Closing characters, such as a right curly bracket (
}). Pi- Initial quote marks. Be aware that in some languages, an initial quote mark might actually be in the set of closing characters (
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix : XSLT Formatting Codes
- InhaltsvorschauThis appendix lists the formatting codes for numbers, dates, and times used in XSLT. These codes are used in the following elements and functions:
format-date( ),format-time( )andformat-dateTime( ), defined in XSLT 2.0 section 16.5, “Formatting Dates and Times.”- The
formatattribute of the<xsl:number>element, defined in XSLT 1.0 section 7.7, “Numbering.” The capabilities of theformatattribute were enhanced in XSLT 2.0 section 12, “Numbering.” - The
<xsl:decimal-format>element, defined in XSLT 1.0 section 12.3, “Number Formatting.” - The
format-number( )function, defined in XSLT 1.0 and XSLT 2.0.
Most of the formatting codes for numbers were defined in XSLT 1.0. The main additions for number formatting added by XSLT 2.0 are the ordinal and language options. The date and time formatting functions were added in XSLT 2.0. There are three types of formatting codes we’ll list here:- The date and time format codes defined by the ISO 8601 standard for the representation of dates and times. You use these format codes for creating new
xs:date,xs:time,xs:dateTime,xs:duration,xs:dayTimeDuration, andxs:yearMonthDurationvalues. - The date and time formatting codes defined in XSLT 2.0 section 16.5, “Formatting Dates and Times.” Use these codes to format parts of
xs:date,xs:time,xs:dateTime,xs:duration,xs:dayTimeDuration, andxs:yearMonthDurationvalues. - The numbering formatting codes defined in XSLT 1.0 section 7.7, “Numbering,” and section 12.3, “Number Formatting.” These codes were extended in XSLT 2.0 section 12, “Numbering,” and section 16.4, “Number Formatting.”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Formatting Codes for Numbers
- InhaltsvorschauThe following subsections detail the codes for formatting numbers. These are used by the
<xsl:decimal-format>and<xsl:number>elements and by theformat-number( ).describes the characters that represent parts of a number. They are used by theformat-number( )function and by the<xsl:decimal-format>element.Table : Number formatting codes Code Meaning #Represents a digit. Trailing or leading zeroes are not displayed. Formatting the number 4.0 with the string "#.##"returns the string"4".0Represents a digit. Unlike the #character, the 0 always displays a zero. Formatting the number 4.1 with the string"#.00"returns the string"4.10"..Represents the decimal point. -Represents the minus sign. ,Is the grouping separator. ;Separates the positive-number pattern from the negative-number pattern. %Indicates that a number should be displayed as a percentage. The value is multiplied by 100, and then displayed as a percentage. Formatting the number .76with the string"##%"returns the string"76%".\u2030Is the Unicode character for the per-thousand (per-mille) sign. The value will be multiplied by 1000, and then displayed as a per mille. Formatting the number .768with the string"###\u2030"returns the string"768‰".The<xsl:decimal-format>element lets us define named formats for decimal numbers. Each named format is a group of settings for the properties discussed in .Table : Parts of decimal formats Part name Meaning Default value nameGives a name to this format. N/Adecimal-separatorDefines the character (usually either a period or comma) used as the decimal point. This character is used both in the format string and in the output. .(period)grouping-separatorDefines the character (usually either a period or comma) used as the thousands separator. This character is used both in the format string and in the output. Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Formatting Codes for Dates and Times
- Inhaltsvorschaudescribes the codes defined for the different parts of
xs:date,xs:dateTime, andxs:timevalues.Table : Parts of dates and times Specifier Meaning Default presentation modifier YYear (absolute value) 1 MMonth in year 1 DDay in month 1 dDay in year 1 FDay of week n WWeek in year 1 wWeek in month 1 HHour in day (24 hours) 1 hHour in half-day (12 hours) 1 Pa.m./p.m. marker n mMinute in hour 01 sSecond in minute 01 fFractional seconds 1 ZTimezone as a time offset from UTC—or if an alphabetic modifier is present, the conventional name of a timezone (such as PST) 1 zTimezone as a time offset using GMT—for example, GMT+1 1 CCalendar: the name or abbreviation of a calendar name n EEra: the name of a baseline for the numbering of years—for example, the reign of a monarch n A presentation modifier is a code that defines how a part of a date or time value should be displayed. For example,FNndisplays the day of the week as the capitalized name of the day, using the current language. If your system is set up to use English and the calendar used in the United States, the name of the day of the week (FNn) for 15 August 2007 isWednesday. The formatting codeFWwdisplays the numeric valueFour. Using German with the same codes on the same date displays the valuesMittwochandDrei(Wednesday is the third day of the week in the European calendar). describes the presentation modifiers.Table : Presentation modifiers Modifier Meaning 1The value as a number with one or more digits: 0, 1, 2, 3, 4, .... 01The value as a number with two or more digits: 00, 01, 02, ... 09, 10, 11, ... 99, 100, 101, .... An XSLT processor is free to support other numbering schemes. To quote an example from the spec, a formatting code of ๑tells the processor to use Thai numbering. See the documentation for your processor to see which numbering schemes it supports.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Appendix : XSLT 2.0 Migration Guide
- InhaltsvorschauThis appendix contains some hits and suggestions for migrating your XSLT 1.0 stylesheets to XSLT 2.0. Most XSLT 1.0 stylesheets will work with an XSLT 2.0 processor, but there are a few errors you need to watch for. We’ll also look at some of the new features in XSLT 2.0. If none of the new features in XSLT 2.0 and XPath 2.0 provide any value for you, there’s no reason to migrate your stylesheets. (It’s very unlikely that nothing in XSLT 2.0 and XPath 2.0 can help you, but still....)Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Powerful New Features in XSLT 2.0 and XPath 2.0
- InhaltsvorschauWe’ll discuss some of the most important new features in XSLT 2.0 and XPath 2.0. This isn’t a complete list, but it should give you an idea of whether XSLT 2.0 will simplify your stylesheets and applications.In XSLT 1.0 stylesheets, tail recursion was a common technique. String replacement, for example, requires a recursive template that replaces the first instance of a substring, and then reinvokes itself with the remainder of the string. In XSLT 2.0, you can use the
replace( )function. Recursive templates are much more difficult to write and maintain; if you can replace them with simpler code in an XSLT 2.0 stylesheet, it’s worth it. See the section ” in for a more detailed example. Another good example is in the section ” in .Grouping in XSLT 2.0 is orders of magnitude easier than it was in XSLT 1.0. The<xsl:for-each-group>element can make your code as much as 80maller, depending on the complexity of your XSLT 1.0 stylesheets. If your existing stylesheets do grouping, the new grouping support in XSLT 2.0 can make them much more elegant. See the section ” in for all the details.If type checking and validation are important to your application, moving to XSLT 2.0 is a must. A basic XSLT 2.0 processor supports all the basic datatypes of XML Schema, while a schema-aware processor lets you define your own datatypes and use them in your stylesheets. Datatypes and schema support are discussed in .Although XSLT 1.0 supports functions such ascontains( ),substring-before( ), andsubstring-after( ), these are no substitute for regular expressions. The regular expression support in XSLT 2.0 is very powerful and flexible. See the discussions of the element and the , , and functions for the details on regular expression support. has a complete overview of the regular expression syntax used in XSLT 2.0 and XPath 2.0.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Potential Errors
- InhaltsvorschauThere are several differences between XSLT 1.0 and XSLT 2.0 that can cause fatal errors. If you’re going to migrate your 1.0 stylesheets to 2.0, you’ll need to handle all of those differences.In XSLT 1.0, you could use
<xsl:call-template>to invoke a template with as many parameters as you wanted. If any of those parameters weren’t defined in the template, they were ignored. In XSLT 2.0, using<xsl:call-template>with an undefined parameter causes a fatal error.It’s not an error to pass undefined parameters with<xsl:apply-templates>,<xsl:apply-imports>, or<xsl:next-match>.Many times XSLT 1.0 stylesheets passed extra parameters because they might eventually be needed by another template. Every time another template was invoked (via<xsl:apply-templates>or<xsl:call-template>), the extra parameters were passed along. XSLT 2.0 features much more sophisticated tunnel parameters. A tunnel parameter isn’t passed to each template, so it makes your stylesheets much cleaner. See the section ” in for more information.This potential problem is a static error. That means the XSLT 2.0 processor can tell whether you’re passing the wrong number of parameters to a template without actually transforming an XML document.XSLT 1.0 featured a simplenumberdatatype. Math operations, particularly anything dealing with division by zero, work differently in XSLT 2.0.To make things more complicated, XSLT 2.0 handles different kinds of numbers differently. Dividing anxs:integerorxs:decimalby zero is a fatal error, while dividing anxs:doubleorxs:floatreturnsINF(infinity).The simplest way to avoid this error is to addversion="1.0"to the element. That causes the XSLT 2.0 processor to evaluate the expression in XSLT 1.0 mode, so your stylesheets will behave as they always have.<xsl:variableversion="1.0" name="ratio" select="$orders div $returns"/>A more sophisticated approach is to use the new XPathifoperator. For example, you could change the code like this:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Approaches to Migration
- InhaltsvorschauThere are several approaches to migrating your stylesheets to XSLT 2.0. We’ll outline them here.Obviously this is the most drastic option. If you don’t have a large investment in XSLT 1.0 code, you can start writing XSLT 2.0 stylesheets from scratch. It’s more likely that you would replace a few stylesheets used in parts of your application, and then use your expertise and experience to rewrite larger and more sophisticated stylesheets.This requires a significant commitment in development resources and training. Having the resources to develop stylesheets from scratch is one thing; those resources need to understand all of the new features of XSLT 2.0 and how to take advantage of them.The simplest approach to migration is to change the
versionattribute of the<xsl:stylesheet>element to2.0. If you have any static errors, the XSLT 2.0 processor will flag those immediately. You can then fix the errors or useversion="1.0"on specific XSLT elements so the XSLT 2.0 processor will use backwards-compatible mode.If you use this approach, it’s important to check for the dynamic errors we covered in the previous section. If you addversion="2.0"to your stylesheet and it runs with an XML document, that doesn’t mean it will run with every document. As with any modified code, testing is crucial before you put your stylesheet into production.A less drastic way to migrate to XSLT 2.0 is to look through your stylesheets for templates that could be replaced with XSLT 2.0 features. For example, if you have a recursive template to do string replacement, replacing that with the newreplace( )function will simplify your code. (It’s likely it will perform better as well.) Anything that uses recursion or extension functions is a candidate for replacement with XSLT 2.0.Another thing to look for is using variables extensively. If you use a variable to store the result generated by a named template, consider replacing the named template with anEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Zurück zu XSLT
