问题
What happens when the control gets into xsl:variable? It should never reach <xsl:value-of select="$number * $recursive_result"/>
as it is calling the template again and again but it does. This made me question the overall control flow of XSLT. Please explain!
<xsl:template name="factorial">
<xsl:param name="number" select="1"/>
<xsl:choose>
<xsl:when test="$number < 1">
<xsl:value-of select="1"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="recursive_result">
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="$number - 1"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$number * $recursive_result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
回答1:
It does reach the <xsl:value-of select="$number * $recursive_result"/>
.
If you look at the variable declaration:
<xsl:variable name="recursive_result">
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="$number - 1"/>
</xsl:call-template>
</xsl:variable>
Every time the template, factorial, is called, the parameter being passed is reduced by 1(look at the following instruction):
<xsl:with-param name="number" select="$number - 1"/>
So, for example, if the template factorial
was called, at first, with value of 3
,
the <xsl:otherwise>
is reached and the variable in the factorial
template's <xsl:otherwise>
makes a call to factorial
template again but this time with value as 2. And similarly with 1, and then with 0.
When called with 0
as the value, the <xsl:when>
is entered and the output 1 is produced for that instance of recursive call. Then the control returns to where the template was called from(the previous instance of factorial
call). And hence, the <xsl:value-of>
being the next intruction is called.
This happens to all the previous instances of factorial
calls that called the template recursively(and hence processing <xsl:value-of>
of every <xsl:otherwise>
as being the next instruction after <xsl:variable>
).
By the way, you can save 1 redundant call to the template by changing your <xsl:when>
to:
<xsl:when test="$number <= 1">
<xsl:value-of select="1"/>
</xsl:when>
To have a look at the variables/values at every call use this XSLT, which has <xsl:message>
that prints specific values:
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/">
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="5"/>
<xsl:with-param name="iteration" select="1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="factorial">
<xsl:param name="number" select="1"/>
<xsl:param name="iteration" select="1"/>
<xsl:choose>
<xsl:when test="$number < 1">
<xsl:value-of select="1"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="recursive_result">
<xsl:call-template name="factorial">
<xsl:with-param name="number" select="$number - 1"/>
<xsl:with-param name="iteration" select="$iteration + 1"/>
</xsl:call-template>
</xsl:variable>
<xsl:message>iteration number = <xsl:value-of select="$iteration"/>; recursive_result = <xsl:value-of select="$recursive_result"/>; result = <xsl:value-of select="$number * $recursive_result"/> </xsl:message>
<xsl:value-of select="$number * $recursive_result"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:transform>
The number for which factorial is desired can by modified by modifying the following instruction in the first template:
<xsl:with-param name="number" select="5"/>
Here is the screenshot of what you can expect(using command line interface, depending on the processor you are using):
来源:https://stackoverflow.com/questions/27634960/i-saw-this-recursion-template-in-xslt-and-cannot-understand-what-is-happening