It is best to always avoid recursion, when possible.
In XSLT 2.0 one simply writes:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pNumRows" select="7"/>
<xsl:variable name="vDoc" select="/"/>
<xsl:template match="items">
<table>
<xsl:for-each select="1 to $pNumRows">
<tr><xsl:copy-of select="$vDoc/items/item[current()]"/></tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
and when this transformation is applied to the provided XML document:
<items>
<item />
<item />
<item />
</items>
the wanted correct result is produced:
<table>
<tr>
<item/>
</tr>
<tr>
<item/>
</tr>
<tr>
<item/>
</tr>
<tr/>
<tr/>
<tr/>
<tr/>
</table>
Very few people know that for a large number of cases one can avoid recursion in XSLT 1.0, too:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pNumRows" select="7"/>
<xsl:param name="vDoc" select="/"/>
<xsl:template match="items">
<table>
<xsl:for-each select=
"(document('')//node())[not(position() > $pNumRows)]">
<xsl:variable name="vPos" select="position()"/>
<tr><xsl:copy-of select="$vDoc/items/item[position()=$vPos]"/></tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
This is called the method of Piez and one can read about it here.
Remember: Recursion is much slower than simple iteration -- it also tends to crash with stack overflow if the list has considerable length (around 1000 or more) and special programmatic measures are not taken.