XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition (265 page)

BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition
11.15Mb size Format: txt, pdf, ePub

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:


Variables to Hold Intermediate Results

When a complex transformation task is undertaken, it is often useful to split it into a sequence of steps. The output of one step can be held in a variable, which is then used as the input to the next step.

Any kind of value can be used as an intermediate result, but most commonly it will either be a sequence of items, or a temporary document.

The value of a variable will be a temporary document (or a result tree fragment as it was known in XSLT 1.0) if it is defined using the content of the

element rather than the
select
attribute, and if there is no
as
attribute.

Variables evaluated using a sequence constructor are useful when you use

or

to calculate a value that you then want to manipulate further. If such a value is complex, it will generally take the form of a temporary document. Such documents 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 document 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 (often referred to as a
    pipeline
    ), 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.

Example: A Multiphase Transformation

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:



10-Jun-98

Brazil

Scotland



10-Jun-98

Morocco

Norway



16-Jun-98

Scotland

Norway




Stylesheet

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

 xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”

 version=“2.0”

>





  

     

     

     

           select=“count($matches[team[.=$this]/@score gt

                                 team[.!=$this]/@score])”/>

     

          select=“count($matches[team[.=$this]/@score lt

                                 team[.!=$this]/@score])”/>

     

          select=“count($matches[team[.=$this]/@score eq

                                  team[.!=$this]/@score])”/>

     

          select=“sum($matches/team[.=current()]/@score)”/>

     

          select=“sum($matches[team=current()]/team/@score) - $for”/>

     

          lost=“{$lost}” for=“{$for}” against=“{$against}”/>

  




Since we're talking about usage of

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. The stylesheet only contains one template, so 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

element for each team, with attributes indicating the number of matches won and lost, the goals scored, and so on.

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

 xmlns:xsl=“http://www.w3.org/1999/XSL/Transform”

 version=“2.0”

>



  


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

element created by the previous stylesheet.



  League Table

  

    League Table

    

    

      

        Team

        Played

        Won

        Lost

        Drawn

        For

        Against

      

      

      

        

          

          

          

          

          

          

          

        

      

      

    

   




Output

The output of the stylesheet is shown in
Figure 6-19
.

Avoiding Trivial Documents

There is a tendency to create temporary documents when they aren't needed. One often sees constructs like this:


    


This first calculates a number (the result of the
count()
function). It then converts this number to a string, wraps the string into a text node, creates a document node with the text node as its only child, and sets the value of the variable to be this document node. The chances are that the variable will then be used in an expression such as
$played>5
, in which a number is required: so the system has to atomize the document node, extract its string value by reading all its text node descendants, and then convert the resulting string to a number. You can save yourself two lines of code, and the system a lot of unnecessary work, by writing instead:


Here the value of the variable is a number. No need to create the temporary document, and no need to atomize it later to extract the value.

I call this kind of variable a trivial document. A trivial document behaves almost exactly like an
untypedAtomic
value. Here is a slightly more complicated example:


   

      

         

      

      0

   


In XSLT 2.0 it is almost always possible to avoid this kind of construct and the overheads that go with it. Write this instead as:

   select=“if (@width) then @width else 0”/>

Or more concisely:


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 document node is a very heavyweight object compared with an integer.

Other books

Three Good Things by Lois Peterson
Riley's Journey by Parker, P.L., Edwards, Sandra
Dreams of Us by St. James, Brooke
Power by Robert J. Crane
Point of Origin by Patricia Cornwell
Ship of Fools by Fintan O'Toole
Dreaming a Reality by Lisa M. Cronkhite
Only Yours by C. Shell
Las benévolas by Jonathan Littell