Recursive Versus Iterative Style Sheets






Recursive Versus Iterative Style Sheets

One of the things about XSLT is that although the capability exists for iteration (looping), it is strongly frowned upon by the development community. Instead, recursive templates are considered the acceptable standard. Although this philosophy requires some changes in the way developers think, it also means that recursive style sheets are often far more compact and not nested nearly as deep as their iterative counterparts. At the very least, recursive style sheets are always far more structured, which can be a major advantage in larger style sheets.

Let's say that our goal is to create an XSLT table and the source XML document shown in Listing 10-2. As a starting point, there are two distinct courses of action: an iterative style sheet (see Listing 10-3) and a recursive style sheet (see Listing 10-4). Each of these two approaches to coding style sheets has its own strengths and weaknesses. For example, the iterative style sheet is about the same length, but it is also nested much deeper than the recursive style sheet.

-2. Source XML Document

<?xml version="1.0" encoding="UTF-8"?>
<library>
      <book publisher="Del Rey">
            <series/>
            <title>Way Station</title>
            <author>Clifford D. Simak</author>
      </book>
      <book publisher="Del Rey">
            <series>The Lord of the Rings</series>
            <title>The Fellowship of the Ring</title>
            <author>J.R.R. Tolkien</author>
      </book>
      <book publisher="Del Rey">
            <series>The Lord of the Rings</series>
            <title>The Two Towers</title>
            <author>J.R.R. Tolkien</author>
      </book>
      <book publisher="Del Rey">
            <series>The Lord of the Rings</series>
            <title>The Return of the King</title>
            <author>J.R.R. Tolkien</author>
      </book>
      <book publisher="Ace">
            <series>Lord Darcy</series>
            <title>Too Many Magicians</title>
            <author>Randall Garrett</author>
      </book>
      <book publisher="Ace">
            <series>Lord Darcy</series>
            <title>Murder and Magic</title>
            <author>Randall Garrett</author>
      </book>
      <book publisher="Ace">
            <series>Lord Darcy</series>
            <title>The Napoli Express</title>
            <author>Randall Garrett</author>
      </book>
      <book publisher="Ace">
            <series>Lord Darcy</series>
            <title>Lord Darcy Investigates</title>
            <author>Randall Garrett</author>
      </book>
</library>

-3. Iterative Style Sheet

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="UTF-8"/>

      <xsl:template match="/">

            <xsl:element name="table">

                  <xsl:for-each select="//book">
                        <xsl:element name="tr">

                              <xsl:for-each select="child::*">
                                    <xsl:element name="td">
                                          <xsl:value-of select="."/>
                                    </xsl:element>
                              </xsl:for-each>

                        </xsl:element>
                  </xsl:for-each>
            </xsl:element>

       </xsl:template>

</xsl:stylesheet>

-4. Recursive Style Sheet

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="UTF-8"/>

      <xsl:template match="/">

            <xsl:element name="table">
                  <xsl:apply-templates select="//book"/>
            </xsl:element>

      </xsl:template>

      <xsl:template match="*">

             <xsl:if test="count(ancestor::*) = 1">
                   <xsl:element name="tr">
                         <xsl:apply-templates select="child::*"/>
                   </xsl:element>
             </xsl:if>
             <xsl:if test="count(ancestor::*) != 1">
                   <xsl:element name="td">
                        <xsl:value-of select="."/>
                  </xsl:element>
            </xsl:if>

      </xsl:template>

</xsl:stylesheet>

The decision to use an iterative design or a recursive design is more a matter of personal taste and comfort than any rule imposed from on high. For example, many developers new to XSLT start by writing iterative style sheets and move to recursive methods only when they become more confident in their abilities. But in the end, the result of the two style sheets is the same as shown in Listing 10-5.

Listing 10-5. Result from Applying Either Style Sheet to the XML in Listing 10-2

<?xml version="1.0" encoding="UTF-8"?>
<library>
      <book publisher="Del Rey">
        <series/>
        <title>Way Station</title>
        <author>Clifford D. Simak</author>
      </book>
      <book publisher="Del Rey">
        <series>The Lord of the Rings</series>
        <title>The Fellowship of the Ring</title>
        <author>J.R.R. Tolkien</author>
      </book>
      <book publisher="Del Rey">
        <series>The Lord of the Rings</series>
        <title>The Two Towers</title>
        <author>J.R.R. Tolkien</author>
      </book>
      <book publisher="Del Rey">
        <series>The Lord of the Rings</series>
        <title>The Return of the King</title>
        <author>J.R.R. Tolkien</author>
      </book>
      <book publisher="Ace">
        <series>Lord Darcy</series>
        <title>Too Many Magicians</title>
        <author>Randall Garrett</author>
      </book>
      <book publisher="Ace">
        <series>Lord Darcy</series>
        <title>Murder and Magic</title>
        <author>Randall Garrett</author>
      </book>
      <book publisher="Ace">
        <series>Lord Darcy</series>
        <title>The Napoli Express</title>
        <author>Randall Garrett</author>
      </book>
      <book publisher="Ace">
        <series>Lord Darcy</series>
        <title>Lord Darcy Investigates</title>
        <author>Randall Garrett</author>
      </book>
</library>

Scope

If you're in a cubical right now, take a moment and look around; you're the absolute ruler of all that you survey. The desk and its contents all fall under your benevolent influence, as do the coffee cup and its contents. However, all that is beyond the imaginary line that separates your cubical from the corridor is beyond the scope of your influence and belongs to another. This simplistic description of office life is essentially the same as how the concept of scope works in XSLT. In XSLT, scope is applied to both the context node, the current position in the XML document, and the variables.

It is best to think of scope along the same lines as local and global variables in other programming languages. For example, if a variable is defined within an if statement, it is accessible only inside that if statement. Or if a variable is defined within a function (template in XSLT), it can be used only within that function, not in any subsequent function, unless it is passed as a parameter. Variables defined on the root level are considered global to the entire XSLT document. Also, while we're on the subject of variables, I should describe the toughest issue that new developers have with learning XSLT.

Nonvariable Variables

As with other programming languages, XSLT provides the capability to create variables, which can be a major stumbling block to newcomers. You see, because of the functional nature of XSLT, variables aren't variable, and after they're created, they cannot be assigned a new value within the same scope. This might seem at first to be a problem, but it was intentional because XSLT is not a procedural language, like JavaScript. XSLT variables function more like variables in mathematical functions; you can create them, you can use them, but you can never change them.

This, probably more than any other aspect of XSLT, has caused more developers to run screaming into the night, although I'm not sure, having never conducted any research into the subject. After all, how long can you develop without Jonesing for a fixer, make that needing a way to alter a variable or something along those lines?

There is, however, a way around this issue; remember what I said about scope? That scope can be both local and global? Imagine, if you will, a recursive template. Yes, the headaches are starting already, but bear with me on this. There is absolutely no reason why a template cannot call itself. Okay, that's really useful information. A template can get around this issue, and it would be even more useful if I were to explain what a template is.

In XSLT, a template is the equivalent to a function in another language, such as PHP or JavaScript. In fact, it isn't all that unusual for a template to have a name and be invoked using that name, just like a function. In addition, templates can accept parameters, just as functions do in other languages. However, there is a major difference between XSLT functions and, say, JavaScript functions.

In JavaScript, functions are required to have names, whereas, in XSLT, templates aren't required to have names. This raises the question, if a template doesn't have a name, then how do you call it? The simple answer is that you don't call it; only named templates can be called. Instead, you apply it. The XSLT apply-templates element has an attribute named select, which uses XPath to specify which nodes in the source document the template is to be applied to.



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows