In this sixth of nine pieces on the subject of XSLT, we'll take the various functions and expressions you've learned about in previous tips and describe how to embed them inside sequences of processing instructions. Usually, this occurs within the scope of some <xsl:call-template> markup element or another, since that element fulfills the same kind of role in XSLT that function or subroutine calls serve in many programming languages. In that particular context, in fact, you'll find most of the iterative and recursive structures in XSLT put to work—as illustrated in the labeled paragraphs that follow next.
Navigating to and processing specific document nodes
To use <xsl:call-template> to process some node other than the current document node, the most expeditious technique is to nest an <xsl:call-template> element inside an <xsl:for-each> element, but you can also provide a target template with a unique node name, and use the <xsl:apply-template> element to apply to some specific node instead. The "for-each" construct, however, is purely iterative and makes more sense in circumstances where all nodes in a document or results tree need to be processed anyway. You'll find examples of this approach completely spelled out in Michael Kay's XSLT Programmers Reference (Wrox, 2001, pp. 169 and 170). He also explains a neat technique on page 169 for calling <xsl:call-template> inside an <xsl:variable> element, where a simple conversion of the results tree to a string acts just as if the <xsl:call-template> element is returning a result from its invocation.
The structure for this sort of process may be illustrated as follows, where a template for enclosing string values within square brackets is called inside a variable element:
<!-- start with template definition, proceed to variable element --> <xsl:template name="bracketit"> <xsl:param name="string" /> <xsl:value-of select="concat("'[', $string, ']')"/> </xsl:template> <xsl:variable name="cite-in-brackets"> <xsl:call-template name="bracketit"/> <xsl:with-param name="string" select="@cite"/> </xsl:call-template> </xsl:variable>
If the value of the cite attribute is Horn79, the resulting value of the variable cite-in-brackets will be [Horn79].
Using Recursion to Process Item Lists
XSLT lacks updatable variables like the counters used in conventional programming languages to progress through specific counts of activities, nor does it support conditional looping constructs such as while, for, or until either. But XSLT does support recursion, which provides a handy way to achieve the same sorts of purposes. The approach to this process involves setting up a recursive function call where the function is applied to the first node in a list or the first non-empty character sequence in a string, and the function is also applied to the remainder of the node list or string, with the first element or character sequence removed from its contents. For each type of data, operations proceed until the list or string is empty—namely, when no more nodes or non-empty strings occur in the remainder portion. In his very nice Sybex book titled Mastering XSLT, Chuck White refers to this approach as "…repeating a result fragment for every instance of a named expression" (2002, pg 266; he also has great markup examples in chapter 9, where recursion is covered on pp. 268-269, as Michael Kay does on pp. 168-175 of his already-cited book).
Managing Conditional Processing
The <xsl:choose> and <xsl:when> elements permit conditional branching where multiple alternatives might be needed; an <xsl:otherwise> element even permits explicit handling of item that fail all specific tests defined. The basic syntax provides a construct that looks every much like a typical if-then-else statements with arbitrary nesting. White spells out the basic syntax stripped of actual values or checks for such statements as follows on p. 291 of Mastering XSLT:
<xsl:choose> <xsl:when test="expression"> <!-- processing statements --> </xsl:when> <xsl:otherwise> <!-- processing statements --> </xsl:otherwise> </xsl:choose>
Given the various techniques that XSLT supports so readily, it's reasonably easy to build your own document processing examples around navigation, recursion, and conditional testing techniques. You can also revisit the XSLT tutorial at zvon.org for more illustrations and examples as well, or check out Sal Mangano's XSLT Cookbook (O'Reilly, 2003) for more elaborate and lengthy examples that you can import and easily adapt for your own uses.
About the author
Ed Tittel is a full-time writer and trainer whose interests include XML and development topics, along with IT Certification and information security topics. E-mail Ed with comments, questions, or suggested topics or tools for review.