FelHa
FelHa

Reputation: 1103

XSLT call-template Recursion

I am wondering how the following templates work in detail. Both return the same results. Both are recursive and both use substring() to split the string given by the calling template, but if I debug both templates, rec1 returns its string at once, while rec2 returns a value each time, it calls itself.

XML:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <foo style="äöb"></foo>
</root>

XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="#all">

<xsl:template match="foo">
    <root>
        <xsl:call-template name="rec1">
            <xsl:with-param name="style" select="@style"/>
        </xsl:call-template>
    </root>
</xsl:template>


<xsl:template name="rec1">
    <xsl:param name="style"/>
    <xsl:variable name="firstChar" select="substring($style,1,1)"/>
    <xsl:variable name="charMap">
        <xsl:choose>
            <xsl:when test="$firstChar='ä'">ae</xsl:when>
            <xsl:when test="$firstChar='ö'">oe</xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$firstChar"/>
            </xsl:otherwise>
        </xsl:choose>
        <xsl:if test="string-length($style) &gt; 1">
            <xsl:call-template name="rec1">
                <xsl:with-param name="style" select="substring($style,2)"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:variable>
    <xsl:value-of select="$charMap"/>
</xsl:template>

<xsl:template name="rec2">
    <xsl:param name="style"/>
    <xsl:variable name="firstChar" select="substring($style,1,1)"/>
    <xsl:choose>
        <xsl:when test="$firstChar='ä'">ae</xsl:when>
        <xsl:when test="$firstChar='ö'">oe</xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$firstChar"/>
        </xsl:otherwise>
    </xsl:choose>
    <xsl:if test="string-length($style) &gt; 1">
        <xsl:call-template name="rec2">
            <xsl:with-param name="style" select="substring($style,2)"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Upvotes: 2

Views: 1008

Answers (1)

lampyridae
lampyridae

Reputation: 1016

rec1 Template

rec1 recursively builds the value of the variable charMap and then outputs it. The only call to <xsl:value-of select="$charMap"/> that results in an output is the one coming from the root call of rec1, because all subsequent recursive calls happen inside the variable definition of charMap (<xsl:variable name=charMap>).

Actually, <xsl:variable name="charMap"> marks the beginning of the definition of the $charMap variable but for $charMap to be actually defined we need to reach </xsl:variable>… although before we reach it we enter a recursive call of rec1! All subsequent recursive calls will find themselves waiting for the next recursive call to finish before they can define their own shorter $charMap until we reach the last call.

In other words, for rec1 called with 'Sävsjö':

  • charMap0 = S + charMap1
  • charMap1 = ae + charMap2
  • charMap2 = v + charMap3
  • charMap3 = s + charMap4
  • charMap4 = j + charMap5
  • charMap5 = oe

As long as you don't know the value of charMap5, you can't have charMap0.

rec2 Template

rec2 has no charMap variable since each call outputs a partial result before doing the recursive call to rec2. In the case of rec2, no xsl:value-of happens inside a xsl:variable hence each xsl:value-of produces a direct output.

Upvotes: 2

Related Questions