Appendix A. XSLT ReferenceThis chapter is a complete reference to all the elements defined in the XSLT specification.
CategoryInstruction Required AttributesNone. Optional AttributesNone. ContentNone. <xsl:apply-imports> is an empty element. Appears in<xsl:apply-imports> appears inside a template. Defined inXSLT section 5.6, Overriding Template Rules. ExampleHere is a short XML file we'll use to illustrate <xsl:apply-imports>: <?xml version="1.0"?> <test> <p>This is a test XML document used by several of our sample stylesheets.</p> <question> <text>When completed, the Eiffel Tower was the tallest building in the world.</text> <true correct="yes">You're correct! The Eiffel Tower was the world's tallest building until 1930.</true> <false>No, the Eiffel Tower was the world's tallest building for over 30 years.</false> </question> <question> <text>New York's Empire State Building knocked the Eiffel Tower from its pedestal.</text> <true>No, that's not correct.</true> <false correct="yes">Correct! New York's Chrysler Building, completed in 1930, became the world's tallest.</false> </question> </test> Here's the stylesheet we'll import: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <body> <xsl:for-each select="//text|//true|//false"> <p> <xsl:apply-templates select="."/> </p> </xsl:for-each> </body> </html> </xsl:template> <xsl:template match="text"> <xsl:text>True or False: </xsl:text><xsl:value-of select="."/> </xsl:template> <xsl:template match="true|false"> <b><xsl:value-of select="name()"/>:</b> <br/> <xsl:value-of select="."/> </xsl:template> </xsl:stylesheet> This template provides basic formatting for the <true> and <false> elements, as shown in Figure A-1. Figure A-1. Document generated with basic formattingWe'll illustrate <xsl:apply-imports> with this stylesheet, which imports the other stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="imported.xsl"/> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title>A Brief Test</title> <style> <xsl:comment> p.question {font-size: 125%; font-weight: bold} p.right {color: green} p.wrong {color: red} </xsl:comment> </style> </head> <body> <h1>A Brief Test</h1> <xsl:for-each select="//question"> <table border="1"> <xsl:apply-templates select="text"/> <xsl:apply-templates select="true|false"/> </table> <br/> </xsl:for-each> </body> </html> </xsl:template> <xsl:template match="text"> <tr bgcolor="lightslategray"> <td> <p class="question"> <xsl:apply-imports/> </p> </td> </tr> </xsl:template> <xsl:template match="true|false"> <tr> <td> <xsl:choose> <xsl:when test="@correct='yes'"> <p class="right"> <xsl:apply-imports/> </p> </xsl:when> <xsl:otherwise> <p class="wrong"> <xsl:apply-imports/> </p> </xsl:otherwise> </xsl:choose> </td> </tr> </xsl:template> </xsl:stylesheet> Using <xsl:apply-imports> allows us to augment the behavior of the imported templates. Our new stylesheet produces this document: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>A Brief Test</title> <style> <!-- p.question {font-size: 125%; font-weight: bold} p.right {color: green} p.wrong {color: red} --> </style> </head> <body> <h1>A Brief Test</h1> <table border="1"> <tr bgcolor="lightslategray"> <td> <p class="question">True or False: When completed, the Eiffel Tower was the tallest building in the world.</p> </td> </tr> <tr> <td> <p class="right"> <b>true:</b> <br>You're correct! The Eiffel Tower was the world's tallest building until 1930.</p> </td> </tr> <tr> <td> <p class="wrong"> <b>false:</b> <br>No, the Eiffel Tower was the world's tallest building for over 30 years.</p> </td> </tr> </table> <br> <table border="1"> <tr bgcolor="lightslategray"> <td> <p class="question">True or False: New York's Empire State Building knocked the Eiffel Tower from its pedestal.</p> </td> </tr> <tr> <td> <p class="wrong"> <b>true:</b> <br>No, that's not correct.</p> </td> </tr> <tr> <td> <p class="right"> <b>false:</b> <br>Correct! New York's Chrysler Building, completed in 1930, became the world's tallest.</p> </td> </tr> </table> <br> </body> </html> When rendered, this stylesheet looks like Figure A-2. Figure A-2. Document generated with <xsl:apply-imports>
CategoryInstruction Required AttributesNone. Optional Attributes
ContentThe <xsl:apply-templates> element can contain any number of <xsl:sort> and <xsl:with-param> elements. In most cases, <xsl:apply-templates> is empty. Appears in<xsl:apply-templates> appears inside a template. Defined inXSLT section 5.4, Applying Template Rules. ExampleIn our case study (see Chapter 9, "Case Study: The Toot-O-Matic"), we needed to create several different outputs from the same data. We addressed this need with the mode attribute of the <xsl:apply-templates> element. Here's the main template (match="/"): <xsl:template match="/"> <xsl:apply-templates select="tutorial" mode="build-main-index"/> <redirect:write select="concat($curDir, $fileSep, 'index.html')"> <xsl:apply-templates select="tutorial" mode="build-main-index"/> </redirect:write> <xsl:apply-templates select="tutorial" mode="build-section-indexes"/> <xsl:apply-templates select="tutorial" mode="build-individual-panels"/> <xsl:apply-templates select="tutorial" mode="generate-graphics"/> <xsl:apply-templates select="tutorial" mode="generate-pdf-file"> <xsl:with-param name="page-size" select="'ltr'"/> </xsl:apply-templates> <xsl:apply-templates select="tutorial" mode="generate-pdf-file"> <xsl:with-param name="page-size" select="'a4'"/> </xsl:apply-templates> <xsl:apply-templates select="tutorial" mode="generate-zip-file"/> </xsl:template> Notice that this example selects the <tutorial> element eight times, but applies templates with a different mode (or different parameters for the same mode) each time.
CategoryInstruction Required Attributes
Optional Attributes
ContentAn XSLT template. In other words, you can build the contents of an attribute with <xsl:choose> elements, <xsl:text>, and <xsl:value-of> elements. Appears in<xsl:attribute> appears inside a template. Defined inXSLT section 7.1.3, Creating Attributes with xsl:attribute. ExampleFor this example, we want to create an HTML table from the following XML document: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> We'll create a table that has each <listitem> in a separate row in the right column of the table, and a single cell with rowspan equal to the number of <listitem> elements in the XML document on the left. Clearly we can't hardcode a value for the rowspan attribute because the number of <listitem>s can change. This stylesheet uses <xsl:attribute> to do what we want: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title><xsl:value-of select="list/title"/></title> </head> <body> <xsl:apply-templates select="list"/> </body> </html> </xsl:template> <xsl:template match="list"> <table border="1" width="75%"> <tr> <td bgcolor="lightslategray" width="100" align="right"> <xsl:attribute name="rowspan"> <xsl:value-of select="count(listitem)"/> </xsl:attribute> <p style="font-size: 125%"> <xsl:value-of select="title"/> </p> </td> <td> <xsl:value-of select="listitem[1]"/> </td> </tr> <xsl:for-each select="listitem"> <xsl:if test="position() > 1"> <tr> <td> <xsl:value-of select="."/> </td> </tr> </xsl:if> </xsl:for-each> </table> </xsl:template> </xsl:stylesheet> Here is the generated HTML document: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Albums I've bought recently:</title> </head> <body> <table width="75%" border="1"> <tr> <td align="right" width="100" rowspan="7" bgcolor="lightslategray"> <p style="font-size: 125%">Albums I've bought recently:</p> </td><td>The Sacred Art of Dub</td> </tr> <tr> <td>Only the Poor Man Feel It</td> </tr> <tr> <td>Excitable Boy</td> </tr> <tr> <td>Aki Special</td> </tr> <tr> <td>Combat Rock</td> </tr> <tr> <td>Talking Timbuktu</td> </tr> <tr> <td>The Birth of the Cool</td> </tr> </table> </body> </html> Notice that the <td> element had several attributes hardcoded on it; those attributes are combined with the attribute we created with <xsl:attribute>. You can have as many <xsl:attribute> elements as you want, but they must appear together as the first thing inside the element to which you add attributes. Figure A-3 shows how our generated HTML document looks. Figure A-3. Document with generated AttributesBe aware that in this instance, we could have used an attribute-value template. You could generate the value of the rowspan attribute like this: <td bgcolor="lightslategray" rowspan="{count(listitem)}" width="100" align="right"> The expression in curly braces ({}) is evaluated and replaced with whatever its value happens to be. In this case, count(listitem) returns the number 7, which becomes the value of the rowspan attribute.
CategoryTop-level element Required Attributes
Optional Attributes
ContentOne or more <xsl:attribute> elements. Appears in<xsl:stylesheet>. <xsl:attribute-set> is a top-level element and can only appear as a child of <xsl:stylesheet>. Defined inXSLT section 7.1.4, Named Attribute Sets. ExampleFor this example, we'll create a stylesheet that defines attribute sets for regular text, emphasized text, and large text. Just for variety's sake, we'll use the Extensible Stylesheet Language Formatting Objects (XSL-FO) specification to convert our XML document into a PDF file. Here's our stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method="html"/> <xsl:attribute-set name="regular-text"> <xsl:attribute name="font-size">12pt</xsl:attribute> <xsl:attribute name="font-family">sans-serif</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="emphasized-text" use-attribute-sets="regular-text"> <xsl:attribute name="font-style">italic</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="large-text" use-attribute-sets="regular-text"> <xsl:attribute name="font-size">18pt</xsl:attribute> <xsl:attribute name="font-weight">bold</xsl:attribute> <xsl:attribute name="space-after.optimum">21pt</xsl:attribute> </xsl:attribute-set> <xsl:template match="/"> <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master margin-right="75pt" margin-left="75pt" page-height="11in" page-width="8.5in" margin-bottom="25pt" margin-top="25pt" master-name="main"> <fo:region-before extent="25pt"/> <fo:region-body margin-top="50pt" margin-bottom="50pt"/> <fo:region-after extent="25pt"/> </fo:simple-page-master> <fo:page-sequence-master master-name="standard"> <fo:repeatable-page-master-alternatives> <fo:conditional-page-master-reference master-name="main" odd-or-even="any"/> </fo:repeatable-page-master-alternatives> </fo:page-sequence-master> </fo:layout-master-set> <fo:page-sequence master-name="standard"> <fo:flow flow-name="xsl-region-body"> <xsl:apply-templates select="list"/> </fo:flow> </fo:page-sequence> </fo:root> </xsl:template> <xsl:template match="list"> <fo:block xsl:use-attribute-sets="large-text"> <xsl:value-of select="title"/> </fo:block> <fo:list-block provisional-distance-between-starts="0.4cm" provisional-label-separation="0.15cm"> <xsl:for-each select="listitem"> <fo:list-item start-indent="0.5cm" space-after.optimum="17pt"> <fo:list-item-label> <fo:block xsl:use-attribute-sets="regular-text">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block xsl:use-attribute-sets="emphasized-text"> <xsl:value-of select="."/> </fo:block> </fo:list-item-body> </fo:list-item> </xsl:for-each> </fo:list-block> </xsl:template> </xsl:stylesheet> Notice that both the emphasized-text and large-text attribute sets use the regular-text attribute set as a base. In the case of large-text, the font-size attribute defined in the large-text attribute set overrides the font-size attribute included from the regular-text attribute set. We'll apply our stylesheet to the following XML document: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> The stylesheet generates this messy-looking file of formatting objects, which describe how the text of our XML source document should be rendered: <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> <fo:layout-master-set> <fo:simple-page-master master-name="main" margin-top="25pt" margin-bottom="25pt" page-width="8.5in" page-height="11in" margin-left="75pt" margin-right="75pt"> <fo:region-before extent="25pt"/> <fo:region-body margin-bottom="50pt" margin-top="50pt"/> <fo:region-after extent="25pt"/> </fo:simple-page-master> <fo:page-sequence-master master-name="standard"> <fo:repeatable-page-master-alternatives> <fo:conditional-page-master-reference odd-or-even="any" master-name="main"/> </fo:repeatable-page-master-alternatives> </fo:page-sequence-master> </fo:layout-master-set> <fo:page-sequence master-name="standard"> <fo:flow flow-name="xsl-region-body"> <fo:block font-size="18pt" font-family="sans-serif" font-weight="bold" space-after.optimum="21pt">A few of my favorite albums</fo:block> <fo:list-block provisional-label-separation="0.15cm" provisional-distance-between-starts="0.4cm"> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">A Love Supreme</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">Beat Crazy</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">Here Come the Warm Jets</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">Kind of Blue</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">London Calling</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">Remain in Light</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">The Joshua Tree</fo:block> </fo:list-item-body> </fo:list-item> <fo:list-item space-after.optimum="17pt" start-indent="0.5cm"> <fo:list-item-label> <fo:block font-size="12pt" font-family="sans-serif">*</fo:block> </fo:list-item-label> <fo:list-item-body> <fo:block font-size="12pt" font-family="sans-serif" font-style="italic">The Indestructible Beat of Soweto</fo:block> </fo:list-item-body> </fo:list-item> </fo:list-block> </fo:flow> </fo:page-sequence> </fo:root> Be aware that as of this writing (May 2001), the XSL-FO specification isn't final, so there's no guarantee that these formatting objects will work correctly with future XSL-FO tools. Here's how we invoke the Apache XML Project's FOP (Formatting Objects to PDF translator) tool to create a PDF: java org.apache.fop.apps.CommandLine test.fo test.pdf The FOP tool creates a PDF that looks like Figure A-4. Figure A-4. PDF generated from an XSL-FO file
CategoryInstruction Required Attributes
Optional AttributesNone. ContentThis element can contain any number of optional <xsl:with-param> elements. Appears in<xsl:call-template> appears inside a template. Defined inXSLT section 6, Named Templates. ExampleThe <xsl:call-template> element gives you an excellent way to create modular stylesheets. In our case study (see Chapter 9, "Case Study: The Toot-O-Matic"), we need to generate common items at the top and bottom of every HTML page we generate. We build a navigation bar and title bar at the top of each panel in a similar way. Rather than intermingle these templates with the rest of our stylesheets, we put the templates for the common sections of the HTML pages in a separate stylesheet, then reference them when needed. <xsl:call-template name="dw-masthead"/> <xsl:call-template name="dw-title-bar"/> <xsl:call-template name="dw-nav-bar"> <xsl:with-param name="includeMain" select="'youBetcha'"/> <xsl:with-param name="sectionNumber" select="$sectionNumber"/> <xsl:with-param name="position" select="$pos"/> <xsl:with-param name="last" select="$last"/> <xsl:with-param name="topOrBottom" select="'top'"/> <xsl:with-param name="oneOrTwo" select="'two'"/> </xsl:call-template> <!-- Processing for the main body of the page goes here --> <xsl:call-template name="dw-nav-bar"> <xsl:with-param name="includeMain" select="'youBetcha'"/> <xsl:with-param name="sectionNumber" select="$sectionNumber"/> <xsl:with-param name="position" select="$pos"/> <xsl:with-param name="last" select="$last"/> <xsl:with-param name="topOrBottom" select="'bottom'"/> <xsl:with-param name="oneOrTwo" select="'two'"/> </xsl:call-template> <xsl:call-template name="dw-footer"/> In this code fragment, we've invoked four templates to generate the look and feel we want our HTML pages to have. If we decide to change the look and feel of our tutorials, changing those four named templates lets us change the look and feel by simply transforming the XML document again. See Section 9.5.5, "Generating the Individual Panels" in Chapter 9, "Case Study: The Toot-O-Matic" for details on how this works.
CategoryInstruction Required AttributesNone. Optional AttributesNone. ContentContains one or more <xsl:when> elements and might contain a single <xsl:otherwise> element. Any <xsl:otherwise> elements must be the last element inside <xsl:choose>. Appears in<xsl:choose> appears inside a template. Defined inXSLT section 9.2, Conditional Processing with xsl:choose. ExampleHere's an example that uses <xsl:choose> to select the background color for the rows of an HTML table. We cycle among four different values, using <xsl:choose> to determine the value of the bgcolor attribute in the generated HTML document. Here's the XML document we'll use: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> And here's our stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="list/title"/> </title> </head> <body> <h1><xsl:value-of select="list/title"/></h1> <table border="1"> <xsl:for-each select="list/listitem"> <tr> <td> <xsl:attribute name="bgcolor"> <xsl:choose> <xsl:when test="position() mod 4 = 0"> <xsl:text>papayawhip</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 1"> <xsl:text>mintcream</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 2"> <xsl:text>lavender</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>whitesmoke</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:value-of select="."/> </td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> We use <xsl:choose> to determine the background color of each generated <td> element. Here's the generated HTML document, which cycles through the various background colors: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Albums I've bought recently:</title> </head> <body> <h1>Albums I've bought recently:</h1> <table border="1"> <tr> <td bgcolor="mintcream">The Sacred Art of Dub</td> </tr> <tr> <td bgcolor="lavender">Only the Poor Man Feel It</td> </tr> <tr> <td bgcolor="whitesmoke">Excitable Boy</td> </tr> <tr> <td bgcolor="papayawhip">Aki Special</td> </tr> <tr> <td bgcolor="mintcream">Combat Rock</td> </tr> <tr> <td bgcolor="lavender">Talking Timbuktu</td> </tr> <tr> <td bgcolor="whitesmoke">The Birth of the Cool</td> </tr> </table> </body> </html> When rendered, our HTML document looks like Figure A-5. Figure A-5. Document cycling among different background colors
CategoryInstruction Required AttributesNone. Optional AttributesNone. ContentAn XSLT template. Appears in<xsl:comment> appears in a template. Defined inXSLT section 7.4, Creating Comments. ExampleHere's a stylesheet that generates a comment to define CSS styles in an HTML document: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title>XSLT and CSS Demo</title> <style> <xsl:comment> p.big {font-size: 125%; font-weight: bold} p.green {color: green; font-weight: bold} p.red {color: red; font-style: italic} </xsl:comment> </style> </head> <body> <xsl:apply-templates select="list/title"/> <xsl:apply-templates select="list/listitem"/> </body> </html> </xsl:template> <xsl:template match="title"> <p class="big"><xsl:value-of select="."/></p> </xsl:template> <xsl:template match="listitem"> <xsl:choose> <xsl:when test="position() mod 2"> <p class="green"><xsl:value-of select="."/></p> </xsl:when> <xsl:otherwise> <p class="red"><xsl:value-of select="."/></p> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> This stylesheet creates three CSS styles inside an HTML comment. We'll apply the stylesheet to this document: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> The stylesheet will apply one CSS style to the <title> element and will alternate between two CSS styles for the <listitem>s. Here's the generated HTML: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>XSLT and CSS Demo</title> <style> <!-- p.big {font-size: 125%; font-weight: bold} p.green {color: green; font-weight: bold} p.red {color: red; font-style: italic} --> </style> </head> <body> <p class="big">Albums I've bought recently:</p> <p class="green">The Sacred Art of Dub</p> <p class="red">Only the Poor Man Feel It</p> <p class="green">Excitable Boy</p> <p class="red">Aki Special</p> <p class="green">Combat Rock</p> <p class="red">Talking Timbuktu</p> <p class="green">The Birth of the Cool</p> </body> </html> When rendered, the document looks like Figure A-6. Figure A-6. Document with generated comment nodes
CategoryInstruction Required AttributesNone. Optional Attributes
ContentAn XSLT template. Appears in<xsl:copy> appears in a template. Defined inXSLT section 7.5, Copying. ExampleWe'll demonstrate <xsl:copy> with an example that copies an element to the result tree. Notice that we do not specifically request that the attribute nodes of the source document be processed, so the result tree will not contain any attributes. Here is our stylesheet: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet> We'll test our stylesheet with the following XML document: <?xml version="1.0"?> <report> <title>Miles Flown in 2001</title> <month sequence="01"> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month sequence="02"> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month sequence="03"> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month sequence="04"> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report> Here are the results: <?xml version="1.0" encoding="UTF-8"?> <report> <title>Miles Flown in 2001</title> <month> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report> The <xsl:copy> does a shallow copy, which gives you more control over the output than the <xsl:copy-of> element does. However, you must explicitly specify any child nodes or attribute nodes you would like copied to the result tree. The <xsl:apply-templates> element selects all text, element, comment, and processing-instruction children of the current element; without this element, the result tree would contain only a single, empty <report> element. Compare this approach with the example in the <xsl:copy-of> element.
CategoryInstruction Required Attributes
Optional AttributesNone. ContentNone. <xsl:copy-of> is an empty element. Appears in<xsl:copy-of> appears inside a template. Defined inXSLT section 11.3, Using Values of Variables and Parameters with xsl:copy-of. ExampleWe'll demonstrate <xsl:copy-of> with a simple stylesheet that copies the input document to the result tree. Here is our stylesheet: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet> We'll test our stylesheet with the following document: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> When we transform the XML document, the results are strikingly similar to the input document: <?xml version="1.0" encoding="UTF-8"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> The only difference between the two documents is that the stylesheet engine has added an encoding to the XML declaration. Compare this to the example in the <xsl:copy> element.
CategoryTop-level element Required AttributesNone. Optional Attributes
ContentNone. <xsl:decimal-format> is an empty element. Appears in<xsl:decimal-format> is a top-level element and can only appear as a child of <xsl:stylesheet>. Defined inXSLT section 12.3, Number Formatting. ExampleHere is a stylesheet that defines two <decimal-format>s: <?xml version="1.0" encoding="ISO-8859-1" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:months="Lookup table for month names"> <xsl:output method="text"/> <months:name sequence="01">January</months:name> <months:name sequence="02">February</months:name> <months:name sequence="03">March</months:name> <months:name sequence="04">April</months:name> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:decimal-format name="f1" decimal-separator=":" grouping-separator="/"/> <xsl:decimal-format name="f2" infinity="Really, really big" NaN="[not a number]"/> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:text>Tests of the <decimal-format> element:</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:text> format-number(1528.3, '#/###:00', 'f1')=</xsl:text> <xsl:value-of select="format-number(1528.3, '#/###:00;-#/###:00', 'f1')"/> <xsl:value-of select="$newline"/> <xsl:text> format-number(1 div 0, '###,###.00', 'f2')=</xsl:text> <xsl:value-of select="format-number(1 div 0, '###,###.00', 'f2')"/> <xsl:value-of select="$newline"/> <xsl:text> format-number(blue div orange, '#.##', 'f2')=</xsl:text> <xsl:value-of select="format-number(blue div orange, '#.##', 'f2')"/> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select="report/month"> <xsl:text> </xsl:text> <xsl:value-of select="document('')/*/months:name[@sequence=current()/@sequence]"/> <xsl:text> - </xsl:text> <xsl:value-of select="format-number(miles-flown, '##,###')"/> <xsl:text> miles flown, </xsl:text> <xsl:value-of select="format-number(miles-earned, '##,###')"/> <xsl:text> miles earned.</xsl:text> <xsl:value-of select="$newline"/> <xsl:text> (</xsl:text> <xsl:value-of select="format-number(miles-flown div sum(//miles-flown), '##%')"/> <xsl:text> of all miles flown, </xsl:text> <xsl:value-of select="format-number(miles-earned div sum(//miles-earned), '##%')"/> <xsl:text> of all miles earned.)</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:text> Total miles flown: </xsl:text> <xsl:value-of select="format-number(sum(//miles-flown), '##,###')"/> <xsl:text>, total miles earned: </xsl:text> <xsl:value-of select="format-number(sum(//miles-earned), '##,###')"/> </xsl:template> </xsl:stylesheet> We'll use this stylesheet against the following document: <?xml version="1.0"?> <report> <title>Miles Flown in 2001</title> <month sequence="01"> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month sequence="02"> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month sequence="03"> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month sequence="04"> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report> When we process this document with the stylesheet, here are the results: Tests of the <decimal-format> element: format-number(1528.3, '#/###:00', 'f1')=1/528:30 format-number(1 div 0, '###,###.00', 'f2')=Really, really big format-number(blue div orange, '#.##', 'f2')=[not a number] January - 12,379 miles flown, 35,215 miles earned. (15% of all miles flown, 15% of all miles earned.) February - 32,857 miles flown, 92,731 miles earned. (39% of all miles flown, 39% of all miles earned.) March - 19,920 miles flown, 76,725 miles earned. (24% of all miles flown, 32% of all miles earned.) April - 18,903 miles flown, 31,781 miles earned. (22% of all miles flown, 13% of all miles earned.) Total miles flown: 84,059, total miles earned: 236,452
CategoryInstruction Required Attributes
Optional Attributes
ContentAn XSLT template. Appears in<xsl:element> appears inside a template. Defined inXSLT section 7.1.2, Creating Elements with xsl:element. ExampleWe'll use a generic stylesheet that copies the input document to the result tree, with one exception: all attributes in the original documents are converted to child elements in the result tree. The name of the new element will be the name of the format attribute, and its text will be the value of the attribute. Because we don't know the name of the attribute until we process the XML source document, we must use the <xsl:element> element to create the result tree. Here's how our stylesheet looks: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:for-each select="@*"> <xsl:element name="{name()}"> <xsl:value-of select="."/> </xsl:element> </xsl:for-each> <xsl:apply-templates select="*|text()"/> </xsl:element> </xsl:template> </xsl:stylesheet> This stylesheet uses the <xsl:element> element in two places: first to create a new element with the same name as the original element, and second to create a new element with the same name as each attribute. We'll apply the stylesheet to this document: <?xml version="1.0"?> <report> <title>Miles Flown in 2001</title> <month sequence="01"> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month sequence="02"> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month sequence="03"> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month sequence="04"> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report> Here are our results: <?xml version="1.0" encoding="UTF-8"?> <report> <title>Miles Flown in 2001</title> <month><sequence>01</sequence> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month><sequence>02</sequence> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month><sequence>03</sequence> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month><sequence>04</sequence> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report> The <xsl:element> element created all the elements in the output document, including the <sequence> elements that were created from the sequence attributes in the original document.
CategoryInstruction Required AttributesNone. Optional AttributesNone. ContentAn XSLT template. Appears in<xsl:fallback> appears inside a template. Defined inXSLT section 15, Fallback. ExampleHere is a stylesheet that uses <xsl:fallback> to terminate the transformation if an extension element can't be found: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:db="xalan://DatabaseExtension" extension-element-prefixes="db"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title><xsl:value-of select="report/title"/></title> </head> <body> <h1><xsl:value-of select="report/title"/></h1> <xsl:for-each select="report/section"> <h2><xsl:value-of select="title"/></h2> <xsl:for-each select="dbaccess"> <db:accessDatabase> <xsl:fallback> <xsl:message terminate="yes"> Database library not available! </xsl:message> </xsl:fallback> </db:accessDatabase> </xsl:for-each> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet> When we use this stylesheet to transform a document, the <xsl:fallback> element is processed if the extension element can't be found: Database library not available! Processing terminated using xsl:message In this case, the extension element is the Java class DatabaseExtension. If, for whatever reason, that class can't be loaded, the <xsl:fallback> element is processed. Note that the <xsl:fallback> element is processed only when the extension element can't be found; if the code that implements that extension element is found, but fails, it must be handled some other way. Also be aware that the exact format of the message and the gracefulness of stylesheet termination will vary from one XSLT processor to the next.
CategoryInstruction Required Attributes
Optional AttributesNone. Content<xsl:for-each> contains a template that is evaluated against each of the selected nodes. The <xsl:for-each> element can contain one or more <xsl:sort> elements to order the selected nodes before they are processed. All <xsl:sort> elements must appear first, before the template begins. Appears in<xsl:for-each> appears inside a template. Defined inXSLT section 8, Repetition. ExampleWe'll demonstrate the <xsl:for-each> element with the following stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:variable name="complicatedVariable"> <xsl:choose> <xsl:when test="count(//listitem) > 10"> <xsl:text>really long list</xsl:text> </xsl:when> <xsl:when test="count(//listitem) > 5"> <xsl:text>moderately long list</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>fairly short list</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:text>Here is a </xsl:text> <xsl:value-of select="$complicatedVariable"/> <xsl:text>:</xsl:text> <xsl:value-of select="$newline"/> <xsl:variable name="listitems" select="list/listitem"/> <xsl:call-template name="processListitems"> <xsl:with-param name="items" select="$listitems"/> </xsl:call-template> </xsl:template> <xsl:template name="processListitems"> <xsl:param name="items"/> <xsl:for-each select="$items"> <xsl:value-of select="position()"/> <xsl:text>. </xsl:text> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:for-each> </xsl:template> </xsl:stylesheet> In this stylesheet, we use an <xsl:param> named items to illustrate the <xsl:for-each> element. The items parameter contains some number of <listitem> elements from the XML source document; the <xsl:for-each> element iterates through all those elements and processes each one. We'll use our stylesheet with the following XML document: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> When we run the transformation, here are the results: Here is a moderately long list: 1. A Love Supreme 2. Beat Crazy 3. Here Come the Warm Jets 4. Kind of Blue 5. London Calling 6. Remain in Light 7. The Joshua Tree 8. The Indestructible Beat of Soweto The <xsl:for-each> element has iterated through all the <listitem> elements from the XML source document and has processed each one.
CategoryInstruction Required Attributes
Optional AttributesNone. ContentAn XSLT template. Appears in<xsl:if> appears inside a template. Defined inXSLT section 9.1, Conditional Processing with xsl:if. ExampleWe'll illustrate the <xsl:if> element with the following stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:text>Here are the odd-numbered items from the list:</xsl:text> <xsl:value-of select="$newline"/> <xsl:for-each select="list/listitem"> <xsl:if test="(position() mod 2) = 1"> <xsl:number format="1. "/> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> This stylesheet uses the <xsl:if> element to see if a given <listitem>'s position is an odd number. If it is, we write it to the result tree. We'll test our stylesheet with this XML document: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> When we run this transformation, here are the results: Here are the odd-numbered items from the list: 1. A Love Supreme 3. Here Come the Warm Jets 5. London Calling 7. The Joshua Tree
CategoryTop-level element Required Attributes
Optional AttributesNone. ContentNone. <xsl:import> is an empty element. Appears in<xsl:import> is a top-level element and can appear only as a child of <xsl:stylesheet>. Defined inXSLT section 2.6.2, Stylesheet Import. ExampleHere is a simple stylesheet that we'll import: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:apply-templates select="list/title"/> <xsl:apply-templates select="list/listitem"/> </xsl:template> <xsl:template match="title"> <xsl:value-of select="."/> <xsl:text>: </xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template match="listitem"> <xsl:text>HERE IS LISTITEM NUMBER </xsl:text> <xsl:value-of select="position()"/> <xsl:text>: </xsl:text> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:template> </xsl:stylesheet> We'll test both this stylesheet and the one that imports it with this XML document: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> When we process our XML source document with this stylesheet, here are the results: A few of my favorite albums: HERE IS LISTITEM NUMBER 1: A Love Supreme HERE IS LISTITEM NUMBER 2: Beat Crazy HERE IS LISTITEM NUMBER 3: Here Come the Warm Jets HERE IS LISTITEM NUMBER 4: Kind of Blue HERE IS LISTITEM NUMBER 5: London Calling HERE IS LISTITEM NUMBER 6: Remain in Light HERE IS LISTITEM NUMBER 7: The Joshua Tree HERE IS LISTITEM NUMBER 8: The Indestructible Beat of Soweto Now we'll use <xsl:import> in another stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:import href="listitem.xsl"/> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:apply-templates select="list/title"/> <xsl:apply-templates select="list/listitem"/> </xsl:template> <xsl:template match="listitem"> <xsl:value-of select="position()"/> <xsl:text>. </xsl:text> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:template> </xsl:stylesheet> Here are the results created by our second stylesheet: A few of my favorite albums: 1. A Love Supreme 2. Beat Crazy 3. Here Come the Warm Jets 4. Kind of Blue 5. London Calling 6. Remain in Light 7. The Joshua Tree 8. The Indestructible Beat of Soweto Notice that both stylesheets had a template with match="listitem". The template in the imported stylesheet has a lower priority, so it is not used. Only the imported stylesheet has a template with match="title", so the imported template is used for the <title> element.
CategoryTop-level element Required Attributes
Optional AttributesNone. ContentNone. <xsl:include> is an empty element. Appears in<xsl:include> is a top-level element and can appear only as a child of <xsl:stylesheet>. Defined inXSLT section 2.6.1, Stylesheet Inclusion. ExampleThe <xsl:include> element is a good way to break your stylesheets into smaller pieces. (Those smaller pieces are often easier to reuse.) In our case study (see Chapter 9, "Case Study: The Toot-O-Matic"), we had a number of different stylesheets, each of which contained templates for a particular purpose. Here's how our <xsl:include> elements look: <xsl:include href="toot-o-matic-variables.xsl"/> <xsl:include href="xslt-utilities.xsl"/> <xsl:include href="dw-style.xsl"/> <xsl:include href="build-main-index.xsl"/> <xsl:include href="build-section-indexes.xsl"/> <xsl:include href="build-individual-panels.xsl"/> <xsl:include href="build-graphics.xsl"/> <xsl:include href="build-pdf-file.xsl"/> <xsl:include href="build-zip-file.xsl"/> Segmenting your stylesheets this way can make debugging simpler, as well. In our example here, all the rules for creating a PDF file are in the stylesheet build-pdf-file.xsl. If the PDF files are not built correctly, build-pdf-file.xsl is most likely the source of the problem. All visual elements of our generated HTML pages are created in the stylesheet dw-style.xsl. If we need to change the look of all the HTML pages, changing the templates in dw-style.xsl will do the trick.
CategoryTop-level element Required Attributes
Optional AttributesNone. ContentNone. <xsl:key> is an empty element. Appears in<xsl:key> is a top-level element and can only appear as a child of <xsl:stylesheet>. Defined inXSLT section 12.2, Keys. ExampleHere is a stylesheet that defines two <xsl:key> relations against an XML document: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="language-index" match="defn" use="@language"/> <xsl:key name="term-ids" match="term" use="@id"/> <xsl:param name="targetLanguage"/> <xsl:template match="/"> <xsl:apply-templates select="glossary"/> </xsl:template> <xsl:template match="glossary"> <html> <head> <title> <xsl:text>Glossary Listing: </xsl:text> <xsl:value-of select="key('language-index', $targetLanguage)[1]/preceding-sibling::term"/> <xsl:text> - </xsl:text> <xsl:value-of select="key('language-index', $targetLanguage)[last()]/preceding-sibling::term"/> </title> </head> <body> <h1> <xsl:text>Glossary Listing: </xsl:text> <xsl:value-of select="key('language-index', $targetLanguage)[1]/ancestor::glentry/term"/> <xsl:text> - </xsl:text> <xsl:value-of select="key('language-index', $targetLanguage)[last()]/ancestor::glentry/term"/> </h1> <xsl:for-each select="key('language-index', $targetLanguage)"> <xsl:apply-templates select="ancestor::glentry"/> </xsl:for-each> </body> </html> </xsl:template> ... </xsl:stylesheet> For a complete discussion of this stylesheet, illustrating how the <xsl:key> relations are used, see Section 5.2.3, "Stylesheets That Use the key() Function" in Chapter 5, "Creating Links and Cross-References".
CategoryInstruction Required AttributesNone. Optional Attributes
ContentAn XSLT template. Appears in<xsl:message> appears inside a template. Defined inXSLT section 13, Messages. ExampleHere's a stylesheet that uses the <xsl:message> element to trace the transformation of an XML document. We'll use our list of recently purchased albums again: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> We'll list all of the purchased albums in an HTML table, with the background color of each row alternating through various colors. Our stylesheet uses an <xsl:choose> element inside an <xsl:attribute> element to determine the value of the bgcolor attribute. If a given <listitem> is converted to an HTML <tr> with a background color of lavender, we'll issue a celebratory message: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="list/title"/> </title> </head> <body> <h1><xsl:value-of select="list/title"/></h1> <table border="1"> <xsl:for-each select="list/listitem"> <tr> <td> <xsl:attribute name="bgcolor"> <xsl:choose> <xsl:when test="position() mod 4 = 0"> <xsl:text>papayawhip</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 1"> <xsl:text>mintcream</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 2"> <xsl:text>lavender</xsl:text> <xsl:message terminate="no"> <xsl:text>Table row #</xsl:text> <xsl:value-of select="position()"/> <xsl:text> is lavender!</xsl:text> </xsl:message> </xsl:when> <xsl:otherwise> <xsl:text>whitesmoke</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:value-of select="."/> </td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> Note that the XSLT specification doesn't define how the message is issued. When we use this stylesheet with Xalan 2.0.1, we get these results: file:///D:/O'Reilly/XSLT/bookSamples/AppendixA/message.xsl; Line 32; Column 51; Table row #2 is lavender! file:///D:/O'Reilly/XSLT/bookSamples/AppendixA/message.xsl; Line 32; Column 51; Table row #6 is lavender! Xalan gives us feedback on the part of the stylesheet that generated each message. Saxon, on the other hand, keeps things short and sweet: Table row #2 is lavender! Table row #6 is lavender! For variety's sake, here's how XT processes the <xsl:message> element: file:/D:/O'Reilly/XSLT/bookSamples/AppendixA/test4.xml:5: Table row #2 is lavender! file:/D:/O'Reilly/XSLT/bookSamples/AppendixA/test4.xml:9: Table row #6 is lavender! XT gives information about the line in the XML source document that generated the message.
CategoryTop-level element Required Attributes
Optional AttributesNone. ContentNone. <xsl:namespace-alias> is an empty element. Appears in<xsl:stylesheet>. <xsl:namespace-alias> is a top-level element and can appear only as a child of <xsl:stylesheet>. Defined inXSLT section 7.1.1, Literal Result Elements. ExampleThis element is not used frequently, and the reasons for its existence are based on the somewhat obscure case of an XSLT stylesheet that needs to generate another XSLT stylesheet. Our test case here creates a stylesheet that generates the identity transform, a stylesheet that simply copies any input document to the result tree. Here's our original stylesheet that uses the namespace alias: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xslout="(the namespace URI doesn't matter here)"> <xsl:output method="xml" indent="yes"/> <xsl:namespace-alias stylesheet-prefix="xslout" result-prefix="xsl"/> <xsl:template match="/"> <xslout:stylesheet version="1.0"> <xslout:output method="xml"/> <xslout:template match="/"> <xslout:copy-of select="."/> </xslout:template> </xslout:stylesheet> </xsl:template> </xsl:stylesheet> When we run this stylesheet with any XML document at all, we get a new stylesheet: <?xml version="1.0" encoding="UTF-8"?> <xslout:stylesheet xmlns:xslout="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xslout:output method="xml"/> <xslout:template match="/"> <xslout:copy-of select="."/> </xslout:template> </xslout:stylesheet> You can take this generated stylesheet and use it to copy any XML document. In our original stylesheet, we use an <xsl:namespace-alias> because we have no other way of identifying to the XSLT processor with which XSLT elements should be processed and which ones should be treated as literals passed to the output. Using the namespace alias lets us generate the XSLT elements we need in our output. Notice in the result document that the correct namespace value was declared automatically on the <xslout:stylesheet> element.
CategoryInstruction Required AttributesNone. Optional Attributes
ContentNone. <xsl:number> is an empty element. Appears in<xsl:number> appears inside a template. Defined inXSLT section 7.7, Numbering. ExampleTo fully illustrate how <xsl:number> works, we'll need an XML document with many things to count. Here's the document we'll use: <?xml version="1.0"?> <book> <chapter> <title>Alfa Romeo</title> <sect1> <title>Bentley</title> </sect1> <sect1> <title>Chevrolet</title> <sect2> <title>Dodge</title> <sect3> <title>Eagle</title> </sect3> </sect2> </sect1> </chapter> <chapter> <title>Ford</title> <sect1> <title>GMC</title> <sect2> <title>Honda</title> <sect3> <title>Isuzu</title> </sect3> <sect3> <title>Javelin</title> </sect3> <sect3> <title>K-Car</title> </sect3> <sect3> <title>Lincoln</title> </sect3> </sect2> <sect2> <title>Mercedes</title> </sect2> <sect2> <title>Nash</title> <sect3> <title>Opel</title> </sect3> <sect3> <title>Pontiac</title> </sect3> </sect2> <sect2> <title>Quantum</title> <sect3> <title>Rambler</title> </sect3> <sect3> <title>Studebaker</title> </sect3> </sect2> </sect1> <sect1> <title>Toyota</title> <sect2> <title>Um, is there a car that starts with "U"?</title> </sect2> </sect1> <sect1> <title>Volkswagen</title> </sect1> </chapter> </book> We'll use <xsl:number> in several different ways to illustrate the various options we have in numbering things. We'll look at the stylesheet and the results, then we'll discuss them. Here's the stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:apply-templates select="book" mode="number-1"/> <xsl:apply-templates select="book" mode="number-2"/> <xsl:apply-templates select="book" mode="number-3"/> <xsl:apply-templates select="book" mode="number-4"/> <xsl:apply-templates select="book" mode="number-5"/> <xsl:apply-templates select="book" mode="number-6"/> <xsl:apply-templates select="book" mode="number-7"/> </xsl:template> <xsl:template match="book" mode="number-1"> <xsl:text>Test #1: level="multiple", count="chapter|sect1|sect2|sect3", format="1.1.1.1. "</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3"> <xsl:number level="multiple" count="chapter|sect1|sect2|sect3" format="1.1.1.1. "/> <xsl:value-of select="title"/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template match="book" mode="number-2"> <xsl:text>Test #2: level="any", count="chapter|sect1|sect2|sect3", format="1. "</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3"> <xsl:number level="any" count="chapter|sect1|sect2|sect3" format="1. "/> <xsl:value-of select="title"/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template match="book" mode="number-3"> <xsl:text>Test #3: level="single", count="chapter|sect1|sect2|sect3", format="1.1.1.1. "</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3"> <xsl:number level="single" count="chapter|sect1|sect2|sect3" format="1.1.1.1. "/> <xsl:value-of select="title"/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template match="book" mode="number-4"> <xsl:text>Test #4: level="multiple", select=".//sect2", count="chapter|sect1|sect2", format="I-A-i: "</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select=".//sect2"> <xsl:number level="multiple" count="chapter|sect1|sect2" format="I-A-i: "/> <xsl:value-of select="title"/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template match="book" mode="number-5"> <xsl:text>Test #5: level="any", count="[various elements]" from="[various elements]" format="1.1.1.1. "</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select=".//sect3"> <xsl:number level="any" from="book" count="chapter" format="1."/> <xsl:number level="any" from="chapter" count="sect1" format="1."/> <xsl:number level="any" from="sect1" count="sect2" format="1."/> <xsl:number level="any" from="sect2" count="sect3" format="1. "/> <xsl:value-of select="title"/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template match="book" mode="number-6"> <xsl:text>Test #6: level="any", count="chapter|sect1|sect2|sect3", grouping-separator=",", using a variable to start counting at 1000.</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3"> <xsl:variable name="value1"> <xsl:number level="any" count="chapter|sect1|sect2|sect3"/> </xsl:variable> <xsl:number value="$value1 + 999" grouping-separator="." grouping-size="3"/> <xsl:text>. </xsl:text> <xsl:value-of select="title"/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template match="book" mode="number-7"> <xsl:text>Test #7: level="multiple", count="chapter|sect1|sect2|sect3", format="1.1.1.1. ", selecting up to the first two <sect1> elements from chapter 2.</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:for-each select="chapter[2]/sect1[position() < 3]"> <xsl:for-each select="chapter|.//sect1|.//sect2|.//sect3"> <xsl:number level="multiple" count="chapter|sect1|sect2|sect3" format="1.1.1.1. "/> <xsl:value-of select="title"/> <xsl:value-of select="$newline"/> </xsl:for-each> </xsl:for-each> </xsl:template> </xsl:stylesheet> Here are our results: Test #1: level="multiple", count="chapter|sect1|sect2|sect3", format="1.1.1.1. " 1. Alfa Romeo 1.1. Bentley 1.2. Chevrolet 1.2.1. Dodge 1.2.1.1. Eagle 2. Ford 2.1. GMC 2.1.1. Honda 2.1.1.1. Isuzu 2.1.1.2. Javelin 2.1.1.3. K-Car 2.1.1.4. Lincoln 2.1.2. Mercedes 2.1.3. Nash 2.1.3.1. Opel 2.1.3.2. Pontiac 2.1.4. Quantum 2.1.4.1. Rambler 2.1.4.2. Studebaker 2.2. Toyota 2.2.1. Um, is there a car that starts with "U"? 2.3. Volkswagen Test #2: level="any", count="chapter|sect1|sect2|sect3", format="1. " 1. Alfa Romeo 2. Bentley 3. Chevrolet 4. Dodge 5. Eagle 6. Ford 7. GMC 8. Honda 9. Isuzu 10. Javelin 11. K-Car 12. Lincoln 13. Mercedes 14. Nash 15. Opel 16. Pontiac 17. Quantum 18. Rambler 19. Studebaker 20. Toyota 21. Um, is there a car that starts with "U"? 22. Volkswagen Test #3: level="single", count="chapter|sect1|sect2|sect3", format="1.1.1.1. " 1. Alfa Romeo 1. Bentley 2. Chevrolet 1. Dodge 1. Eagle 2. Ford 1. GMC 1. Honda 1. Isuzu 2. Javelin 3. K-Car 4. Lincoln 2. Mercedes 3. Nash 1. Opel 2. Pontiac 4. Quantum 1. Rambler 2. Studebaker 2. Toyota 1. Um, is there a car that starts with "U"? 3. Volkswagen Test #4: level="multiple", select=".//sect2", count="chapter|sect1|sect2", format="I-A-i: " I-B-i: Dodge II-A-i: Honda II-A-ii: Mercedes II-A-iii: Nash II-A-iv: Quantum II-B-i: Um, is there a car that starts with "U"? Test #5: level="any", count="[various elements]" from="[various elements]" format="1.1.1.1. " 1.2.1.1. Eagle 2.1.1.1. Isuzu 2.1.1.2. Javelin 2.1.1.3. K-Car 2.1.1.4. Lincoln 2.1.3.1. Opel 2.1.3.2. Pontiac 2.1.4.1. Rambler 2.1.4.2. Studebaker Test #6: level="any", count="chapter|sect1|sect2|sect3", grouping-separator=",", using a variable to start counting at 1000. 1,000. Alfa Romeo 1,001. Bentley 1,002. Chevrolet 1,003. Dodge 1,004. Eagle 1,005. Ford 1,006. GMC 1,007. Honda 1,008. Isuzu 1,009. Javelin 1,010. K-Car 1,011. Lincoln 1,012. Mercedes 1,013. Nash 1,014. Opel 1,015. Pontiac 1,016. Quantum 1,017. Rambler 1,018. Studebaker 1,019. Toyota 1,020. Um, is there a car that starts with "U"? 1,021. Volkswagen Test #7: level="multiple", count="chapter|sect1|sect2|sect3", format="1.1.1.1. ", selecting up to the first two <sect1> elements from chapter 2. 2.1. GMC 2.1.1. Honda 2.1.1.1. Isuzu 2.1.1.2. Javelin 2.1.1.3. K-Car 2.1.1.4. Lincoln 2.1.2. Mercedes 2.1.3. Nash 2.1.3.1. Opel 2.1.3.2. Pontiac 2.1.4. Quantum 2.1.4.1. Rambler 2.1.4.2. Studebaker 2.2. Toyota 2.2.1. Um, is there a car that starts with "U"? In Test 1, we used level="multiple" to count the <chapter>, <sect1>, <sect2>, and <sect3> elements. Numbering these at multiple levels gives us a dotted-decimal number for each element. We can look at the number next to Studebaker and know that it is the second <sect3> element inside the fourth <sect2> element inside the first <sect1> element inside the second <chapter> element. Test 2 uses level="any" to count all of the <chapter>, <sect1>, <sect2>, and <sect3> elements in order. Test 3 uses level="single" to count the elements at each level. This means that the fourth <sect3> element inside a given <sect2> element will be numbered with a 4 (or iv or D or whatever the appropriate value would be). Notice that the number used for each element is the same as the last number beside each element in Test 1. Test 4 does a couple of things differently: first, it uses the uppercase-alpha and lowercase-roman numbering styles. Second, it counts elements at multiple levels (for the <chapter>, <sect1>, and <sect2> elements), but we only process the <sect2> elements. Even though we only output the title text for the <sect2> elements, we can still generate the appropriate multilevel numbers. Test 5 generates numbers similarly to Test 4, except that it uses the from attribute. We generate numbers for <sect3> elements in four stages; first, we count the <chapter> ancestors, starting at the first <book> ancestor; then we count the <sect1> ancestors, starting at the first <chapter> ancestor, etc. Test 6 starts counting at 1000 instead of 1. To do this, we have to store the value generated by <xsl:number> in a variable, then output the value of the variable plus 1000. Notice that we can use an expression in the value attribute of the <xsl:number> element. We also used the grouping-separator attribute to use a comma to separate groups of three digits. Last but not least, Test 7 only numbers items from the first and second <sect1> elements (<sect1> elements whose position() is less than 3) in the second <chapter> element. Even though we're only processing these sections, we can still use <xsl:number> to generate the correct numbers for the elements.
CategorySubinstruction (<xsl:otherwise> always appears as part of an <xsl:choose> element). Required AttributesNone. Optional AttributesNone. ContentA template. Appears inThe <xsl:choose> element. Defined inXSLT section 9.2, Conditional Processing with xsl:choose. ExampleAs an example, we'll use an <xsl:choose> element that cycles through a set of values for the background color of a cell in an HTML table. We'll use this XML document as our input: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> Here is our stylesheet, which uses <xsl:choose> inside an <xsl:attribute> element to determine the correct value for the bgcolor attribute. We have an <xsl:otherwise> element that generates the value whitesmoke for every fourth <listitem> in our source document: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="list/title"/> </title> </head> <body> <h1><xsl:value-of select="list/title"/></h1> <table border="1"> <xsl:for-each select="list/listitem"> <tr> <td> <xsl:attribute name="bgcolor"> <xsl:choose> <xsl:when test="@bgcolor"> <xsl:value-of select="@bgcolor"/> </xsl:when> <xsl:when test="position() mod 4 = 0"> <xsl:text>papayawhip</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 1"> <xsl:text>mintcream</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 2"> <xsl:text>lavender</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>whitesmoke</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:value-of select="."/> </td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> Here is our generated HTML document. Notice that every fourth row has a background color of whitesmoke; that value was generated by the <xsl:otherwise> element: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Albums I've bought recently:</title> </head> <body> <h1>Albums I've bought recently:</h1> <table border="1"> <tr> <td bgcolor="mintcream">The Sacred Art of Dub</td> </tr> <tr> <td bgcolor="lavender">Only the Poor Man Feel It</td> </tr> <tr> <td bgcolor="whitesmoke">Excitable Boy</td> </tr> <tr> <td bgcolor="papayawhip">Aki Special</td> </tr> <tr> <td bgcolor="mintcream">Combat Rock</td> </tr> <tr> <td bgcolor="lavender">Talking Timbuktu</td> </tr> <tr> <td bgcolor="whitesmoke">The Birth of the Cool</td> </tr> </table> </body> </html> When rendered, our HTML document looks like Figure A-7. Figure A-7. Document cycling among different background colors
CategoryTop-level element Required AttributesNone. Optional Attributes
ContentNone. <xsl:output> is an empty element. Appears in<xsl:output> is a top-level element and can only appear as a child of <xsl:stylesheet>. Defined inXSLT section 16, Output. ExampleTo illustrate the three output methods defined in the XSLT specification, we'll create three stylesheets, each of which uses one of the three methods. We'll use the following XML document in all three examples: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> We'll now look at our three stylesheets and the results produced by each. First, let's look at the method="xml" stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" doctype-public="-//W3C/DTD XHTML 1.0//EN" doctype-system="file:///d:/xhtml.dtd" encoding="ISO-8859-1" indent="no"/> <xsl:template match="/"> <html> <head> <title><xsl:value-of select="/list/title"/></title> </head> <body> <h1><xsl:value-of select="/list/title"/></h1> <p> <xsl:for-each select="/list/listitem"> <xsl:number format="1. "/> <xsl:value-of select="."/> <br/> </xsl:for-each> </p> </body> </html> </xsl:template> </xsl:stylesheet> This stylesheet generates the following results: <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C/DTD XHTML 1.0//EN" "file:///d:/xhtml.dtd"> <html><head><title>A few of my favorite albums</title> </head><body><h1>A few of my favorite albums</h1> <p>1. A Love Supreme<br/>2. Beat Crazy<br/>3. Here Come the Warm Jets<br/>4. Kind of Blue<br/>5. London Calling<br/>6. Remain in Light<br/>7. The Joshua Tree<br/>8. The Indestructible Beat of Soweto<br/></p></body></html> (We actually added line breaks to this listing; the original output put everything from <html> through </html> on a single line.) The output document has the encoding we specified in our stylesheet, and the DOCTYPE declaration includes the PUBLIC and SYSTEM identifiers we requested as well. Even with the line breaks we added, it's still obvious that this document has not been formatted with any extra whitespace whatsoever. We also have empty <br/> elements in our output document; those elements will be handled differently when we specify method="html". Speaking of which, here is our method="html" stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C/DTD HTML 1.0 Transitional//EN"/> <xsl:template match="/"> <html> <head> <title><xsl:value-of select="/list/title"/></title> </head> <body> <h1><xsl:value-of select="/list/title"/></h1> <p> <xsl:for-each select="/list/listitem"> <xsl:number format="1. "/> <xsl:value-of select="."/> <br/> </xsl:for-each> </p> </body> </html> </xsl:template> </xsl:stylesheet> Here is the HTML document generated by this stylesheet: <!DOCTYPE HTML PUBLIC "-//W3C/DTD HTML 1.0 Transitional//EN"> <html> <head> <META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>A few of my favorite albums</title> </head> <body> <h1>A few of my favorite albums</h1> <p>1. A Love Supreme<br>2. Beat Crazy<br>3. Here Come the Warm Jets<br>4. Kind of Blue<br>5. London Calling<br>6. Remain in Light<br>7. The Joshua Tree<br>8. The Indestructible Beat of Soweto<br> </p> </body> </html> (As before, we added line breaks to make the listing legible.) Notice that the XSLT processor has automatically inserted a <META> element in the <head> of our HTML document. The <br> elements that were empty in our previous stylesheet are now old-fashioned <br> tags. Even though this style of XSLT output results in a document that is not valid XML (or XHTML), the document will work with existing HTML browsers. Our final stylesheet will use method="text": <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <html> <head> <title><xsl:value-of select="/list/title"/></title> </head> <body> <h1><xsl:value-of select="/list/title"/></h1> <p> <xsl:for-each select="/list/listitem"> <xsl:number format="1. "/> <xsl:value-of select="."/> <br/> </xsl:for-each> </p> </body> </html> </xsl:template> </xsl:stylesheet> Here are the results, such as they are, from this stylesheet: A few of my favorite albumsA few of my favorite albums1. A Love Supreme2. Beat Crazy3. Here Come the Warm Jets4. Kind of Blue5. London Calling6. Remain in Light7. The Joshua Tree8. The Indestructible Beat of Soweto (As before, we inserted line breaks so the document would fit on the page.) These results are basically worthless. Why weren't our carefully coded HTML elements output to the text document? The reason is that the text output method only outputs text nodes to the result tree. Even though we requested that various HTML elements be generated along the way, they're ignored because we specified method="text".
CategoryInstruction Required Attributes
Optional Attributes
ContentIf the select attribute is used, <xsl:param> should be empty. Otherwise, it contains an XSLT template. Appears in<xsl:stylesheet> and <xsl:template>. If an <xsl:param> appears as a child of <xsl:stylesheet>, then it is a global parameter visible throughout the stylesheet. XSLT doesn't define the way global parameters are passed to the XSLT processor, so check the documentation for your processor to see how this is done. (See Section 4.4.3, "Global Parameters" in Chapter 4, "Branching and Control Elements" for an overview of how to pass parameters to the most popular XSLT processors.) Defined inXSLT section 11, Variables and Parameters. ExampleHere is a stylesheet that defines several <xsl:param> elements, both global and local. Notice that one of the parameters is a node-set; parameters can be of any XPath or XSLT datatype: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:param name="favoriteNumber" select="23"/> <xsl:param name="favoriteColor"/> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:value-of select="list/title"/> <xsl:value-of select="$newline"/> <xsl:variable name="listitems" select="list/listitem"/> <xsl:call-template name="processListitems"> <xsl:with-param name="items" select="$listitems"/> <xsl:with-param name="color" select="'yellow'"/> <xsl:with-param name="number" select="$favoriteNumber"/> </xsl:call-template> </xsl:template> <xsl:template name="processListitems"> <xsl:param name="items"/> <xsl:param name="color" select="'blue'"/> <xsl:for-each select="$items"> <xsl:value-of select="position()"/> <xsl:text>. </xsl:text> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> <xsl:text>Your favorite color is </xsl:text> <xsl:value-of select="$favoriteColor"/> <xsl:text>.</xsl:text> <xsl:value-of select="$newline"/> <xsl:text>The color passed to this template is </xsl:text> <xsl:value-of select="$color"/> <xsl:text>.</xsl:text> <xsl:value-of select="$newline"/> </xsl:template> </xsl:stylesheet> We'll use this stylesheet to transform the following document: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> Here are the results: A few of my favorite albums 1. A Love Supreme 2. Beat Crazy 3. Here Come the Warm Jets 4. Kind of Blue 5. London Calling 6. Remain in Light 7. The Joshua Tree 8. The Indestructible Beat of Soweto Your favorite color is purple. The color passed to this template is yellow. To generate these results, we passed the value purple to the XSLT processor. With Xalan, the value is passed like this: java org.apache.xalan.xslt.Process -in test4.xml -xsl param.xsl -param favoriteColor purple (The command should be entered on a single line.) See Section 4.4.3, "Global Parameters" in Chapter 4, "Branching and Control Elements" for a more complete discussion of global parameters and how they can be set for various XSLT processors.
CategoryTop-level element Required Attributes
Optional AttributesNone. ContentNone. <xsl:preserve-space> is an empty element. Appears in<preserve-space> is a top-level element and can only appear as a child of <xsl:stylesheet> . Defined inXSLT section 3.4, Whitespace Stripping. ExampleWe'll illustrate how <preserve-space> works with the following stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:preserve-space elements="listing"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:value-of select="/code-sample/title"/> <xsl:value-of select="$newline"/> <xsl:for-each select="/code-sample/listing"> <xsl:value-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet> We'll use this stylesheet to process the following document: <?xml version="1.0"?> <code-sample> <title>Conditional variable initialization</title> <listing> <type>int</type> <variable>y</variable> = <constant>23</constant>; <type>int</type> <variable>x</variable>; <keyword>if</keyword> (<variable>y</variable> > <constant>10</constant>) <variable>x</variable> = <constant>5</constant>; <keyword>else</keyword> <keyword>if</keyword> (<variable>y</variable> > <constant>5</constant>) <variable>x</variable> = <constant>3</constant>; <keyword>else</keyword> <variable>x</variable> = <constant>1</constant>; </listing> </code-sample> When we process this document with our stylesheet, we get these results: Conditional variable initialization int y = 23; int x; if (y > 10) x = 5; else if (y > 5) x = 3; else x = 1; Compare this example to the one for the <strip-space> element.
CategoryInstruction Required Attributes
Optional AttributesNone. ContentAn XSLT template. The contents of the template become the data of the processing instruction. Appears in<xsl:processing-instruction> appears inside a template. Defined inXSLT section 7.3, Creating Processing Instructions. ExampleWe'll demonstrate a stylesheet that adds a processing instruction to an XML document. The processing instruction will associate the stylesheet template.xsl with this XML document. Here is our stylesheet: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <xsl:processing-instruction name="xml-stylesheet">href="docbook/html/docbook.xsl" type="text/xsl"</xsl:processing-instruction> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet> This stylesheet simply uses the <xsl:copy-of> element to copy the input document to the result tree, adding a processing instruction along the way. We'll use our stylesheet with this XML document: <?xml version="1.0"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> When we run this transformation, here are the results: <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet href="docbook/html/docbook.xsl" type="text/xsl"?> <list> <title>A few of my favorite albums</title> <listitem>A Love Supreme</listitem> <listitem>Beat Crazy</listitem> <listitem>Here Come the Warm Jets</listitem> <listitem>Kind of Blue</listitem> <listitem>London Calling</listitem> <listitem>Remain in Light</listitem> <listitem>The Joshua Tree</listitem> <listitem>The Indestructible Beat of Soweto</listitem> </list> Note that the contents of a processing instruction are text. Even though the processing instruction we just generated looks like it contains two attributes, you can't create the processing instruction like this: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <xsl:processing-instruction name="xml-stylesheet"> <!-- This doesn't work! You can't put <xsl:attribute> elements inside a <xsl:processing-instruction> element. --> <xsl:attribute name="href"> <xsl:text>docbook/html/docbook.xsl</xsl:text> </xsl:attribute> <xsl:attribute name="type"> <xsl:text>text/xsl</xsl:text> </xsl:attribute> </xsl:processing-instruction> <xsl:copy-of select="."/> </xsl:template> </xsl:stylesheet> If you try this, you'll get an exception from the XSLT processor.
CategorySubinstruction (<xsl:sort> always appears as a child of the <xsl:apply-templates> or <xsl:for-each> elements) Required AttributesNone. Optional Attributes
ContentNone. Appears in<xsl:apply-templates> and <xsl:for-each>. Defined inXSLT section 10, Sorting. ExampleWe'll illustrate <xsl:sort> with this stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:call-template name="ascending-alpha-sort"> <xsl:with-param name="items" select="/sample/textlist/listitem"/> </xsl:call-template> <xsl:call-template name="ascending-alpha-sort"> <xsl:with-param name="items" select="/sample/numericlist/listitem"/> </xsl:call-template> <xsl:call-template name="ascending-numeric-sort"> <xsl:with-param name="items" select="/sample/numericlist/listitem"/> </xsl:call-template> <xsl:call-template name="descending-alpha-sort"> <xsl:with-param name="items" select="/sample/textlist/listitem"/> </xsl:call-template> </xsl:template> <xsl:template name="ascending-alpha-sort"> <xsl:param name="items"/> <xsl:text>Ascending text sort:</xsl:text> <xsl:value-of select="$newline"/> <xsl:for-each select="$items"> <xsl:sort select="."/> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template name="descending-alpha-sort"> <xsl:param name="items"/> <xsl:text>Descending text sort:</xsl:text> <xsl:value-of select="$newline"/> <xsl:for-each select="$items"> <xsl:sort select="." order="descending"/> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> <xsl:template name="ascending-numeric-sort"> <xsl:param name="items"/> <xsl:text>Ascending numeric sort:</xsl:text> <xsl:value-of select="$newline"/> <xsl:for-each select="$items"> <xsl:sort select="." data-type="number"/> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> </xsl:template> </xsl:stylesheet> Our stylesheet defines three named templates, each of which sorts <listitem>s in a different order or with a different data-type. We'll use this stylesheet against this document: <?xml version="1.0"?> <sample> <numericlist> <listitem>1</listitem> <listitem>3</listitem> <listitem>23</listitem> <listitem>120</listitem> <listitem>2</listitem> </numericlist> <textlist> <listitem>3</listitem> <listitem>apple</listitem> <listitem>orange</listitem> <listitem>dragonfruit</listitem> <listitem>carambola</listitem> </textlist> </sample> Here are the results: Ascending text sort: 3 apple carambola dragonfruit orange Ascending text sort: 1 120 2 23 3 Ascending numeric sort: 1 2 3 23 120 Descending text sort: orange dragonfruit carambola apple 3 Notice that the data-type="numeric" attribute causes data to be sorted in numeric order.
CategoryTop-level element Required Attributes
Optional AttributesNone. ContentNone. <xsl:strip-space> is an empty element. Appears in<xsl:strip-space> is a top-level element, and can only appear as a child of <xsl:stylesheet> . Defined inXSLT section 3.4, Whitespace Stripping. ExampleWe'll illustrate the <xsl:strip-space> element with the following stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:strip-space elements="listing"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:value-of select="/code-sample/title"/> <xsl:value-of select="$newline"/> <xsl:for-each select="/code-sample/listing"> <xsl:value-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet> We'll use this stylesheet to process the following document: <?xml version="1.0"?> <code-sample> <title>Conditional variable initialization</title> <listing> <type>int</type> <variable>y</variable> = <constant>23</constant>; <type>int</type> <variable>x</variable>; <keyword>if</keyword> (<variable>y</variable> > <constant>10</constant>) <variable>x</variable> = <constant>5</constant>; <keyword>else</keyword> <keyword>if</keyword> (<variable>y</variable> > <constant>5</constant>) <variable>x</variable> = <constant>3</constant>; <keyword>else</keyword> <variable>x</variable> = <constant>1</constant>; </listing> </code-sample> Here are the results: Conditional variable initialization inty = 23; intx; if (y > 10) x = 5; elseif (y > 5) x = 3; elsex = 1; Notice that all the extra whitespace from the <listing> element has been removed. This includes the space between the various elements contained inside <listing>, such as <keyword>, <constant>, and <variable>. Compare this example to the one for the <preserve-space> element.
CategoryContains the entire stylesheet Required Attributes
Optional Attributes
ContentThis element contains the entire stylesheet. The following items can be children of <xsl:stylesheet>:
Appears inNone. <xsl:stylesheet> is the root element of the stylesheet. Defined inXSLT section 2.2, Stylesheet Element. ExampleFor the sake of completeness, we'll include an example here. We'll use the Hello World document from the XML 1.0 specification for our example: <?xml version="1.0"?> <greeting> Hello, World! </greeting> We'll transform our document with this stylesheet: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <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> When we transform our document with this stylesheet, here are the results: <html> <body> <h1> Hello, World! </h1> </body> </html>
CategoryTop-level element Required AttributesNone. Optional Attributes
ContentAn XSLT template. Appears in<xsl:stylesheet>. <xsl:template> is a top-level element and can only appear as a child of <xsl:stylesheet>. Defined inXSLT section 5.3, Defining Template Rules. ExampleWe'll use a template that copies all nodes from the input document to the output document, with one important difference: all attributes in the original document are converted to elements in the output document. The name of each generated element is the name of the original attribute, and the text of each element is the attribute's value. Here's our stylesheet: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:element name="{name()}"> <xsl:for-each select="@*"> <xsl:element name="{name()}"> <xsl:value-of select="."/> </xsl:element> </xsl:for-each> <xsl:apply-templates select="*|text()"/> </xsl:element> </xsl:template> </xsl:stylesheet> Our stylesheet contains a single <xsl:template> that transforms every node in the original document. We'll use our stylesheet to transform the following XML document: <?xml version="1.0"?> <report> <title>Miles Flown in 2001</title> <month sequence="01"> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month sequence="02"> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month sequence="03"> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month sequence="04"> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report> Here are the results of our transformation: <?xml version="1.0" encoding="UTF-8"?> <report> <title>Miles Flown in 2001</title> <month><sequence>01</sequence> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month><sequence>02</sequence> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month><sequence>03</sequence> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month><sequence>04</sequence> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report>
CategoryInstruction Required AttributesNone. Optional Attributes
Content#PCDATA, literal text, and entity references. Appears in<xsl:text> appears inside a template. Defined inXSLT section 7.2, Creating Text. ExampleThis sample stylesheet generates text with <xsl:text>. We intermingle <xsl:text> elements and <xsl:value-of> elements to create a coherent sentence. In this case, we simply generate a text document, but this technique works equally well to create the text of an HTML or XML element. Here is the stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:text>Your document contains </xsl:text> <xsl:value-of select="count(//*)"/> <xsl:text> elements and </xsl:text> <xsl:value-of select="count(//@*)"/> <xsl:text> attributes. </xsl:text> <xsl:value-of select="$newline"/> <xsl:text disable-output-escaping="yes"><Have a great day!></xsl:text> </xsl:template> </xsl:stylesheet> Also notice our use of <xsl:variable> to generate line breaks. The <xsl:text> element inside the <xsl:variable> element contains a line break, so writing the value of that variable to the result tree gives us the line break we want. Given this XML document: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> Our stylesheet produces these results: Your document contains 9 elements and 5 attributes. <Have a great day!> Since we use the text output method, the disable-output-escaping attribute has no effect. If you change the stylesheet to use <xsl:output method="html"/> or <xsl:output method="xml"/>, then disable-output-escaping is used. Here are the results for disable-output-escaping="yes": Your document contains 10 elements and 2 attributes. <Have a great day!> And here are the results for disable-output-escaping="no", the default: Your document contains 10 elements and 2 attributes. <Have a great day!>
CategoryInstruction Required Attributes
Optional Attributes
ContentNone. <xsl:value-of> is an empty element. Appears in<xsl:value-of> appears inside a template. Defined inXSLT section 7.6.1, Generating Text with xsl:value-of. ExampleWe'll use the <xsl:value-of> element to generate some text. Here is our stylesheet: <?xsl version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:template match="/"> <xsl:text>Your document contains</xsl:text> <xsl:value-of select="count(//*)"/> <xsl:text> elements and </xsl:text> <xsl:value-of select="count(//@*)"/> <xsl:text> attributes. </xsl:text> <xsl:value-of select="$newline"/> <xsl:text>Have a great day!</xsl:text> </xsl:template> </xsl:stylesheet> We'll use this XML document as input: <?xml version="1.0"?> <report> <title>Miles Flown in 2001</title> <month sequence="01"> <miles-flown>12379</miles-flown> <miles-earned>35215</miles-earned> </month> <month sequence="02"> <miles-flown>32857</miles-flown> <miles-earned>92731</miles-earned> </month> <month sequence="03"> <miles-flown>19920</miles-flown> <miles-earned>76725</miles-earned> </month> <month sequence="04"> <miles-flown>18903</miles-flown> <miles-earned>31781</miles-earned> </month> </report> Here are the results: Your document contains 14 elements and 4 attributes. Have a great day!
CategoryEither a top-level element or an instruction Required Attributes
Optional Attributes
ContentThe <xsl:variable> element can be empty, or it can contain an XSLT template. If it contains an XSLT template, the value of the select attribute (if any exists) is ignored. Appears in<xsl:stylesheet> as a top-level element or in a template. Defined inXSLT section 11, Variables and Parameters. ExampleHere is a stylesheet that defines a number of variables: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:variable name="favoriteNumber" select="23"/> <xsl:variable name="favoriteColor" select="'blue'"/> <xsl:variable name="complicatedVariable"> <xsl:choose> <xsl:when test="count(//listitem) > 10"> <xsl:text>really long list</xsl:text> </xsl:when> <xsl:when test="count(//listitem) > 5"> <xsl:text>moderately long list</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>fairly short list</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:template match="/"> <xsl:text>Hello! Your favorite number is </xsl:text> <xsl:value-of select="$favoriteNumber"/> <xsl:text>.</xsl:text> <xsl:value-of select="$newline"/> <xsl:text>Your favorite color is </xsl:text> <xsl:value-of select="$favoriteColor"/> <xsl:text>.</xsl:text> <xsl:value-of select="$newline"/> <xsl:value-of select="$newline"/> <xsl:text>Here is a </xsl:text> <xsl:value-of select="$complicatedVariable"/> <xsl:text>:</xsl:text> <xsl:value-of select="$newline"/> <xsl:variable name="listitems" select="list/listitem"/> <xsl:call-template name="processListitems"> <xsl:with-param name="items" select="$listitems"/> </xsl:call-template> </xsl:template> <xsl:template name="processListitems"> <xsl:param name="items"/> <xsl:variable name="favoriteColor"> <xsl:text>chartreuse</xsl:text> </xsl:variable> <xsl:text> (Your favorite color is now </xsl:text> <xsl:value-of select="$favoriteColor"/> <xsl:text>.)</xsl:text> <xsl:value-of select="$newline"/> <xsl:for-each select="$items"> <xsl:value-of select="position()"/> <xsl:text>. </xsl:text> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:for-each> </xsl:template> </xsl:stylesheet> We'll use our stylesheet to transform the following document: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> Here are the results of our transformation: Hello! Your favorite number is 23. Your favorite color is blue. Here is a moderately long list: (Your favorite color is now chartreuse.) 1. The Sacred Art of Dub 2. Only the Poor Man Feel It 3. Excitable Boy 4. Aki Special 5. Combat Rock 6. Talking Timbuktu 7. The Birth of the Cool Several things are worth mentioning in our stylesheet. First, notice that when we defined values for the first two variables (favoriteNumber and favoriteColor), we had to quote the string "blue", but didn't have to quote 23. If we don't quote blue, the XSLT processor assumes we mean all the <blue> elements in the current context. We don't have to quote 23 because XML element names can't start with a number. It's a good idea to always quote literals, even those that can't be element names; chances are good that you'll forget this process at some point. Also notice that we have two variables named favoriteColor. One is a global variable because its parent is the <xsl:stylesheet> element; the other is a local variable because it is defined in a <xsl:template>. When we access favoriteColor in the match="/" template, it has one value; when we access it inside the name="processListitems" template, it has another. Having two variables at the same level with the same name is an error. It's also an error to define an <xsl:variable> and an <xsl:param> with the same name at the same level. Using an <xsl:choose> element to initialize an <xsl:variable> is a common technique. This technique is the equivalent of this procedural programming construct: String complicatedVariable; if (count(listitems) > 10) complicatedVariable = "really long list"; else if (count(listitems)) > 5) complicatedVariable = "moderately long list"; else complicatedVariable = "fairly short list"; The last point we'll make is that a variable can be any of the XPath or XSLT variable types, including a node-set. When we call the processListitems template, the parameter we pass to it is a variable containing the node-set of all the <listitem> elements in our document. Inside the processListitems template, our variable (which is now technically a parameter) can be used inside an <xsl:for-each> element.
CategorySubinstruction (<xsl:when> always appears as a child of an <xsl:choose> element) Required Attributes
Optional AttributesNone. ContentAn XSLT template. Appears inThe <xsl:choose> element only. Defined inXSLT section 9.2, Conditional Processing with xsl:choose. ExampleThis example uses an <xsl:choose> element and three <xsl:when> elements to cycle through a set of values. Now we will generate rows of an HTML table for each <listitem>: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> In our stylesheet, we'll generate table rows with the background colors of mintcream, lavender, whitesmoke, and papayawhip. For each <listitem> in our source document, one of the <xsl:when> elements (or the <xsl:otherwise> element) generates the appropriate color. <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html"/> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="list/title"/> </title> </head> <body> <h1><xsl:value-of select="list/title"/></h1> <table border="1"> <xsl:for-each select="list/listitem"> <tr> <td> <xsl:attribute name="bgcolor"> <xsl:choose> <xsl:when test="@bgcolor"> <xsl:value-of select="@bgcolor"/> </xsl:when> <xsl:when test="position() mod 4 = 0"> <xsl:text>papayawhip</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 1"> <xsl:text>mintcream</xsl:text> </xsl:when> <xsl:when test="position() mod 4 = 2"> <xsl:text>lavender</xsl:text> </xsl:when> <xsl:otherwise> <xsl:text>whitesmoke</xsl:text> </xsl:otherwise> </xsl:choose> </xsl:attribute> <xsl:value-of select="."/> </td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> When we process our XML source document with this stylesheet, here are the results: <html> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Albums I've bought recently:</title> </head> <body> <h1>Albums I've bought recently:</h1> <table border="1"> <tr> <td bgcolor="mintcream">The Sacred Art of Dub</td> </tr> <tr> <td bgcolor="lavender">Only the Poor Man Feel It</td> </tr> <tr> <td bgcolor="whitesmoke">Excitable Boy</td> </tr> <tr> <td bgcolor="papayawhip">Aki Special</td> </tr> <tr> <td bgcolor="mintcream">Combat Rock</td> </tr> <tr> <td bgcolor="lavender">Talking Timbuktu</td> </tr> <tr> <td bgcolor="whitesmoke">The Birth of the Cool</td> </tr> </table> </body> </html> All <td> elements with a background color of papayawhip, mintcream, or lavender were generated by one of the <xsl:when> elements.
CategorySubinstruction (<xsl:with-param> always appears inside an <xsl:apply-templates> or <xsl:call-template> element) Description<xsl:with-param> defines a parameter to be passed to a template. When the template is invoked, values can be passed in for the parameter. The value of the parameter can be defined in one of three ways:
If no value is passed to the template (<xsl:with-param name="x"/>), then the default value of the parameter, if any, is used instead. The default value of the parameter is defined on the <xsl:param> element inside the <xsl:template> itself; see the description of the <xsl:param> element for more details. Required Attributes
Optional Attributes
ContentThe <xsl:with-param> element can be empty, or it can contain an XSLT template. If it contains an XSLT template, the value of the select attribute (if any exists) is ignored. Appears in<xsl:apply-templates> and <xsl:call-template>. Defined inXSLT section 11.6, Passing Parameters to Templates. ExampleHere is a stylesheet with a number of parameters. Notice that some parameters are global and defined outside the stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:variable name="newline"> <xsl:text> </xsl:text> </xsl:variable> <xsl:param name="favoriteNumber" select="23"/> <xsl:param name="favoriteColor"/> <xsl:template match="/"> <xsl:value-of select="$newline"/> <xsl:value-of select="list/title"/> <xsl:value-of select="$newline"/> <xsl:variable name="listitems" select="list/listitem"/> <xsl:call-template name="processListitems"> <xsl:with-param name="items" select="$listitems"/> <xsl:with-param name="color" select="'yellow'"/> <xsl:with-param name="number" select="$favoriteNumber"/> </xsl:call-template> </xsl:template> <xsl:template name="processListitems"> <xsl:param name="items"/> <xsl:param name="color" select="'blue'"/> <xsl:for-each select="$items"> <xsl:value-of select="position()"/> <xsl:text>. </xsl:text> <xsl:value-of select="."/> <xsl:value-of select="$newline"/> </xsl:for-each> <xsl:value-of select="$newline"/> <xsl:text>Your favorite color is </xsl:text> <xsl:value-of select="$favoriteColor"/> <xsl:text>.</xsl:text> <xsl:value-of select="$newline"/> <xsl:text>The color passed to this template is </xsl:text> <xsl:value-of select="$color"/> <xsl:text>.</xsl:text> <xsl:value-of select="$newline"/> </xsl:template> </xsl:stylesheet> We'll use this stylesheet to transform this document: <?xml version="1.0"?> <list xml:lang="en"> <title>Albums I've bought recently:</title> <listitem>The Sacred Art of Dub</listitem> <listitem>Only the Poor Man Feel It</listitem> <listitem>Excitable Boy</listitem> <listitem xml:lang="sw">Aki Special</listitem> <listitem xml:lang="en-gb">Combat Rock</listitem> <listitem xml:lang="zu">Talking Timbuktu</listitem> <listitem xml:lang="jz">The Birth of the Cool</listitem> </list> Our stylesheet contains two global parameters, favoriteNumber and favoriteColor, and defines a default value for favoriteNumber. The stylesheet also passes a parameter from the match="/" template to the name="processListitems" template; that parameter contains a node-set. Here are the results of the transformation: Albums I've bought recently: 1. The Sacred Art of Dub 2. Only the Poor Man Feel It 3. Excitable Boy 4. Aki Special 5. Combat Rock 6. Talking Timbuktu 7. The Birth of the Cool Your favorite color is orange. The color passed to this template is yellow. To generate these results with Xalan, we use this command: java org.apache.xalan.xslt.Process -in test4.xml -xsl with-param.xsl -param favoriteColor orange The command should appear on a single line. See Section 4.4.3, "Global Parameters" in Chapter 4, "Branching and Control Elements" for a complete discussion of global parameters and how you define them for various XSLT processors. Copyright © 2002 O'Reilly & Associates. All rights reserved. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|