xsl:variable


The <xsl:variable> element is used to declare a local or global variable in a stylesheet, and to give it a value.

Changes in 2.0

A new attribute, as , has been introduced. This allows the type of the variable to be declared; it also determines whether an <xsl:variable> element containing a sequence constructor will use the value of the sequence to construct a temporary tree, or will simply set the value of the variable to be this sequence.

Format

 <xsl:variable   name = qname   select? = expression   as? = sequence-type>   <!-- Content: sequence-constructor --> </xsl:variable> 

Position

The <xsl:variable> element may appear either as a top-level declaration (that is, as a child of the <xsl:stylesheet> element), or as an instruction within a sequence constructor.

Attributes

Name

Value

Meaning

name

mandatory

lexical QName

The name of the variable

select

optional

Expression

An expression that is evaluated to give the value of the variable. If omitted, the value is determined from the contents of the <xsl:variable> element

as

optional

SequenceType

Declares the type of the variable. A type error occurs if the value of the expression cannot be converted to this type using the standard type conversions defined below (page 476). In addition, the presence of this attribute on an <xsl:variable> element with nonempty content indicates that the result of evaluating the contained sequence constructor is to be used directly as the value of the variable, rather than being used to construct a temporary tree

The SequenceType construct is outlined in Chapter 4, and described in full detail in Chapter 9 of XPath 2.0 Programmer's Reference .

Content

An optional sequence constructor. If a select attribute is present, the <xsl:variable> element must be empty.

Effect

An <xsl:variable> element may appear either at the top level of the stylesheet (in which case it declares a global variable) or as an instruction within a sequence constructor (in which case it declares a local variable).

The Name of the Variable

The name of the variable is defined by a lexical QName. Normally this will be a simple name such as «city » or «total-sales » , 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 variable, 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 has a null namespace URI-it does not use the default namespace URI.

The scope of a global variable is the entire stylesheet, including any stylesheets that are included or imported. A global variable may even be referenced before it is declared. The only constraint is that circular definitions are not allowed; if variable x is defined in terms of y, then y may not be defined directly or indirectly in terms of x .

The scope of a local variable is block-structured; it may be referenced in any following sibling element or in a descendant of a following sibling. This is illustrated in Figure 5-16.

click to expand
Figure 5-16

The diagram shows, for a variable X, the elements that may contain a reference to X; the shaded elements may refer to X, and the unshaded elements may not. Specifically, a local variable may be referenced in any following sibling element, or in a descendant of a following sibling. It cannot be referenced within its own descendants, and it goes out of scope when the end tag for its parent element is encountered . Unlike global variables, a forwards reference to a local variable is not allowed. If you think of XSLT instructions as being like the statements in a block-structured language such as C, Java, or JavaScript, and the enclosing element as being like a block enclosed in these languages by curly braces, the scope rules will seem very familiar.

Two global variables may have the same name only if they have different import precedence ; in other words, if one of them was in an imported stylesheet (for further details, see <xsl:import> on page 312). In this case, the definition with higher import precedence wins. Note that the higher precedence definition applies everywhere, even within the imported stylesheet that contains the lower precedence definition. This means it is not a good idea to rely on precedence to resolve accidental name clashes between independently developed modules, it's better to use namespaces.

XSLT 1.0 did not allow a local variable to be defined with the same name as another local variable already in scope. This restriction was there as a way of detecting user errors. The restriction has gone in XSLT 2.0, although there is still a warning in the specification advising that this isn't good practice. In fact, not all XSLT 1.0 processors actually enforced this rule. If a variable reference is used when two or more variables with the matching name are in scope, then the reference is taken to refer to the one whose scope is smallest.

This principle extends to variables declared within an XPath expression. To take an extreme example, it is legal to write:

  <xsl:variable name="x" select="'A'"/>   <xsl:template match="para">   <xsl:variable name="x" select="$x, 'B'"/>   <xsl:variable name="x" select="$x, 'C'"/>   <xsl:value-of select="for $x in ($x, 'D') return ($x, '+')"/>   </xsl:template>  

The output of the template will be «A + B + C + D + » .

These rules on uniqueness and scope of names apply equally to parameters declared using <xsl:param> ; the <xsl:param> instruction is effectively just another way of declaring a variable.

The Value of the Variable

The value of the variable 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:variable> element should be empty. If there is no select attribute and the sequence constructor is empty, the value of the variable is a zero-length string, unless there is an as attribute, in which case the value is an empty sequence ( assuming that the as attribute permits an empty sequence).

The table below summarizes the different ways of specifying the value. The numbers in brackets refer to the numbered paragraphs below the table that explain the option in more detail.

   

select present

select absent

content

present

as present

error

Evaluate the content constructor and return its value, checking the type against the as attribute (3)

content

present

as absent

error

Evaluate the content constructor and use it to build a temporary tree (4)

content

absent

as present

Evaluate the select expression and return its value, checking the type against the as attribute (1)

Return an empty sequence, provided the as attribute allows an empty sequence (5)

content

absent

as absent

Evaluate the select expression and return its value (2)

Return a zero-length string (6)

  1. If the select attribute is provided, its value must be an XPath expression. This expression is evaluated. The value is checked against the type specified in the as attribute, and if necessary is converted to this type using the standard conversion rules described on page 476. An error occurs if this conversion is not possible. The processor may report this as a compile-time error if it can tell at compile time that the value of the expression will never be convertible to the required type. Otherwise , it will report the error at runtime. For example:

      <xsl:variable name="pi" select="3.14159" as="xs:double"/>  

    Here the value of the select expression is of type xs:decimal , but the final value of the variable is an xs:double , because the as attribute forces a conversion.

  2. If the select attribute is provided without an as attribute, the effect is the same as if «as="item()*" » were specified: No type checking or conversion takes place, and the value may be of any type. For example:

      <xsl:variable name="pi" select="3.14159eo"/>  

    Here the value of the select attribute is again of type xs:double , but for a different reason: It was written as a double literal, and no conversion has taken place.

  3. If a sequence constructor is used with an as attribute, the instructions in the sequence constructor are evaluated. The result sequence is checked against the type specified in the as attribute, and is converted if necessary using the standard conversion rules. Again, an error is reported if the conversion is not possible. For example:

      <xsl:variable name="n" as="xs:integer">   <xsl:number/>   </xsl:variable>  

    Here the sequence constructor returns a single text node. The contents of this text node are converted to an integer, which becomes the value of the variable.

  4. If a sequence constructor is used with no as attribute, a temporary tree is constructed . This is done by creating a new document node, and using the value of the result sequence to form the children of the document node. The detailed rules for constructing the content of the document node are the same as those for the <xsl:document> instruction, and are given on page 258. The value of the variable will be the document node at the root of the temporary tree. For example:

      <xsl:variable name="tree">   <data>   <country code="de">Germany</country>   <country code="fr">France</country>   <country code="gb">United Kingdom</country>   <country code="us">United States</country>   </data>   </xsl:variable>  

    Here the value of the variable is a document node, whose only child is a <data> element, which in turn has four <country> elements as its children. Temporary trees are described in more detail on page 481.

  5. The following example declares a parameter whose default value is an empty sequence:

      <xsl:param name="codes" as="xs:integer*"/>  

    This option is not very useful for variables, but <xsl:param> follows exactly the same rules as <xsl:variable> , and it can be useful there.

  6. The following example declares a parameter whose default value is a zero-length string:

      <xsl:param name="input"/>  

    Again, this option is not useful for variables, but <xsl:param> follows exactly the same rules as <xsl:variable> , and it can be useful there.

Note that if an expression is used to assign a literal string value to a variable, the string literal must be enclosed in quotes, and these quotes are additional to the quotes used around the XML attribute. So to assign the string value «London » to the variable named «city » , you can write either of the following:

  <xsl:variable name="city" select="'London'"/>   <xsl:variable name="city" select='"London"'/>  

You can also write:

  <xsl:variable name="city" as="xs:string">London</xsl:variable>  

A common mistake is to write:

 <xsl:variable name="city" select="London"/> <!-- WRONG --> 

This sets the value of «$city » to a sequence containing all the element children of the current node that have element name <London> . This will probably be an empty sequence, so if you use the variable as a string, its value will be a zero-length string. You won't get any error message if you make this mistake, because it's a perfectly valid thing to write, it will just cause your stylesheet to produce the wrong output.

A schema-aware XSLT processor might give you a warning saying that there is no <London> element defined in the schema; but you can't rely on this.

You won't be alone if you make this mistake; there's an example of it in the original XSLT 1.0 specification, which had to be fixed in a subsequent erratum.

You don't need the extra quotes if you want the value to be a number:

  <xsl:variable name="max-size" select="255"/>  

Standard Conversion Rules

This section provides the detailed conversion rules used when converting the supplied value of a variable (the result of evaluating its select attribute or its sequence constructor) to the type required by the as attribute. The same conversion rules are used under a number of other circumstances, such as when values are supplied for stylesheet parameters. They are the same as the function conversion rules defined in XPath 2.0, which define what happens when the supplied arguments in a function call differ from the declared types of the parameters, with the exception that the rules described here never use XPath 1.0 backwards compatibility mode. The reason for this is that they are always invoked in contexts where backwards compatibility issues do not arise.

The rules take as input a supplied value and a required type, and they produce as output a result value. The required type has two parts : the required item type (for example, integer or element) and the required cardinality. The required cardinality may be exactly-one (when there is no occurrence indicator in the SequenceType as written) or zero-or-one, zero-or-more, or one-or-more , corresponding to the occurrence indicators «? », «* » , and «+ » .

Instead of returning a result value, the rules may also result in a type error, if the supplied value cannot be converted to the required type.

The rules are as follows:

  1. If the supplied value is an instance of the required type, return it as the result value.

  2. If the required item type is an atomic type, the supplied value is atomized. Atomization causes each node in the supplied sequence to be replaced by its typed value, while leaving any atomic values in the sequence unchanged. Note that the typed value of a node can itself be a sequence of zero or more atomic values. Elements declared in the schema to have element-only content have no typed value, so this operation can result in an error.

  3. Any item in the atomized sequence that is of type xdt:untypedAtomic is cast to the required type. Such items are most likely to arise as the result of atomizing a node in a schema-less document. This means, for example, that an attribute such as @date-of-birth will be acceptable where the required type is xs:date , provided that either (a) the attribute is annotated as an xs:date as a result of schema validation, or (b) the attribute is unvalidated and its textual form is acceptable as an xs:date .

  4. If the required item type is a numeric type (one of xs:double, xs:float, xs:decimal , or xs:integer , or a type derived from these by restricting the range of values), then any numeric value in the atomized sequence is promoted to the required numeric type where possible. An integer can be promoted to any other numeric type; a decimal can be promoted to xs:float or xs:double ; and an xs:float can be converted to an xs:double . However, other conversions are not possible, for example if the required item type is xs:integer but the supplied value is xs:double , a type error will be reported.

If, after these conversions, the sequence conforms to the required type, then it is returned as the result value. If not, the system reports a type error. Type errors may be reported at runtime, but if the system can tell in advance that the expression will return a value of the wrong type, then they can also be reported at compile time.

These rules are not as liberal as the rules that were used in XPath 1.0 for type conversions, where, for example, a boolean could be supplied when a string was expected, and it would be treated as the string " true " or " false " . Because the type system in XSLT 2.0 is so much richer, you have to get used to the idea of thinking about what type of value you are handling, and of doing any necessary conversions yourself, using explicit casts or calls on constructor functions.

Usage

Variables are useful, as in any programming language, to avoid calculating the same result more than once.

Global variables are useful for defining constants, such as a color value, that will be used in many places throughout the stylesheet. They can also be used to extract values from the principal source document.

Unlike variables in many programming languages, XSLT variables cannot be updated. Once they are given an initial value, they retain this value until they go out of scope. This feature has a profound effect on the programming style used when a stylesheet needs to do calculations. The subject of programming without assignment statements is discussed in detail in Chapter 9.

Examples

Most XSLT variables fall into one of the three categories:

  • Variables used to avoid repeating a common expression in more than one place. This might be simply to make the code more readable, or to ensure that you only have to make a change in one place if the value changes, or perhaps because it gives a performance benefit.

  • Variables used to capture context-sensitive information, allowing the variable to be used after the context has changed.

  • Variables holding a temporary tree (or a result tree fragment as it was known in XSLT 1.0).

In each case the variable might be local or global. I'll show some examples of each kind.

Convenience Variables

Consider this example, which calculates the number of goals scored by, and against, a soccer team.

  <xsl:variable name="for"   select="sum($matches/team[.=$this)/@score)"/>   <xsl:variable name    =    "against"   select="sum($matches[team=$this]/team/@score) - $for"/>   ...   <td><xsl:value-of select="$for"/></td>   <td><xsl:value-of select="$against"/></td>  

This uses two rather complex expressions to construct the variables «for » and «against » , which calculate the number of goals scored by, and against, the team identified by the variable «$team » .

It would be quite possible in this case to avoid using the variable «against » . The expression that calculates its value could equally be written at the point where the variable is used, in the second <xsl:value-of> instruction. The same is true of the «for » variable, though this time the expression would need to be written twice, in both places where the variable is used, and this might give a performance penalty. However, these variables are really being used only for clarity; it would be quite possible to write the stylesheet without them.

This is true because nothing can change between the variables being defined and being used. The source document can't change, and the values of the variables $team and $matches can't change. The context (for example the current position in the source document) can change, but in this example (a) it doesn't, and (b) the expressions don't depend on the context anyway.

I call these convenience variables because you could get by without them if you had to (though there might be a performance hit). They can be used either as global variables or as local variables. Creating global convenience variables that refer to sets of nodes in the source document is often a useful programming technique, for example:

  <xsl:variable name="group-A-matches" select="//match[@group='A']"/>  

These act rather like views in an SQL database.

Variables to Capture Context-Sensitive Values

These variables are most often useful in conjunction with <xsl:for-each> , which changes the context item. Consider the following example:

Using a Variable for Context-Sensitive Values
start example

This example shows how a variable can be used to hold on to information that depends on the context, for use when the context has changed.

Source

The source file is opera.xml . It contains a list of operas and details of their composers.

  <?xml version="1.0"?>   <programme>   <opera>   <title>The Magic Flute</title>   <composer>Mozart</composer>   <date>1791</date>   </opera>   <opera>   <title>Don Giovanni</title>   <composer>Mozart</composer>   <date>1787</date>   </opera>   <opera>   <title>Ernani</title>   <composer>Verdi</composer>   <date>1843</date>   </opera>   <opera>   <title>Rigoletto</title>   <composer>Verdi</composer>   <date>1850</date>   </opera>   <opera>   <title>Tosca</title>   <composer>Puccini</composer>   <date>1897</date>   </opera>   <composer name="Mozart">   <fullname>Wolfgang Amadeus Mozart</fullname>   <born>1756</born>   <died>1791</died>   </composer>   <composer name="Verdi">   <fullname>Guiseppe Verdi</fullname>   <born>1813</born>   <died>1901</died>   </composer>   <composer name="Puccini">   <fullname>Giacomo Puccini</fullname>   <born>1858</born>   <died>1924</died>   </composer>   </programme>  

Stylesheet

The stylesheet is the file opera.xsl . This is a complete stylesheet: It uses the simplified stylesheet syntax described on page 119, in Chapter 3.

The stylesheet contains two nested <xsl:for-each> loops . In the outer loop, it sets a variable «c » to the context node (the current composer). In the expression controlling the inner loop, this variable is used. It would not be correct to use «. » in place of «$c » , because the <composer> element is no longer the context node. In this example it would be possible to use the current() function here (this function is described on page 526, in Chapter 7), but there are other cases where a variable is necessary.

  <html   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   xsl:version="1.0">   <body><center>   <h1>Programme</h1>   <xsl:for-each select="/programme/composer">   <h2><xsl: value-of   select= "concat (fullname, ' (', born, '-', died, ')')"/></h2>   <xsl:variable name="c" select="."/>   <xsl:for-each select="/programme/opera[composer=$c/@name]">   <p><xsl:value-of select="title"/></p>   </xsl:for-each>   </xsl:for-each>   </center></body>   </html>  

Output

See Figure 5-17.

click to expand
Figure 5-17
end example
 

One case where context variables are very useful is when handling multiple source documents.

In any stylesheet that handles multiple source documents, it is useful to include a global variable that refers to the document node of the principal source document, thus:

  <xsl:variable name="root" select="/"/>  

This means it is always possible to refer to the source document by using this variable. Without this, when the context node is in a secondary document, there is no way of accessing data from the principal document. For example, the expression «//item » refers to all <item> elements in the same document as the context node. If you actually want all <item> elements in the principal source document, then (provided you have included the global variable declaration above) you can use the expression «$root//item » .

If there is a document referenced from the stylesheet, for example to hold look-up data such as messages or tax rates, it is also useful to define this in a global variable, for example:

  <xsl:variable name="tax-rates" select="document('tax-rates.xml')"/>  

Temporary Trees

The value of a variable is a temporary tree (or result tree fragment as it was known in XSLT 1.0) if it is defined using the content of the <xsl:variable> element rather than the select attribute, and if there is no as attribute.

Temporary trees can be divided into two categories: trivial trees and genuine trees.

A trivial temporary tree will only contain a single text node, in which case it behaves almost exactly like a string variable. Here is an example:

  <xsl:variable name="width">   <xsl:choose>   <xsl:when test="@width">   <xsl:value-of select="@width"/>   </xsl:when>   <xsl:otherwise>0</xsl:otherwise>   </xsl:choose>   </xsl:variable>  

Such a variable can often be useful for expanding the default value of an attribute. Subsequently the variable $width can be used in calculations in place of the attribute @width , without worrying about the case where the attribute was omitted. The fact that the variable is technically a tree rather than a string does not affect the way it can be used.

I prefer in such cases to specify the type of the variable explicitly (which means that the type is no longer a document node):

  <xsl:variable name="width" as="xs:integer">   <xsl:choose>   <xsl:when test="@width">   <xsl:sequence select="@width"/>   </xsl:when>   <xsl:otherwise>0</xsl:otherwise>   </xsl:choose>   </xsl:variable>  

Or more concisely:

  <xsl:variable name="width" as="xs:integer"   select="if (@width) then @width else 0"/>  

Or perhaps even:

  <xsl:variable name="width" as="xs:integer" selects"(@width, 0 ) [1]"/>  

There are several benefits in declaring the type. Firstly, it's good documentation for anyone reading the stylesheet. Secondly, it causes the system to do some error checking for you: If the width isn't an integer, you'll get an appropriate error message. Finally, it's likely to be more efficient. A temporary tree is a rather heavyweight object compared with an integer.

In the example above I substituted <xsl:sequence> for <xsl:value-of> . In fact either instruction would work (in both examples). The system would carry out any necessary conversions automatically.

But in the second example, using <xsl:value-of> would create a text node, only to extract its value and convert this to an integer, which is unnecessarily inefficient.

Beginners often try to write this as:

  <xsl:choose>   <xsl:when test="@width">   <xsl:variable name="width" select="@width"/>   </xsl:when>   <xsl:otherwise>   <xsl:variable name="width" select="0"/>   </xsl:otherwise>   </xsl:choose>  

This won't work, because when you get to the end tag of the <xsl:choose> element, both variable declarations will have gone out of scope!

Tree-valued variables are useful when you use <xsl:call-template> or <xsl:apply-templates> to calculate a value that you then want to manipulate further. The next example shows how this works in the case of <xsl:call-template> , but the same applies equally to <xsl:apply-templates> .

Getting the Result of <xsl: call-template> In a Variable
start example

This example calls a general-purpose template to format a list of items. It captures the result of this template in a variable, and then performs further processing on the result.

Source

The source file is the list of operas and composers used in the previous example, opera.xml .

Stylesheet

The stylesheet is the file composers.xsl .

This stylesheet uses a general-purpose named template ( «make-list » ) to output a list of names in the form «A; B; C; and D » . It passes this template a sequence of nodes containing the names of all the composers in the source document. On return from the «make-list » template, it extracts the result of this template into a variable (which will be a temporary tree containing a single text node), and passes this variable into the translate() function (described in XPath 2.0 Programmer's Reference , Chapter 10) to convert the commas to semicolons. The translate() function converts its first argument to a string, which in this case extracts the value of the text node from the tree.

  <xsl:stylesheet   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   version="1.0">   <xsl:template match="/">   <xsl:variable name="list">   <xsl:call-template name="make-list">   <xsl:with-param name="names"   select="/programme/composer/fullname"/>   </xsl:call-template>   </xsl:variable>   This week's composers are:   <xsl:value-of select="translate($list, ',', ';')"/>   </xsl:template>   <xsl:template name="make-list">   <xsl:param name ="names"/>   <xsl:for-each select="$names">   <xsl:value-of select="."/>   <xsl:if test="position()!=last()">, </xsl:if>   <xsl:if test="position()=last()-l">and </xsl:if>   </xsl:for-each>   </xsl:template>   </xsl:stylesheet>  

Output

This week's composers are:

  Wolfgang Amadeus Mozart; Guiseppe Verdi; and Giacomo Puccini  
end example
 

Most of the examples so far have used trivial trees, those containing a single text node. These can be manipulated to all intents and purposes as if they were strings, with the additional feature that the string will be converted to whatever type is required when it is used. (Technically, the value of the variable is a document node. The standard type conversions will atomize this document node if necessary, which returns a value of type xdt:untypedAtomic , and in contexts where the standard conversion rules are used, such as function calls and XSLT variable initialization, a value of xdt:untypedAtomic will be automatically cast to the required type.) Although convenient , you should be aware that using a trivial temporary tree rather than an atomic value is likely to incur some system overhead.

Genuine (nontrivial) temporary trees have a rather more important role to play. They are needed whenever you require working data that is too complex to hold in a simple sequence. With XSLT 2.0, it is possible to perform any operation on a temporary tree that you can perform on the principal source document, or on a document loaded using the document() function. This greatly increases their usefulness . There are two main categories:

  • Intermediate results of a multiphase transformation.

    It's often useful to break up a transformation into a sequence of steps, to simplify the logic. A temporary tree can be used as the output of the first phase and the input to the next.

  • Working data passed as a parameter through template or function calls.

    For example, if you need to create a data structure such as a list of keyword/value pairs, and pass this as a parameter to a function or template, then the best way to construct this data structure is as a tree.

The next example shows a multiphase transformation.

A MultiPhase Transformation
start example

This example performs a transformation in two phases. The first phase starts with a list containing the results of a series of soccer matches, and computes a league table showing the standing of the various teams . The second phase renders this league table in HTML. These are quite separate operations and it's best to keep them separate. In fact, we'll keep them completely separate by using different stylesheet modules and different modes.

Source

The source document is soccer.xml . It contains the results of individual matches. Here are the first few:

  <results group="A">   <match>   <date>10-Jun-98</date>   <team score="2">Brazil</team>   <team score="1">Scotland</team>   </match>   <match>   <date>10-Jun-98</date>   <team score="2">Morocco</team>   <team score="2">Norway</team>   </match>   <match>   <date>16-Jun-98</date>   <team score="1">Scotland</team>   <team score="1">Norway</team>   </match>   ...   </results>  

Stylesheet

The first phase of the transformation calculates a league table. This is in module league.xsl , shown below:

  <xsl:transform   xmlns:xsl="http://www.w3   .   org/1999/XSL/Transform"   version="2.0"   >   <xsl:variable name="teams" select="distinct-values(//team)"/>   <xsl:variable name="matches" select="//match"/>   <xsl:template match="results">   <league>   <xsl:for-each select="$teams">   <xsl:variable name="this" select="."/>   <xsl:variable name="played" select="count($matches[team=$this])    "/>    <xsl:variable name="won"   select="count($matches[team[.=$this]/@score gt   team[.!=$this)/@score))"/>   <xsl:variable name="lost"   select="count($matches[team[.=$this]/@score lt   team[.!=$this]/@score])"/>   <xsl:variable name="drawn"   select="count ($matches [team[.$this]/@score eq   team[.!=$this]/@score])"/>   <xsl:variable name="for"   select="sum($matches/team[. =current ()]/@score)"/>   <xsl:variable name="against"   select="sum($matches[team=current()]/team/@score) - $for"/>   <team name="{.}" played="{$played}" won="{$won}" drawn="{$drawn}"   lost="{$lost}" for="{$for}" against="{$against}"/>   </xsl:for-each>   </league>   </xsl:template>   </xsl:transform>  

Since we're talking about usage of <xsl:variable> here, it's worth drawing attention to the way this example uses variables. There are a couple of global variables to define the list of teams and the list of matches. Since the stylesheet only contains one template, these variables could equally well have been local, but making them global reflects the fact that they are potentially reusable. Within the template, the variable $this is set to the context item so that it can be used within predicates, where the context item will have changed. Then the computation is done entirely within a sequence of local variable declarations. This is a very characteristic programming style. Finally, the template outputs one <team> element for each team, with attributes indicating the number of matches won and lost, the goals scored, and so on.

The second stylesheet renders the league table into HTML. It's quite straightforward:

  <xsl: transform   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   veraion="2.0"   >   <xsl:import href="league.xsl"/>   <xsl:variable name="league">   <xsl:apply-templates select="results"/>   </xsl:variable>  

Note the variable here to capture the result of the first phase of processing. The value of this variable will be a document node containing the <league> element created by the previous stylesheet.

  <xsl:template match="/">   <html>   <head><title>League Table</title></head>   <body>   <h1>League Table</h1>   <xsl:copy-of select="$league"/>   <table border="2" cellpadding="5">   <thead>   <th>Team</th>   <th>Played</th>   <th>Won</th>   <th>Lost</th>   <th>Drawn</th>   <th>For</th>   <th>Against</th>   </thead>   <tbody>   <xsl:for-each select="$league/league/team">   <tr>   <td><xsl:value-of select="@name"/></td>   <td><xsl:value-of select=''@played''/></td>   <td><xsl:value-of select="@won''/></td>   <td><xsl:value-of select="@lost"/></td>   <td><xsl:value-of select=''@drawn''/></td>   <td><xsl:value-of select="@for''/></td>   <td><xsl;value-of select=''@against"/></td>   </tr>   </xsl:for-each>   </tbody>   </table>   </body>   </html>   </xsl:template>   </xsl:transform>  

Output

The output of the stylesheet is shown in Figure 5-18.

click to expand
Figure 5-18
end example
 

See Also

<xsl:param> on page 392




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