Recursive design Implementing a String Replace Function

page 70 In the recursive approach, the function calls itself whenever theres at least one more occurrence of the substring. Each time the function calls itself, the originalString parameter is a little smaller, until eventually weve processed the complete string. Heres the complete template: xsl:template name=replace-substring xsl:param name=original xsl:param name=substring xsl:param name=replacement select= xsl:variable name=first xsl:choose xsl:when test=containsoriginal, substring xsl:value-of select=substring-beforeoriginal, substring xsl:when xsl:otherwise xsl:value-of select=original xsl:otherwise xsl:choose xsl:variable xsl:variable name=middle xsl:choose xsl:when test=containsoriginal, substring xsl:value-of select=replacement xsl:when xsl:otherwise xsl:textxsl:text xsl:otherwise xsl:choose xsl:variable xsl:variable name=last xsl:choose xsl:when test=containsoriginal, substring xsl:choose xsl:when test=containssubstring-afteroriginal, substring, substring xsl:call-template name=replace-substring xsl:with-param name=original xsl:value-of select=substring-afteroriginal, substring xsl:with-param xsl:with-param name=substring xsl:value-of select=substring xsl:with-param xsl:with-param name=replacement xsl:value-of select=replacement xsl:with-param xsl:call-template xsl:when xsl:otherwise xsl:value-of select=substring-afteroriginal, substring xsl:otherwise xsl:choose xsl:when xsl:otherwise xsl:textxsl:text xsl:otherwise xsl:choose xsl:variable xsl:value-of select=concatfirst, middle, last xsl:template This style of programming takes some getting used to, but whatever you want to do can usually be done. Our example here is a good illustration of the techniques weve discussed in this chapter, including branching statements, variables, invoking templates by name, and passing parameters. page 71

4.7 A Stylesheet That Emulates a for Loop

We stressed earlier that the xsl:for-each element is not a for loop; its merely an iterator across a group of nodes. However, if you simply must implement a for loop, theres a way to do it. Get ready to use recursion, though.

4.7.1 Template Design

Our design here is to create a named template that will take some arguments, then act as a for loop processor. If you think about a traditional for loop, it has several properties: • One or more initialization statements. These statements are processed before the for loop begins. Typically the initialization statements refer to an index variable that is used to determine whether the loop should continue. • An increment statement. This statement specifies how the index variable should be updated after each pass through the loop. • A boolean expression. If the expression is true , the loop continues; if it is ever false , the loop exits. Lets take a sample from the world of Java and C++: for int i=0; ilength; i++ In this scintillating example, the initialization statement is i=0 , the index variable the variable whose value determines whether were done or not is i , the boolean expression we use to test whether the loop should continue is ilength , and the increment statement is i++ . For our purposes here, were going to make several simplifying assumptions. Feel free, dear reader, to make the example as complicated as you wish. Here are the shortcuts well take: • Rather than use an initialization statement, well require the caller to set the value of the local variable i when it invokes our for loop processor. • Rather than specify an increment statement such as i++ , well require the caller to set the value of the local variable increment . The default value for this variable is 1 ; it can be any negative or positive integer, however. The value of this variable will be added to the current value of i after each iteration through our loop. • Rather than allow any conceivable boolean expression, well require the caller to pass in two parameters; operator and testValue . The allowable values for the operator variable are = , coded as lt; , coded as gt; , coded as lt;gt; , = coded as lt;= , and = coded as gt;= . Were doing things this way because there isnt a way to ask the XSLT processor to evaluate a literal such as ilength as if it were part of the stylesheet.

4.7.2 Implementation

Lets look at the parameters for our for loop template: xsl:param name=i select=1 xsl:param name=increment select=1 xsl:param name=operator select== xsl:param name=testValue select=1 page 72 Our for template uses four parameters: the index variable, the increment, the comparison operator, and the test value. To emulate this C++ statement: for int i=1; i=10; i++ Youd use this markup: xsl:call-template name=for-loop xsl:with-param name=i select=1 xsl:with-param name=increment select=1 xsl:with-param name=operator select=lt;= xsl:with-param name=testValue select=10 xsl:call-template To demonstrate our stylesheet, our first version simply prints out the value of our index variable each time through the loop: Transforming... Iteration 1: i=1 Iteration 2: i=2 Iteration 3: i=3 Iteration 4: i=4 Iteration 5: i=5 Iteration 6: i=6 Iteration 7: i=7 Iteration 8: i=8 Iteration 9: i=9 Iteration 10: i=10 transform took 260 milliseconds XSLProcessor: done Heres the markup youd use to emulate the Java statement for int i=10; i0; i-=2 : xsl:call-template name=for-loop xsl:with-param name=i select=10 xsl:with-param name=increment select=-2 xsl:with-param name=operator select=gt; xsl:with-param name=testValue select=0 xsl:call-template In this case, the values of i decrease from 10 to : Transforming... Iteration 1: i=10 Iteration 2: i=8 Iteration 3: i=6 Iteration 4: i=4 Iteration 5: i=2 transform took 110 milliseconds XSLProcessor: done

4.7.3 The Complete Example

Heres our complete stylesheet: ?xml version=1.0? xsl:stylesheet xmlns:xsl=http:www.w3.org1999XSLTransform version=1.0 xsl:output method=text xsl:variable name=newline xsl:text xsl:text xsl:variable xsl:template name=for-loop xsl:param name=i select=1 xsl:param name=increment select=1 xsl:param name=operator select== xsl:param name=testValue select=1 xsl:param name=iteration select=1