4.8.3. Complications
There are a couple of complications in producing our stylesheet-generating stylesheet. First, we need to have some way to distinguish among the XSLT elements in the stylesheet being processed and the XSLT elements we're generating. Here's one way to do it:
<xsl:element name="xsl:template"
namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name">for-loop</xsl:attribute>
<xsl:element name="xsl:param"
namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name">i</xsl:attribute>
<xsl:attribute name="select">
<xsl:value-of select="@index-variable"/>
</xsl:attribute>
</xsl:element>
<xsl:element name="xsl:param" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name">increment</xsl:attribute>
<xsl:attribute name="select">
<xsl:value-of select="@increment"/>
</xsl:attribute>
</xsl:element>
<xsl:element name="xsl:param" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name">operator</xsl:attribute>
<xsl:attribute name="select">
<xsl:text>'</xsl:text>
<xsl:value-of select="@operator"/>
<xsl:text>'</xsl:text>
</xsl:attribute>
</xsl:element>
<xsl:element name="xsl:param" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name">testValue</xsl:attribute>
<xsl:attribute name="select">
<xsl:value-of select="@test-value"/>
</xsl:attribute>
</xsl:element>
<xsl:element name="xsl:param" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name">iteration</xsl:attribute>
<xsl:attribute name="select">1</xsl:attribute>
</xsl:element>
...
This lengthy listing generates this simple XML fragment:
<ns1:template name="for-loop">
<ns1:param name="i" select="0"/>
<ns1:param name="increment" select="1"/>
<ns1:param name="operator" select="'<='"/>
<ns1:param name="testValue" select="10"/>
<ns1:param name="iteration" select="1"/>
...
This approach works, but we're doing an awful lot of work to create some fairly simple elements. For all the XSLT elements we're generating with <xsl:element> elements, we have to declare the namespace for each one. The obvious way of handling this would be to generate a namespace declaration on the <xsl:stylesheet> element:
<xsl:attribute name="xmlns:xsl">
http://www.w3.org/1999/XSL/Transform
</xsl:attribute>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xslout="can be anything, doesn't matter">
<xsl:output method="xml" indent="yes"/>
<xsl:namespace-alias stylesheet-prefix="xslout" result-prefix="xsl"/>
<xsl:template match="*|@*|text()|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates
select="*|@*|text()|comment()|processing-instruction()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="for-loop">
<xslout:call-template name="for-loop">
<xslout:with-param name="i" select="{@index-variable}"/>
<xslout:with-param name="increment" select="{@increment}"/>
<xslout:with-param name="operator">
<xsl:attribute name="select">
<xsl:text>'</xsl:text>
<xsl:value-of select="@operator"/>
<xsl:text>'</xsl:text>
</xsl:attribute>
</xslout:with-param>
<xslout:with-param name="testValue" select="{@test-value}"/>
</xslout:call-template>
</xsl:template>
<xsl:template match="for-loop" mode="generate-template">
<xslout:variable name="newline">
<xslout:text>
</xslout:text>
</xslout:variable>
<xslout:template name="for-loop">
<xslout:param name="i" select="@index-variable"/>
<xslout:param name="increment" select="@increment"/>
<xslout:param name="operator" select="@operator"/>
<xslout:param name="testValue" select="@test-value"/>
<xslout:param name="iteration" select="1"/>
<xslout:variable name="testPassed">
<xslout:choose>
<xslout:when test="starts-with($operator, '!=')">
<xslout:if test="$i != $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '<=')">
<xslout:if test="$i <= $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '>=')">
<xslout:if test="$i >= $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '=')">
<xslout:if test="$i = $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '<')">
<xslout:if test="$i < $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '>')">
<xslout:if test="$i > $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:otherwise>
<xslout:message terminate="yes">
<xslout:text>Sorry, the for-loop emulator only </xslout:text>
<xslout:text>handles six operators </xslout:text>
<xslout:value-of select="$newline"/>
<xslout:text>(< | > | = | <= | >= | !=). </xslout:text>
<xslout:text>The value </xslout:text>
<xslout:value-of select="$operator"/>
<xslout:text> is not allowed.</xslout:text>
<xslout:value-of select="$newline"/>
</xslout:message>
</xslout:otherwise>
</xslout:choose>
</xslout:variable>
<xslout:if test="$testPassed='true'">
<xslout:comment>From your stylesheet:</xslout:comment>
<xsl:apply-templates select="*"/>
<xslout:comment>End of text from your stylesheet</xslout:comment>
<xslout:call-template name="for-loop">
<xslout:with-param name="i" select="$i + $increment"/>
<xslout:with-param name="increment" select="$increment"/>
<xslout:with-param name="operator" select="$operator"/>
<xslout:with-param name="testValue" select="$testValue"/>
<xslout:with-param name="iteration" select="$iteration + 1"/>
</xslout:call-template>
</xslout:if>
</xslout:template>
</xsl:template>
<xsl:template match="/">
<xslout:stylesheet version="1.0">
<xsl:apply-templates select="//for-loop" mode="generate-template"/>
<xslout:template match="/">
<xsl:apply-templates select="*"/>
</xslout:template>
</xslout:stylesheet>
</xsl:template>
</xsl:stylesheet>
Throughout our stylesheet, we used the usual xsl namespace for the stylesheet elements we use, and the xslout namespace for the stylesheet elements we generate. Notice that though we define the xslout namespace on the <xsl:namespace-alias> element, we still have to declare it on the <xsl:stylesheet> element. Also note that the value we define for the xslout namespace doesn't matter; the value referred to by the <xsl:namespace-alias> is used instead.
Here is the stylesheet generated by our stylesheet-generating stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xslout:stylesheet xmlns:xslout="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xslout:variable name="newline">
<xslout:text/>
</xslout:variable>
<xslout:template name="for-loop">
<xslout:param select="@index-variable" name="i"/>
<xslout:param select="@increment" name="increment"/>
<xslout:param select="@operator" name="operator"/>
<xslout:param select="@test-value" name="testValue"/>
<xslout:param select="1" name="iteration"/>
<xslout:variable name="testPassed">
<xslout:choose>
<xslout:when test="starts-with($operator, '!=')">
<xslout:if test="$i != $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '<=')">
<xslout:if test="$i <= $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '>=')">
<xslout:if test="$i >= $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '=')">
<xslout:if test="$i = $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '<')">
<xslout:if test="$i < $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:when test="starts-with($operator, '>')">
<xslout:if test="$i > $testValue">
<xslout:text>true</xslout:text>
</xslout:if>
</xslout:when>
<xslout:otherwise>
<xslout:message terminate="yes">
<xslout:text>Sorry, the for-loop emulator only </xslout:text>
<xslout:text>handles six operators </xslout:text>
<xslout:value-of select="$newline"/>
<xslout:text>(< | > | = | <= | >= | !=). </xslout:text>
<xslout:text>The value </xslout:text>
<xslout:value-of select="$operator"/>
<xslout:text> is not allowed.</xslout:text>
<xslout:value-of select="$newline"/>
</xslout:message>
</xslout:otherwise>
</xslout:choose>
</xslout:variable>
<xslout:if test="$testPassed='true'">
<xslout:comment>From your stylesheet:</xslout:comment>
<tr xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<td align="center">
<xsl:value-of select="$iteration"/>
</td>
<td align="center">
<xsl:value-of select="$i"/>
</td>
</tr>
<xslout:comment>End of text from your stylesheet</xslout:comment>
<xslout:call-template name="for-loop">
<xslout:with-param select="$i + $increment" name="i"/>
<xslout:with-param select="$increment" name="increment"/>
<xslout:with-param select="$operator" name="operator"/>
<xslout:with-param select="$testValue" name="testValue"/>
<xslout:with-param select="$iteration + 1" name="iteration"/>
</xslout:call-template>
</xslout:if>
</xslout:template>
<xslout:template match="/">
<html xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<head>
<title>Text generated by our for loop processor</title>
</head>
<body>
<h1>Text generated by our for loop processor</h1>
<table border="1">
<tr>
<th>Iteration #</th>
<th>Value of <i>i</i>
</th>
</tr>
<xslout:call-template name="for-loop">
<xslout:with-param select="0" name="i"/>
<xslout:with-param select="1" name="increment"/>
<xslout:with-param name="operator" select="'<='"/>
<xslout:with-param select="10" name="testValue"/>
</xslout:call-template>
</table>
</body>
</html>
</xslout:template>
</xslout:stylesheet>