I have been messing around with for loops, trying to get a completely generic solution, and thought I'd share my results. It's an intellectual exercise, really; it's probably much more efficient to just write specific recursive templates for your use cases rather than calling document() all the time.
The idea is based on http://www.dpawson.co.uk/xsl/sect2/generic.html#d5411e177, which nearly works.
However I can't load the current style sheet using document(''), as it throws an exception: "This operation is not supported for a relative URI".
What you CAN do, is a bit hacky - you can hardcode the physical path to your template in.
Here is the code for a generic for loop:
<xsl:variable name="self" select="'E:\PathToUmbraco\xslt\myTemplate.xslt'"/>
<xsl:template name="for">
<xsl:param name="from" select="1" />
<xsl:param name="to"/>
<xsl:param name="step" select="1" />
<xsl:param name="i" select="$from" />
<xsl:param name="context" />
<xsl:param name="function" />
<xsl:if test="$i <= $to">
<xsl:apply-templates select="document($self)/xsl:stylesheet/xsl:template[@name = $function]">
<xsl:with-param name="i" select="$i" />
<xsl:with-param name="context" select="$context" />
</xsl:apply-templates>
<xsl:call-template name="for">
<xsl:with-param name="from" select="$from"/>
<xsl:with-param name="to" select="$to"/>
<xsl:with-param name="step" select="$step"/>
<xsl:with-param name="i" select="$i + $step"/>
<xsl:with-param name="context" select="$context"/>
<xsl:with-param name="function" select="$function"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
It is generic because you use the $function parameter to pass in the name of the template you want to call. You must also pass the node for your required context in $context.
You must define your "callback" templates in a specific way in order for them to be used - here is one to print the ID of nodes at the current position in the $context:
<xsl:template name="contextCallback" match="xsl:template[@name = 'contextCallback']">
<xsl:param name="i"/>
<xsl:param name="context"/>
<xsl:value-of select="$context[position() = $i]/@id"/><br/>
</xsl:template>
And here is how you call the for loop, with most parameters left as defaults:
Pseduocode equivalent: for(var i = 1; i <= 5; i++) { contextCallback(i, blogNode); }
<xsl:call-template name="for">
<xsl:with-param name="to" select="5"/>
<xsl:with-param name="context" select="umbraco.library:GetXmlAll()//Blog"/>
<xsl:with-param name="function" select="'contextCallback'"/>
</xsl:call-template>
This is a companion discussion topic for the original entry at https://our.umbraco.com/forum/17690-generic-templates-call-template-by-dynamic-name