XML.com: XML From the Inside Out

XML.comWebServices.XML.comO'Reilly Networkoreilly.com
  Resources | Buyer's Guide | Newsletter | Safari Bookshelf
  Download Stylus Studio - The World's Best XML Editor
  Topics
Business
Databases
Graphics
Metadata
Mobile
Programming
Schemas
Semantic Web
Style
Web
Web Services

Product Showcase

BEA Learning Channel




   Essentials
Annotated XML
What is XML?
What is XSLT?
What is XSL-FO?
What is XLink?
What is XML Schema?
What is XQuery?
What is RDF?
What is RSS?
What are Topic Maps?
What are Web Services?
What are XForms?
XSLT Recipe of the Day

Manage Your Account
Forgot Your Password?

  Find
Search
Article Archive

Add XML to your Website

  Columns
<taglines/>
Dive into XML
Hacking Congress
Hacking the Library
Java Web Services Security
Jon Udell
Perl and XML
Practical XQuery
Python and XML
Rich Salz
Sacré SVG
Standards Lowdown
Transforming XML
XML Q&A
XML Tourist
XML-Deviant

  Guides
XML Resources
Buyer's Guide
Events Calendar
Standards List
Submissions List

  Toolbox

Syntax Checker




Developer Resources Partner



Atom Feed
RSS Feed



XML.com
supported by:

Mortgages Online
Affiliate Programs

   Print.Print
Email.Email article link

Getting Loopy
by Bob DuCharme | Pages: 1, 2

Arbitrary Repetition with Named Template Recursion

XSLT offers no specific element for repeating a group of instructions an arbitrary number of times or until a given condition is true. To understand why requires a little historical background.

Just as XML got its start as a simplified version of SGML, XSLT and XSL began as simplified, XML-based versions of a stylesheet language developed for SGML called DSSSL (Document Style Semantics and Specification Language -- rhymes with "whistle"). Like SGML, DSSSL is an ISO standard, but its actual use in the real world has been limited.

Why didn't it catch on? One problem was its descent from Scheme, a programming language in the LISP family. "LISP" stands for "LISt Processing" language, but some programmers say that it stands for "Lots of Irritating Silly Parentheses". LISP, Scheme, and DSSSL use parentheses heavily for syntax, and the parenthesized expressions get nested at such deep levels that expressions ending with "))))" are common in all three languages. Both data structures and control structures are parenthesized expressions in these languages, and this can make code difficult to read, especially without using a LISP-aware editor like Emacs.

XSL and XSLT remedy this by applying many of DSSSL's principles using XML. Expressions can be deeply nested, but instead of being nested within dozens of parentheses and indentation conventions, they're nested inside of regular XML elements that have names right in their tags describing their purpose -- for example, xsl:if, xsl:number, and xsl:comment. This makes XSLT stylesheets more readable than DSSSL stylesheets for many people.

XSLT did inherit a related aspect of its ancestors that some view as a blessing and others as a curse: there's no concept of a series of instructions being executed sequentially. (The technical term is that XSLT is a "side effect free" language.) A stylesheet gets applied to a source tree to create a result tree, and while the structure of the result tree is important, the order in which it's created is irrelevant. Since you can't have a series of instructions, you certainly don't have a way to repeat a series of instructions.

This doesn't prevent you from doing something a specific number of times or until a given condition is true in XSLT. You just have to do so using recursion, a fundamental LISP/Scheme/DSSSL technique Using recursive named templates, you can get the benefits of both "for" loops and "while" loops.

To demonstrate this, we'll use this simple input document:

<sample>the facile gates of hell too slightly barred</sample>

The following template rule shows how to repeat something a specific number of times. It has a named template called "hyphens" that can call itself as many times as necessary to add the specified number of hyphens to the result tree. To demonstrate the use of this named template, the "sample" template calls the "hyphens" template four times, asking it to add a different number of hyphens to the result tree each time. First, the "sample" template calls it with no value overriding the howMany parameter so that we can see the template's default behavior, and then it calls the template three more times with the values 3, 20, and 0 to override the parameter's default value of 1.

<xsl:template name="hyphens">
  <xsl:param name="howMany">1</xsl:param>
  <xsl:if test="$howMany &gt; 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>
  
<xsl:template match="sample">

  Print 1 hyphen: 
  <xsl:call-template name="hyphens"/>

  Print 3 hyphens: 
  <xsl:call-template name="hyphens">
    <xsl:with-param name="howMany" select="3"/>
  </xsl:call-template>

  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>

This creates the following result:

  Print 1 hyphen: 
  -

  Print 3 hyphens: 
  ---

  Print 20 hyphens: 
  --------------------

  Print 0 hyphens: 
  

The "hyphens" named template first declares the howMany parameter with an xsl:param element that sets this parameter's default value to 1. The rest of the template is a single xsl:if element whose contents get added to the result tree if howMany is set to a value greater than zero. If howMany passes this test, a single hyphen is added to the result tree and an xsl:call-template instruction calls the "hyphens" named template with a value of howMany that is one less than its current setting. If howMany is set to 1, xsl:call-template calls it with a value of 0, so no more hyphens will be added to the result tree. If howMany is set to 3, the named template will be called with a howMany value of 2 after adding the first of the 3 requested hyphens, and the process will be repeated until the template is called with a value of 0.

Recursion: Multiple calls to the same named template

    

Also in Transforming XML

Schematron 1.5: Looking Under the Hood

Converting XML to RDF

Amazon's Web Services and XSLT

An Interview with Michael Kay

Entity and Character References

This is what we mean by "recursion". When a template calls itself, it's a recursive call. You don't want it to call itself forever, so the recursive template needs a terminating condition -- in the case above, an xsl:if element that won't perform the recursive call unless howMany is greater than 0.

You must also be sure that the terminating condition will eventually occur. If the terminating condition was "$howMany = 0" and the recursive call subtracted 2 from the current value of howMany before calling the "hyphens" template again, calling it with a value of 3 would then mean making subsequent calls with howMany values of 1, -1, -3, -5, and so forth without ever hitting 0. The recursive calls would never stop. (The actual outcome of such an endless loop depends on the XSLT processor being used.)

Note The fancier the condition you use to control recursion, the more careful you must be to make absolutely sure that it will occur. Otherwise, the execution of your stylesheet could get stuck there.

The example above simulates the "for" loops used by many other programming languages because its recursive template performs an action a specific number of times, with the exact number passed to it at runtime. A "while" loop typically repeats an action or actions as long as a certain condition is true, and guess what -- the example above is really a "while" loop. The condition is the "$howMany &gt; 0" test in the named template's xsl:if start-tag. You can put any condition you want there, and the template will make recursive calls to itself as long as the condition is true.


Sponsored By:



Contact Us | Our Mission | Privacy Policy | Advertise With Us | Site Help | Submissions Guidelines
Copyright © 2004 O'Reilly Media, Inc.