Generic templates / call template by dynamic name

 

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 &lt;= $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