Setting and Using Variables and Parameters
by Bob DuCharme
|
Pages: 1, 2
Parameters
The xsl:param instruction is just like xsl:variable with one important difference: its value is only treated as a default value and can be overridden at runtime. All the stylesheet examples up to this point would work the same way if you substituted xsl:param elements for their xsl:variable elements, but you would have the option of overriding the values when calling their templates.
For example, let's take one of the earlier examples and make the substitution. Here is how it looks as a complete stylesheet:
<!-- xq348.xsl: converts xq338.xml into xq339.html.
Compare this with xq340.xsl. -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:param name="bodyTextSize">10pt</xsl:param>
<xsl:template match="winery">
<b><font size="{$bodyTextSize}"><xsl:apply-templates/>
<xsl:text> </xsl:text>
<xsl:value-of select="../@grape"/></font></b><br/>
</xsl:template>
<xsl:template match="product">
<i><font size="{$bodyTextSize}">
<xsl:apply-templates/></font></i><br/>
</xsl:template>
<xsl:template match="year | price">
<font size="{$bodyTextSize}"><xsl:apply-templates/></font><br/>
</xsl:template>
</xsl:stylesheet>
If we run it as shown with the same source document, it produces the same result as the previous section's version that used xsl:variable instead of xsl:param:
<b><font size="10pt">Duckpond Cabernet</font></b><br/> <i><font size="10pt">Merit Selection</font></i><br/> <font size="10pt">1996</font><br/> <font size="10pt">11.99</font><br/>
However, if we pass the stylesheet a value of "8pt" to use for bodyTextSize, it substitutes this new value for all uses of this parameter:
<b><font size="8pt">Duckpond Cabernet</font></b><br/> <i><font size="8pt">Merit Selection</font></i><br/> <font size="8pt">1996</font><br/> <font size="8pt">11.99</font><br/>
Of course, I'm skimming over one important detail here: how do you pass the alternative value for the parameter to the stylesheet? The XSLT Recommendation doesn't tell us. In fact, it deliberately tells us that it's not going to tell us. Just as the W3C's XSL Working Group wanted to leave the potential methods for giving input to and getting output from an XSLT processor as open as possible, they also didn't want to limit how the processors will be told a new value for a global parameter setting. (As we'll see, not all parameters are global like the bodyTextSize one above; they can also be local to template rules.) So, it's up the particular XSLT processor's designer. To pass the new value of "8pt" to the stylesheet when using the Saxon XSLT processor, the command line might look like this:
java com.icl.saxon.StyleSheet -x org.apache.xerces.parsers.SAXParser -y org.apache.xerces.parsers.SAXParser xq338.xml xq348.xsl bodyTextSize=8pt
(It's actually one command split over three lines to fit on the page here. When really using Saxon or any other Java-based XSLT processor, it makes your life easier to store everything before the "xq338.xml" in that command line in a Windows batch file, a UNIX shell script, or your operating system's equivalent. Then you can pass it the important parameters each time you run it with no need to type the full Java library names for the XSLT processor and XML parser.)
The only difference between applying the xq348.xsl stylesheet to the xq338.xml document this way and running it with the bodyTextSize default value is the addition of the "bodyTextSize=8pt" part at the end. Other XSLT processors may require a different syntax when passing a new parameter value along from the command line, but they would still create the same result when using this stylesheet and input.
Local parameters are even more useful in template rules than XSLT local variables are, because the flexibility of passing one or more values to a template lets that template adapt to different situations. Named templates that don't take advantage of this can still operate as functions or subroutines, but when you use named templates that do, you can start treating XSLT like a real programming language. For example, the ability of named templates to call themselves with parameters makes recursion and all the power associated with it possible.
How we pass a new value to a template rule's local parameter isn't quite the open question that it is with global parameters because XSLT provides the xsl:with-param instruction for just this purpose. You can use this element in an xsl:apply-templates element to assign a new value to a parameter in a template being applied, but it's more commonly used when calling a named template with the xsl:call-template instruction. For example, the first template rule in the following stylesheet has a name attribute and not a match attribute. Instead of the XSLT processor looking for nodes where it can apply this template, the processor will wait until the template is explicitly called with an xsl:call-template instruction.
<!-- xq352.xsl: converts xq353.xml into xq354.html -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<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>
<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="chapter">
<html><body><xsl:apply-templates/></body></html>
</xsl:template>
</xsl:stylesheet>
The second and third template rules, which have match patterns of "chapter/title" and "section/title", call the first template by its name of "titles" using xsl:call-templates elements. These xsl:call-templates elements don't need any children, but they have them here: xsl:with-param elements to pass parameter values to the named templates. The "titles" template rule will use these values to override the default value of "h4" when it's called. The with-param instruction in the "chapter/title" template rule is saying "pass along the value 'h1' for the headerElement parameter", and the one in the "section/title" template rule is passing the value 'h2'. For this input document,
<chapter><title>Chapter 1</title>
<para>Then with expanded wings he steers his flight</para>
<para author="ar">Aloft, incumbent on the dusky Air</para>
<section><title>Chapter 1, Section 1</title>
<para>That felt unusual weight, till on dry Land</para>
<para>He lights, if it were Land that ever burned</para>
</section>
</chapter>
the "titles" template is called when the XSLT processor finds each of
the two title element nodes. The "titles" named template uses
the passed values to create the h1 and h2 elements
in the result:
<html>
<body>
<h1>Chapter 1</h1>
<p>Then with expanded wings he steers his flight</p>
<p>Aloft, incumbent on the dusky Air</p>
<h2>Chapter 1, Section 1</h2>
<p>That felt unusual weight, till on dry Land</p>
<p>He lights, if it were Land that ever burned</p>
</body>
</html>
Just as an xsl:param element can specify its default value as either content between its start- and end-tags or as the value of a select attribute, the xsl:with-param element can indicate the value to pass using either method. The two xsl:with-param elements in the example above use the two different methods to demonstrate this.
The XSLT processor evaluates the xsl:with-param element's select value as an expression just like it does with the xsl:param element's select attribute value. This is why the third template above needs single quotation marks around the value of "h2" even though it's also enclosed by double quotation marks. The double quotation marks serve a different purpose: to tell the XML parser where the select attribute value starts and ends. The inner single quotation marks tell the XSLT processor that the value is a literal string and not an expression to evaluate.
| Note The name value specified in the xsl:call-template element cannot contain a variable reference. For example, if you declared a variable called templateName and stored the string "title" there, an xsl:call-template start-tag of <xsl:call-template name="$templateName"> would not work in the previous example's "chapter/title" or "section/title" template rules. |
You don't have to specify a hardcoded string like "h1" or "h2" as the value of the parameter to pass in an xsl:with-param element. You can put the result of one or more functions in there, or even an XPath expression that retrieves a value from somewhere in the document (or even from another document, using the document() function). This ability opens up an even broader range of possibilities for how you use parameter passing in XSLT.