xsl:param


The <xsl:param> element is used either at the top level, to describe a global parameter, or immediately within an <xsl:template> element, to describe a local parameter to a template. It specifies a name for the parameter and a default value, which is used if the caller supplies no value for the parameter.

Changes in 2.0

An as attribute has been added to define the required type of the parameter.

A required attribute has been added to indicate whether the parameter is mandatory or optional.

A tunnel attribute has been added to support the new facility of tunnel parameters.

Format

 <xsl:param   name = qname   select? = expression   as? = sequence-type   required? = "yes"  "no"   tunnel? = "yes"  "no">   <!-- Content: sequence-constructor --> </xsl:param> 

Position

<xsl:param> may appear as a top-level declaration (a child of the <xsl:stylesheet> element), or as an immediate child element of <xsl:template> or <xsl:function>. The three kinds of parameters are known as stylesheet parameters, template parameters , and function parameters.

In the case of template parameters and function parameters, <xsl:param> elements must come before any other child elements.

Attributes

Name

Value

Meaning

name

mandatory

QName

The name of the parameter

select

optional

Expression

The default value of the parameter if no explicit value is supplied by the caller

as

optional

SequenceType

The required type of the parameter value

required

optional

«yes » or «no »

Indicates whether the parameter is optional or mandatory

tunnel

optional

«yes » or «no »

Indicates whether the parameter is a tunnel parameter

The SequenceType construct is described in Chapter 4, on page 154, and more fully in Chapter 9 of XPath 2.0 Programmer's Reference .

The required attribute is available only for stylesheet parameters and template parameters, not for function parameters (function parameters are always mandatory).

The tunnel attribute is available only for template parameters.

Content

An optional sequence constructor. If a select attribute is present, the element must be empty.

Effect

An <xsl:param> element at the top level of the stylesheet declares a global parameter; an <xsl:param> element appearing as a child of an <xsl:template> element declares a local parameter for that template, and an <xsl:param> element appearing as a child of an <xsl:function> element declares a local parameter for that function.

The <xsl:param> element defines the name of the parameter, and a default value. The default value is used only if no other value is explicitly supplied by the caller. Default values can be supplied for stylesheet parameters and template parameters, but not for function parameters, which must always be supplied in the function call.

An explicit value can be supplied for a template parameter by using the <xsl: with-param > element when the template is invoked using <xsl:apply-templates>, <xsl:call-template>, <xsl: next -match>, or <xsl: apply-imports >.

For function parameters, values are supplied in the function call. The syntax of function calls is defined in Chapter 5 of XPath 2.0 Programmer's Reference . Function calls pass parameters positionally rather than by name; the nth argument in the function call is evaluated to provide the value for the n th <xsl:param> element in the function definition.

The way in which explicit values are supplied for stylesheet parameters is implementation-defined (for example, they may be defined on the command line or through environment variables , or they may be supplied via a vendor-defined API). Information about Microsoft APIs is given in Appendix C, and that about Java APIs in Appendix D.

The Type of the Parameter

The required type of the parameter can be specified using the as attribute. For example, «as="xs:integer" » indicates that a single integer is expected, «as="xs:string*" » indicates that a sequence of strings is expected, and «as="element()+" » indicates that the required type is a sequence of one or more element nodes. With a schema-aware processor it is also possible to supply schema-defined types, for example «as="abc:vehicle-registration" » indicates that the parameter must be an atomic value conforming to the user -defined simple type abc:vehicle-registration, while «as="schema-element (EVENT)" » indicates that it must be an element node validated as being either an EVENT element or an element in the substitution group of EVENT .

If the as attribute is omitted, then the supplied value may be of any type.

The value that is actually supplied by the caller must be suitable for the required type. The value is converted if necessary using the standard conversion rules described on page 476, and it is a fatal error if this conversion fails. Because the ability to specify a type on <xsl:param> is new in XSLT 2.0, the conversion is done according to the XPath 2.0 rules-the 1.0 compatibility rules are not used even if the stylesheet version is set to «1.0 » . In summary, this means that the only conversions allowed are:

  • Atomization (that is, extraction of the typed values of nodes, when the required type is an atomic value or a sequence of atomic values)

  • Numeric promotion, for example conversion of xs: integer to xs:double

  • Casting of xdt:untypedAtomic values (which normally arise as a result of atomizing a node in a document that has not been schema-validated)

If the supplied parameter is the wrong type, then the error may be detected either at compile time or at runtime. With stylesheet parameters the supplied value isn't known until runtime, so this is when the error will occur. The error is more likely to be detected at compile time in the case of calls to named templates or to stylesheet functions.

The as attribute on <xsl:param> also serves a second purpose. Like the as attribute on <xsl:variable>, it is used when the <xsl:param> element has a contained sequence constructor to distinguish whether the default value is the sequence obtained by evaluating the sequence constructor, or the result of building a temporary tree using this sequence to provide the content. For example:

  <xsl:param name="p">Madrid</xsl:param>  

declares a parameter whose default value is a temporary tree consisting of a document node, which owns a text node whose string value is «Madrid »; while

  <xsl:param name="p" as="xs:string">Madrid</xsl:param>  

declares a parameter whose required type is a single string, and whose default value is the string «Madrid » . If you really need to say that the required type is a document node, and to supply a temporary tree as the default value, then you can write it like this:

  <xsl:param name="p" as="document-node()">   <xsl:document>Madrid</xsl:document>   </xsl:param>  

The Default Value of the Parameter

In the case of stylesheet parameters and template parameters, if no value for the parameter is supplied by the caller, a default value is used. The default value of the parameter may be given either by the XPath expression in the select attribute, or by the contents of the contained sequence constructor. If there is a select attribute, the <xsl:param> element should be empty.

The value is calculated in exactly the same way as the value of a variable in <xsl:variable>, and the rules are as given on page 473. Note that the default value need not be a constant; it can be computed in terms of the values of other parameters appearing earlier in the list, and can also depend on information such as the context item and context size .

If there is no select attribute and the sequence constructor is empty, the default value of the parameter is a zero-length string, unless there is an as attribute, in which case the default value is an empty sequence.

If the required attribute has the value «yes », then the parameter is mandatory. In this case, it makes no sense to supply a default value, so the select attribute must be omitted and the element must be empty. Failing to supply a value for a mandatory parameter is a compile-time error in the case of <xsl:call-template>, but a runtime error in all other cases.

The Name of the Parameter

The name of the parameter is defined by the QName given in the name attribute. Normally this will be a simple name (such as «num » or «list-of- names » ), but it may be a name qualified with a prefix, for example «my:value » . If it has a prefix, the prefix must correspond to a namespace that is in scope at that point in the stylesheet. The true name of the parameter, for the purpose of testing whether two names are the same, is determined not by the prefix but by the namespace URI corresponding to the prefix, so two variables «my:value » and «your:value » have the same name if the prefixes «my » and «your » refer to the same namespace URI. If the name has no prefix, it is treated like an attribute name; that is, it has a null namespace URI-it does not use the default namespace URI.

Parameter names are referenced in exactly the same way as variables, by prefixing the name with a dollar sign (for example «$num » ) and all the rules for uniqueness and scope of names are exactly as if the <xsl:param> element was replaced by an <xsl:variable> element. The only difference between parameters and variables is the way they acquire an initial value.

Tunnel Parameters

Tunnel parameters are a new facility in XSLT 2.0. They have the property that if a tunnel parameter is passed to a template when it is called, then it is automatically passed on to any further templates called from this template. For example, if template A creates a tunnel parameter and passes it on a call to template B, then when B calls C and C calls D, the tunnel parameter will be passed transparently through all these calls and will be accessible to template D, even if B and C were quite unaware of the parameter.

This feature is very useful when you are customizing a stylesheet. Suppose that D is a template rule that formats equation numbers in roman numerals, and you want to use greek letters instead. You can write a customization layer (an importing stylesheet) that overrides D with a template rule of your own. But suppose you want D sometimes to use greek letters and sometimes roman numerals, how do you pass it this information? Global variables only solve the problem if the choice is constant for all invocations of D during the course of a transformation. Adding parameters to every template en route from your top-level A template to the D template would require overriding lots of template rules in the base stylesheet, which you want to change as little as possible. So the answer is that you write a customized version of the A template that sets a tunnel parameter, and a customized version of D that reads the tunnel parameter, and the intermediate templates B and C don't need to be changed.

The theory behind tunnel parameters is the concept of dynamically scoped variables in functional programming languages such as Lisp.

A tunnel parameter always starts life in an <xsl:with-param> element. This may be on any kind of template call that allows parameter passing: specifically , <xsl:apply-templates>, <xsl:call-template>, <xsl:apply-imports>, and <xsl:next-match> . For example:

  <xsl:template match="/">   <xsl:apply-templates select="body">   <xsl:with-param name="mq:format-greek" tunnel="yes" select="true()"/>   </xsl:apply-templates>   <xsl:apply-templates select="back">   <xsl:with-param name="mq:format-greek" tunnel="yes" select="false()"/>   </xsl:apply-templates>   </xsl:template>  

I've put the parameter name in a namespace here, to minimize the risk that it will clash with a parameter added by someone else.

This tunnel parameter will be passed silently up the call stack, through all calls of <xsl:apply-templates>, <xsl:call-template>, <xsl:apply-imports>, and <xsl:next-match>, until it reaches a template that is interested in it. This template can declare its interest by including the parameter declaration:

  <xsl:param name="mq:format-greek" as="xs:boolean" required="yes"   tunnel="yes"/>  

and can then use the parameter value in the normal way, by referring to it as «$mq:format-greek » within an XPath expression.

Tunnel parameters are not passed through XPath function calls, so if the stylesheet evaluates an XPath expression which in turn calls a stylesheet function, which in turn calls <xsl:apply-templates>, then the tunnel parameters will not be accessible in this call. Similarly, they are not available when an attribute set is expanded.

At the point where the parameter enters the tunnel (the <xsl:with-param> element) it must have a name that differs from all the other sibling <xsl:with-param> elements, whether these are tunnel parameters or not. Similarly, when it emerges from the tunnel (the <xsl:param> element) it must have a name that differs from other <xsl:param> elements in that template. But where it is being silently passed through intermediate templates, name clashes don't matter: silently passed tunnel parameters are in effect in a different symbol space from explicit parameters.

Tunnel parameters can be of any data type. They can be optional or required parameters, and if optional the receiving template can declare a default value. Reading the tunnel parameter in this way isn't destructive; it will still be passed on to further templates. Specifying a required type or a default value or a required type doesn't change the value that is passed on: For example if the original value is a node, and the receiving template declares it as a string, then the node will be atomized for the purposes of the receiving template, but the value that's passed on will still be a node, unless a new <xsl:with-param> element is used to change the value.

Usage

The different kinds of parameters (stylesheet parameters, template parameters, and tunnel parameters) can be used in different ways. These are discussed in the following sections.

Using Stylesheet Parameters

Stylesheet parameters can be used in various ways to control the actions performed by the transformation. For example, they are particularly useful for selecting which part of the source document to process. A common scenario is that the XSLT processor will be running within a Web server. The user request will be accepted by a Java Server Page or by a Java servlet, or indeed by an ASP page, the request parameters will be accepted, and the stylesheet processing will be kicked off using an API defined by each vendor. Generally this API will provide some way of passing the parameters that came from the HTTP request into the stylesheet as the initial values of global <xsl:param> elements.

If the API supports it, a global parameter may take a value of any type: not just a string, number, or boolean, but also a node or sequence of nodes. Because the value can contain nodes, this provides another way of supplying secondary source documents for use by the stylesheet, as an alternative to the document() function. Many products allow such a parameter to be supplied as a DOM Document object.

Where a stylesheet needs to get system-dependent information (for example, the URI of the source document, or the operating system version number) it is often much easier to pass the information as a stylesheet parameter rather than writing extension functions to deliver the information on request.

Wherever you define a global variable, ask yourself whether it would be better to make it a stylesheet parameter instead. The default value of a stylesheet parameter can be used in exactly the same way as a global variable; the only difference is that you have added the ability for the user to change the value from outside.

The new facilities in XSLT 2.0 to declare a stylesheet parameter with «required="yes" », and to declare its required type, make stylesheet parameters a lot more robust than they were.

Using Template Parameters

Template parameters are used more often with <xsl:call-template> than with <xsl:apply-templates>, though they are available to both, and in XSLT 2.0 they can also be used with <xsl:apply-imports> and <xsl:next-match> . The actual value of the parameter is set by the caller using an <xsl:with-param> element. Parameters are often needed by the recursive algorithms used in XSLT to handle lists of items: There are examples of such algorithms under <xsl:call-template> on page 220. In XSLT 2.0, however, it is often more convenient to implement such algorithms using <xsl:function> .

Declaring the expected type of a parameter, using the as attribute, is optional, but I would always recommend it. It provides useful documentation for anyone who has to debug the stylesheet later, as well as trapping errors when the caller provides incorrect parameter values. My experience is that it catches many coding errors that would otherwise have led to incorrect output being generated. In addition, the information is very useful to the XSLT processor itself, as it enables optimized code to be produced. For example, a test such as <xsl:if test="$p=3"> is very much simpler if it is known in advance that $p will always be an integer, than if the processor has to deal with the possibility of it being a node, a sequence of nodes, a sequence of doubles, or perhaps an untypedAtomic value.

Using Tunnel Parameters

Tunnel parameters provide a half-way house between global variables and local template parameters, combining the advantages of both and removing many of the problems of both.

Compared with global variables, their great advantage is that their value can change in the course of the transformation. This doesn't mean that they introduce side effects, because only the caller of a template can set the value, not the callee.

Compared with local parameters, their great advantage is that you don't have to change every template in the stylesheet to pass the values through.

I found a good use case for tunnel parameters in the stylesheet used to generate the XSLT working draft. The XML master version of this document includes entries describing each error condition that can arise. This is used both to generate inline descriptions of the errors in the document body, and to generate a summary of errors in an appendix. Much of the code to handle the two cases is the same, but a few details differ , for example the way that hyperlinks are generated. Traditionally this problem is tackled using modes; however, even with the XSLT 2.0 ability to write a single template rule that works in more than one mode, using modes means that the intermediate template rules need to be aware of the fact that they can be invoked under two different circumstances. They shouldn't need to know this: Only the code that produces different results in the two cases should need to know that there are two possible cases. A tunnel parameter indicating which phase of processing is active solves the problem neatly.

Examples

This section presents two examples showing the use of <xsl:param> to define template parameters. The first is a very simple demonstration of how parameters work with <xsl:call-template> . The second is a more complicated example, making use of tunnel parameters.

Using <xsl: param> with a Default Value
start example

This example shows a simple named template that defines a parameter and gives it a default value.

Source

This stylesheet works with any XML source file.

Stylesheet

The stylesheet is call.xsl.

It contains a named template that outputs the depth of a node (defined as the number of ancestors ). The node may be supplied as a parameter; if it is not supplied, the parameter defaults to the current node.

The stylesheet includes a template rule for the document node that invokes this named template, defaulting the parameter, to display the name and depth of every element in the source document.

  <xsl:transform   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   version="2.0"   >   <xsl:output method="text"/>   <xsl:template match="/">   <xsl:for-each select="//*">   <xsl:value-of select="concat(name(), ' -- ')"/>   <xsl:call-template name="depth"/>;   </xsl:for-each>   </xsl:template>   <xsl:template name="depth">   <xsl:param name="node" as="node()" select="."/>   <xsl:value-of select="count($node/ancestor::node())"/>   </xsl:template>   </xsl:transform>  

Output

If the stylesheet is run against the file poem.xml used in Chapter 1, the output is as follows :

  poem -- 1;   author -- 2;   date -- 2;   title -- 2;   stanza -- 2;   line -- 3;   line -- 3;   line -- 3;   line -- 3;   stanza -- 2;   line -- 3;   line -- 3;   line -- 3;   line -- 3;   stanza -- 2;   line -- 3;   line -- 3;   line -- 3;   line -- 3;  
end example
 
Tunnel Parameters
start example

Realistic examples using tunnel parameters tend to involve customization of rather complex stylesheets, such as the DocBook stylesheet suite ( http://docbook. sourceforge .net/ ) produced by Norman Walsh. Unfortunately, explaining such an example would take a full chapter of this book. So we'll make do with a simpler case.

Suppose that you start with the stylesheet play.xsl, which is designed to generate a set of linked HTML files containing the text of one of Shakespeare's plays as marked up by Jon Bosak. I won't present this stylesheet in full, because it's pretty standard, and most of it isn't relevant to the example. The challenge now is to customize this stylesheet so that instead of producing a single rendition of the play, it produces a script for each of the characters appearing in the play, with the lines spoken by the character highlighted. You will do this by producing another stylesheet module, script.xsl, which overrides selected template rules from the original.

Source

This stylesheet can be applied to any of the Shakespeare plays available from http://metalab.unc.edu/bosak/xml/eg/shaks200.zip . The examples use othello.xml, which is included in the download files for this book.

Output

The existing stylesheet, play.xsl, produces a set of HTML files: one file called play.html, which acts as a cover sheet and index, and one file for each scene in the play, with names such as sceneN.html. You can run it with a command like this:

  java -jar c:\saxon\saxon7.jar othello.xml play.xsl dir=c:/temp/othello  

The first page of the output, in the file play.html , is shown in Figure 5-10.

click to expand
Figure 5-10

In the customized presentation, we want to create an index page that looks like the one shown in Figure 5-11.

click to expand
Figure 5-11

This presents an index showing all the speaking parts in the play. Clicking on one of the names brings up a modified version of the front page shown before, in which the titles of the scenes are shown as active links if the character appears in these scenes, or as plain text otherwise. The actual text of the scene should also be modified so that the speaker's lines are highlighted.

Stylesheet

The base stylesheet play.xsl is unmodified (it is one that has been included in the Saxon distribution for a while, to illustrate how a stylesheet can create multiple output files).

The customization layer is in the file scripts.xsl . This starts by importing play.xsl . It then contains a template rule providing the new control logic:

  <xsl:template match="/">   <xsl:variable name="play" select="PLAY"/>   <xsl:result-document href="file:///{$dir}/index.html" format="play">   <HTML>   <HEAD><TITLE><xsl:apply-templates select="PLAY/TITLE"/></TITLE>   </HEAD>   <BODY BGCOLOR='{$backcolor}'>   <CENTER>   <H1><xsl:value-of select="PLAY/TITLE"/></H1>   <H3><xsl:apply-templates select="PLAY/PLAYSUBT"/></H3>   <I><xsl:apply-templates select="PLAY/SCNDESCR"/></I>   <BR/><BR/>   <P>   <xsl:for-each select="distinct-values(//SPEAKER)">   <A HREF="{escape-uri(.,true())}/play.html">   <xsl:value-of select="."/>   </A>   <xsl:if test="position() ne last()">  </xsl:if>   <xsl:apply-templates select="$play">   <xsl:with-param name="speaker" select="." tunnel="yes"/>   </xsl:apply-templates>   </xsl:for-each>   </P>   </CENTER>   </BODY>   </HTML>   </xsl:result-document>   </xsl:template>  

This template creates the index page. It calls the distinct-values() function to get a list of speakers appearing in the play, and for each one, it firstly outputs a hyperlink to a play.html file in a subdirectory named after the speaker, and then calls <xsl:apply-templates> to process the <PLAY> element, which is the outermost element in the source file. Crucially, it supplies the name of the speaker as a tunnel parameter to this template.

There are three template rules in the play.xsl stylesheet that need to be modified: These are the template for the <PLAY> element (because the play.html file now has to be placed in a subdirectory), the template for the <SCENE> element (which must now generate pages only for those scenes in which the selected speaker appears), and the template for the <SPEECH> element (to highlight the lines spoken by the selected speaker). Each of these contains a declaration of the tunnel parameter in an <xsl:param> element. Here is the modified template for the <SCENE> element:

  <xsl:template match="SCENEPROLOGUEEPILOGUE">   <xsl:param name="speaker" tunnel="yes" required="yes"/>   <xsl:variable name="NR">   <xsl:number count="SCENEPROLOGUEEPILOGUE" level="any"/>   </xsl:variable>   <xsl:variable name="play" select="ancestor::PLAY/TITLE"/>   <xsl:variable name="act" select="ancestor::ACT/TITLE"/>   <xsl:choose>   <xsl:when test=".//SPEAKER = $speaker">   <A HREF="scene{$NR}.html">   <xsl:value-of select="TITLE" />   </A><BR/>   <xsl:result-document href=   "file:///{$dir}/{escape-uri($speaker, true())}/scene{$NR}.html"   format="scene">   <HTML>   <HEAD>   <TITLE>   <xsl:value-of select="concat($play, ' ', $act, ':', TITLE)"/>   </TITLE>   </HEAD>   <BODY BGCOLOR='{$backcolor}'>   <P>   <A HREF="play.html"><xsl:value-of select="$play"/>   </A><BR/>   <B><xsl:value-of select="$act"/></B><BR/>   </P>   <xsl:apply-templates/>   </BODY>   </HTML>   </xsl:result-document>   </xsl:when>   <xsl:otherwise>   <xsl:value-of select="TITLE"/><BR/>   </xsl:otherwise>   </xsl:choose>   </xsl:template>  

The modifications here, apart from the addition of the <xsl:param> to declare the tunnel parameter, are the addition of the <xsl:choose> to generate the scene page conditionally, and the choice of file name produced by <xsl:result-document> .

The template rule for the <SPEECH> element becomes:

  <xsl:template match="SPEECH">   <xsl:param name="speaker" required="yes" tunnel="yes"/>   <TABLE><TR>   <TD WIDTH="160" VALIGN="TOP">   <xsl:if test="SPEAKER = $speaker">   <xsl:attribute name="BGCOLOR" select="'cyan'"/>   </xsl:if>   <xsl:apply-templates select="SPEAKER"/>   </TD>   <TD VALIGN="TOP">   <xsl:apply-templates select="STAGEDIRLINE"/>   </TD>   </TR></TABLE>   </xsl:template>  

The changes from the original are addition of the <xsl:param> declaring the tunnel parameter, and the addition of the <xsl:if> instruction that outputs an attribute changing the background color if the selected speaker participates in this <SPEECH> (a <SPEECH> can have more than one <SPEAKER>, the equality test succeeds if any of them match).

The key point about this example is that the original stylesheet has been customized and reused without changing it in any way. Without tunnel parameters, this would have required many more of its template rules to be changed, merely to pass the extra parameter through.

end example
 

See Also

  • <xsl:apply-templates> on page 187

  • <xsl:call-template> on page 220

  • <xsl:variable> on page 471

  • <xsl:with-param> on page 488




XSLT 2.0 Programmer's Reference
NetBeansв„ў IDE Field Guide: Developing Desktop, Web, Enterprise, and Mobile Applications (2nd Edition)
ISBN: 764569090
EAN: 2147483647
Year: 2003
Pages: 324

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net