I have a problem where a table has 100s of rows. It causes an issue and needs to be split into several smaller tables with fewer rows each.
My html is valid xml as
This is the classical XSLT 1.0 solution for such kind of problems:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="prowLimit" select="12"/>
<xsl:variable name="vTable" select="/*"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="tr">
<xsl:if test="position() mod $prowLimit = 1">
<table>
<xsl:copy-of select="$vTable/@*"/>
<xsl:copy-of select=
". | following-sibling::tr[not(position() > $prowLimit -1)]"/>
</table>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Here's an XSLT2 solution using for-each-group. To change the number of items per table change the divisor in the group-adjacent attribute. Tested in Oxygen/XML with Saxon 9.2.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="xs xd"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="table">
<xsl:variable name="tblNode" select="."/>
<xsl:variable name="header" select="tr[1]"/>
<xsl:for-each-group select="tr[position() > 1]" group-adjacent="(position()-1) idiv 3">
<xsl:element name="table">
<xsl:copy-of select="$tblNode/@*"/>
<xsl:copy-of select="$header"/>
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Explanation:
Note that if you had nested tables inside the rows you'd have to modify this slightly to avoid having the "table" template match the inner tables.
This XSLT 1.0 stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="pMaxRow" select="2"/>
<xsl:template match="/">
<html>
<xsl:apply-templates
select="table/tr[(position()-1) mod $pMaxRow = 1]"
mode="table"/>
</html>
</xsl:template>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="tr" mode="table">
<table>
<xsl:apply-templates select="../@*|../tr[1]|.|following-sibling::tr
[$pMaxRow > position()]"/>
</table>
</xsl:template>
</xsl:stylesheet>
Output:
<html>
<table class="..." style="...">
<tr>
<td>head 1</td>
<td>head 2</td>
</tr>
<tr>
<td>col1</td>
<td>col2</td>
</tr>
<tr>
<td>col1</td>
<td>col2</td>
</tr>
</table>
<table class="..." style="...">
<tr>
<td>head 1</td>
<td>head 2</td>
</tr>
<tr>
<td>col1</td>
<td>col2</td>
</tr>
<tr>
<td>col1</td>
<td>col2</td>
</tr>
</table>
<table class="..." style="...">
<tr>
<td>head 1</td>
<td>head 2</td>
</tr>
<tr>
<td>col1</td>
<td>col2</td>
</tr>
<tr>
<td>col1</td>
<td>col2</td>
</tr>
</table>
</html>
Edit: Compact code.