XSL is a very powerful tool. There really isn’t anything it can’t do when it comes to transforming XML documents. However, sometimes it’s necessary to operate on nodes in a way that isn’t possible without having variables to guide us. Here is a reminder (to myself) on XSL recursion.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes"/> <!-- root template --> <xsl:template match="/root"> <ul> <xsl:call-template name="pagebreak"> <xsl:with-param name="childpos">0</xsl:with-param> <xsl:with-param name="curpos">0</xsl:with-param> <xsl:with-param name="maxpos"> <xsl:value-of select='count(*)'/> </xsl:with-param> </xsl:call-template> </ul> </xsl:template> <xsl:template name="pagebreak" > <xsl:param name="childpos"/> <xsl:param name="curpos"/> <xsl:param name="maxpos"/> <xsl:variable name="nodetitle" select='name(*[$childpos + 1])'/> <!-- Apply template based on node title --> <!-- OPERATE ON: /root/body --> <xsl:if test="$nodetitle = 'body' "> <!-- pass in the current "body" node of the / --> <xsl:apply-templates select='child::*[$childpos + 1]'> <xsl:with-param name="lipos"> <xsl:choose> <xsl:when test="$curpos=0">1</xsl:when> <xsl:when test="$curpos=1">2</xsl:when> <xsl:when test="$curpos=2">3</xsl:when> </xsl:choose> </xsl:with-param> </xsl:apply-templates> <xsl:if test="$curpos = 2 and name(*[$childpos + 2]) != 'text_lines'"> <!-- If we're at the third position of body, and the next node isn't a text-line, print our ULs. --> <!-- TEMPLATE CONTENTS OMITTED --> </xsl:if> </xsl:if> <!-- OPERATE ON: /root/text_lines --> <xsl:if test="$nodetitle = 'text_lines' "> <xsl:text disable-output-escaping="yes"></ul></xsl:text> <div class='section_title'> <p><xsl:value-of select='child::*[$childpos + 1]'/></p> </div> <xsl:text disable-output-escaping="yes"><ul></xsl:text> </xsl:if> <!-- RECURSIVE(Set variables to operate each time through) --> <xsl:if test="$childpos < ($maxpos - 1)"> <xsl:call-template name="pagebreak"> <!-- Static Variable: Curront position within array of child nodes --> <xsl:with-param name="childpos"> <xsl:value-of select='$childpos + 1'/> </xsl:with-param> <xsl:with-param name="curpos"> <xsl:choose> <xsl:when test="$curpos=2 or $nodetitle = 'text_lines'">0</xsl:when> <xsl:when test="$curpos != 2"> <xsl:value-of select="$curpos + 1"/> </xsl:when> </xsl:choose> </xsl:with-param> <!-- Static Variable: Max length of array of child nodes. --> <xsl:with-param name="maxpos"> <xsl:value-of select='$maxpos + 0'/> </xsl:with-param> </xsl:call-template> </xsl:if> </xsl:template> <!-- mybody template --> <xsl:template name="mybody" match='body'> <xsl:param name="lipos"/> <xsl:variable name="grid_counter" select="$lipos mod 3"/> <li class="grid_column_{$grid_counter}"> <!-- TEMPLATE CONTENTS OMITTED --> </li> </xsl:template> <!-- OTHER TEMPLATES OMITTED --> </xsl:stylesheet>

