330 likes | 491 Views
Intermediate XSLT Bob DuCharme www.snee.com/bob bob@snee.com these slides: www.snee.com/xml 1.0. Outline. Variables and parameters Named templates and parameters xsl:for-each and “looping” XSLT extensions and EXSLT Using keys for faster lookups XSLT and browsers. Variables.
E N D
Intermediate XSLT Bob DuCharme www.snee.com/bob bob@snee.com these slides: www.snee.com/xml 1.0
Outline Variables and parameters Named templates and parameters xsl:for-each and “looping” XSLT extensions and EXSLT Using keys for faster lookups XSLT and browsers
Variables <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes"/> <xsl:variable name="winnerName">John</xsl:variable> <xsl:template match="test"> <xsl:text>Congratulations, </xsl:text> <xsl:value-of select="$winnerName"/> <xsl:text>, you are a winner!</xsl:text> <xsl:apply-templates/> </xsl:template> </xsl:stylesheet> Input document: <test/> Output: Congratulations, John, you are a winner!
Passing Parameters to Stylesheets <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes"/> <xsl:param name="winnerName">John</xsl:param> <xsl:template match="test"> <xsl:text>Congratulations, </xsl:text> <xsl:value-of select="$winnerName"/> <xsl:text>, you are a winner!</xsl:text> <xsl:apply-templates/> </xsl:template> </xsl:stylesheet> Same input document, same result, but when we override the default parameter value: C:\>saxon temp.xml test.xsl winnerName=Jane Congratulations, Jane, you are a winner!
Named Templates <xsl:template name="boldIt"> <b><xsl:apply-templates/></b> </xsl:template> <xsl:template match="winery"> <p><xsl:call-template name="boldIt"/></p> </xsl:template> <xsl:template match="product"> <p><xsl:call-template name="boldIt"/></p> </xsl:template> <xsl:template match="year | price"> <p><xsl:apply-templates/></p> </xsl:template>
Passing Parameters to Named Templates <xsl:template name="titles"> <xsl:param name="headerElement">h4</xsl:param> <xsl:element name="{$headerElement}"> <xsl:apply-templates/> </xsl:element> </xsl:template> <xsl:template match="chapter/title"> <xsl:call-template name="titles"> <xsl:with-param name="headerElement">h1</xsl:with-param> </xsl:call-template> </xsl:template> <xsl:template match="section/title"> <xsl:call-template name="titles"> <xsl:with-param name="headerElement" select="'h2'"/> </xsl:call-template> </xsl:template>
Iterating across a set of nodes <a> <b>3</b> <c>10</c> <b>4</b> <c>20</c> <b>5</b> </a> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="a"> <xsl:for-each select="b"> <xsl:value-of select=". + 5"/> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet> output: <?xml version="1.0" encoding="UTF-8"?>8 9 10
Repetition <xsl:template name="hyphens"> <xsl:param name="howMany">1</xsl:param> <xsl:if test="$howMany > 0"> <!-- Add 1 hyphen to result tree. --> <xsl:text>-</xsl:text> <!-- Print remaining ($howMany - 1) hyphens. --> <xsl:call-template name="hyphens"> <xsl:with-param name="howMany" select="$howMany - 1"/> </xsl:call-template> </xsl:if> </xsl:template>
Testing the recursive template rule <xsl:template match="sample"> Print 1 hyphen: <xsl:call-template name="hyphens"/> Print 20 hyphens: <xsl:call-template name="hyphens"> <xsl:with-param name="howMany" select="20"/> </xsl:call-template> Print 0 hyphens: <xsl:call-template name="hyphens"> <xsl:with-param name="howMany" select="0"/> </xsl:call-template> </xsl:template>
Recursive template rule: result Print 1 hyphen: - Print 20 hyphens: -------------------- Print 0 hyphens:
XSLT Extension functions <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/"> <xsl:template match="*"> <xsl:value-of select="saxon:path()"/> <xsl:text> </xsl:text> <xsl:apply-templates/> </xsl:template> </xsl:stylesheet>
Testing the extension function Source document: <a> <b/> <b><c color="red">test</c></b> <b/> </a> Result: /a /a/b[1] /a/b[2] /a/b[2]/c[1] test /a/b[3]
Extension elements (and attributes) <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" extension-element-prefixes="saxon"> <xsl:variable name="i" select="0" saxon:assignable="yes"/> <xsl:template match="/"> <saxon:while test="$i < 10"> The value of i is <xsl:value-of select="$i"/> <saxon:assign name="i" select="$i+1"/> </saxon:while> </xsl:template> </xsl:stylesheet>
Extension element test output The value of i is 0 The value of i is 1 The value of i is 2 The value of i is 3 The value of i is 4 The value of i is 5 The value of i is 6 The value of i is 7 The value of i is 8 The value of i is 9
Checking for extension support (option 1) <saxon:while test="$i < 10"> The value of i is <xsl:value-of select="$i"/> <xsl:fallback> <xsl:message>Your XSLT processor doesn't support saxon:while.</xsl:message> </xsl:fallback> <saxon:assign name="i" select="$i+1"/> </saxon:while>
Checking for extension support (option 2) <xsl:choose> <xsl:when test="element-available('saxon:while')"> <saxon:while test="$i < 10"> The value of i is <xsl:value-of select="$i"/> <saxon:assign name="i" select="$i+1"/> </saxon:while> </xsl:when> <xsl:otherwise> <xsl:message>Your XSLT processor doesn't support saxon:while.</xsl:message> </xsl:otherwise> </xsl:choose> checking for extension function support: function-available()
EXSLT Saxon documentation on its extensions: “ Before using a Saxon extension, check whether there is an equivalent EXSLT extension available. EXSLT extensions are more likely to be portable across XSLT processors.” http://www.exslt.org
Some EXSLT extensions (pt 1) <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" xmlns:math="http://exslt.org/math" xmlns:date="http://exslt.org/dates-and-times"> <xsl:template match="/"> exsl:object-type(3): <xsl:value-of select="exsl:object-type(3)"/> exsl:object-type('potrzebie'): <xsl:value-of select="exsl:object-type('potrzebie')"/> exsl:object-type(2 > 1): <xsl:value-of select="exsl:object-type(2 > 1)"/>
Some EXSLT extensions (pt 2) math:constant('PI',4): <xsl:value-of select="math:constant('PI',4)"/> math:constant('PI',12): <xsl:value-of select="math:constant('PI',12)"/> math:sqrt(256): <xsl:value-of select="math:sqrt(256)"/> date:date-time: <xsl:value-of select="date:date-time()"/> date:day-name: <xsl:value-of select="date:day-name()"/> </xsl:template> </xsl:stylesheet>
EXSLT demo result exsl:object-type(3): number exsl:object-type('potrzebie'): string exsl:object-type(2 > 1): boolean math:constant('PI',4): 3.1415 math:constant('PI',12): 3.141592653589 math:sqrt(256): 16 date:date-time: 2005-06-25T11:24:12-04:00 date:day-name: Saturday same result with Saxon and Xalan Java!
Declaring and using lookup keys we have: <shirts> <colors> <color cid="c1">yellow</color> <color cid="c4">blue</color> <!-- similar color elements --> <color cid="c7">orange</color> <color cid="c7">green</color> </colors> <shirt colorCode="c4">oxford button-down</shirt> <shirt colorCode="c1">poly blend, straight collar</shirt> <shirt colorCode="c6">monogrammed, tab collar</shirt> </shirts> we want: blue oxford button-down yellow poly blend, straight collar white monogrammed, tab collar
Without keys <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="shirt"> <xsl:variable name="shirtColorCode" select="@colorCode"/> <xsl:value-of select="/shirts/colors/color[@cid = $shirtColorCode]"/> <xsl:text> </xsl:text><xsl:apply-templates/><xsl:text> </xsl:text> </xsl:template> <xsl:template match="color"/> </xsl:stylesheet>
With keys <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:key name="colorNumKey" match="color" use="@cid"/> <xsl:template match="colors"/> <xsl:template match="shirt"> <xsl:value-of select="key('colorNumKey',@colorCode)"/> <xsl:text> </xsl:text><xsl:apply-templates/> </xsl:template> </xsl:stylesheet>
More lookups (part 1) <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:key name="colorNumKey" match="color" use="@cid"/> <xsl:key name="colorKey" match="color" use="."/> <xsl:variable name="testVar">c4</xsl:variable> <xsl:variable name="keyName">colorKey</xsl:variable> <xsl:template match="colors"> Looking up the color name with the color ID: c3's color: <xsl:value-of select="key('colorNumKey','c3')"/> c4's color: <xsl:value-of select="key('colorNumKey',$testVar)"/> c8's color: <xsl:value-of select="key('colorNumKey','c8')"/> c7's colors: <xsl:for-each select="key('colorNumKey','c7')"> <xsl:value-of select="."/><xsl:text> </xsl:text> </xsl:for-each>
More lookups (part 2) Looking up the color ID with the color name: blue's cid: <xsl:value-of select="key('colorKey','blue')/@cid"/> black's cid: <xsl:value-of select="key($keyName,'black')/@cid"/> gray's cid: <xsl:value-of select="key('colorKey','gray')/@cid"/> </xsl:template> <!-- Don't bother outputting shirt contents for this example. --> <xsl:template match="shirt"/> </xsl:stylesheet>
More lookups: result Looking up the color name with the color ID: c3's color: red c4's color: blue c8's color: c7's colors: orange green Looking up the color ID with the color name: blue's cid: c4 black's cid: c2 gray's cid:
Muenchian Grouping <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:key name="files-by-project" match="file" use="@project"/> <xsl:template match="files"> <html><body> <xsl:for-each select= "file[count(. | key('files-by-project', @project)[1]) = 1]"> <xsl:sort select="@project"/> <h1><xsl:value-of select="@project" /></h1> <xsl:for-each select="key('files-by-project', @project)"> <xsl:sort select="@name"/> <p><xsl:value-of select="@name"/> <xsl:text>,</xsl:text> <xsl:value-of select="@size"/> bytes</p> </xsl:for-each> </xsl:for-each> </body></html> </xsl:template> </xsl:stylesheet>
Muenchian Grouping: result <html> <body> <h1>jupiter</h1> <p>gadabout.pas,685 bytes</p> <p>kwatz.xom,43 bytes</p> <p>potrzebie.dbf,1102 bytes</p> <h1>mars</h1> <p>schtroumpf.txt,389 bytes</p> <p>swablr.eps,4313 bytes</p> <p>ummagumma.zip,2441 bytes</p> <h1>neptune</h1> <p>batboy.wks,424 bytes</p> <p>mondegreen.doc,1993 bytes</p> <p>paisley.doc,988 bytes</p> </body> </html>
Web Browsers and XSLT W3C Recommendation "Associating Style Sheets with XML documents" (http://www.w3.org/TR/xml-stylesheet) shows how: <?xml-stylesheet href="squareAsHTML.xsl" type="text/xsl" ?> <numbers> <number>2</number> <number>11</number> <number>100</number> <number>-5</number> </numbers>
Web Browsers and XSLT (part 1) <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- squareAsHTML.xsl: create an HTML document with a statement about the square of each "number" element read from the source tree. --> <xsl:template match="/"> <!-- Set up web page --> <html> <head> <title>Squares</title> <style> <!-- Put a little CSS in --> body { font-family: arial,helvetica; } h1 { font-size: 14pt } p { font-size: 10pt} </style> </head> <body> <h1>Squares</h1> <xsl:apply-templates/> </body> </html> </xsl:template>
Web Browsers and XSLT (part 2) <xsl:template match="number"> <xsl:variable name="value" select="."/> <p> <xsl:text>The square of </xsl:text> <xsl:value-of select="$value"/> <xsl:text> is </xsl:text> <xsl:value-of select="$value * $value"/>.</p> </xsl:template> </xsl:stylesheet> You could create your HTML like this: saxon -o numbers.html numbers.xml squareAsHTML.xsl
XSLT 2.0 Lots more built-in functions Writing your own functions Regular expressions Grouping output by values Tokenizing strings Typing awareness