Rendering a node sequence as M x N table

You must ensure that nesting is never broken. Things you want nested in the output must be nested in the XSLT.

<xsl:variable name="perRow" select="3" />

<xsl:template match="recordset">
  <table>
    <xsl:apply-templates 
      mode   = "tr"
      select = "record[position() mod $perRow = 1]"
    />
  </table>
</xsl:template>

<xsl:template match="record" mode="tr">
  <tr>
    <xsl:variable name="td" select="
      . | following-sibling::record[position() &lt; $perRow]
    " />
    <xsl:apply-templates mode="td" select="$td" />
    <!-- fill up the last row -->
    <xsl:if test="count($td) &lt; $perRow">
      <xsl:call-template name="filler">
        <xsl:with-param name="rest" select="$perRow - count($td)" />
      </xsl:call-template>
    </xsl:if>
  </tr>
</xsl:template>

<xsl:template match="record" mode="td">
  <td>
    <xsl:value-of select="." />
  </td>
</xsl:template>

<xsl:template name="filler">
  <xsl:param name="rest" select="0" />
  <xsl:if test="$rest">
    <td />
    <xsl:call-template name="filler">
      <xsl:with-param name="rest" select="$rest - 1" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

Using xslt 2.0

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:param name="rows">3</xsl:param>
    <xsl:template match="recordset">
        <table>
            <xsl:for-each-group select="record" group-by="count(preceding-sibling::*) mod $rows ">
                <xsl:value-of select="current-grouping-key()"/>
                <tr>
                    <xsl:for-each select="current-group()">
                        <td>
                            <xsl:apply-templates/>
                        </td>
                    </xsl:for-each>
                </tr>
            </xsl:for-each-group>
        </table>
    </xsl:template>
</xsl:stylesheet>