If I have the following table:
<table>
<tr><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>6</td></tr>
<tr><td>A</td><td>B</td><td>C</td><td>D</td><td>E</td><td>F</td></tr>
</table>
How would I split this in XSLT so that I end up with the following:
<table>
<tr><td>1</td><td>2</td><td>3</td></tr>
<tr><td>A</td><td>B</td><td>C</td></tr>
</table>
<table>
<tr><td>4</td><td>5</td><td>6</td></tr>
<tr><td>D</td><td>E</td><td>F</td></tr>
</table>
I am interested in a generalized method, where the table could have any dimensions and be split into more than two tables. I don't care about rows; I want to split where there are more than N columns and end up with TD/N tables where TD is a table data cell. E.g., if there are 12 columns and 25 rows, I'd like 4 tables, each with 3 columns and 25 rows.
Try this. This should work in XSLT 1.0 . Adjust the ITEMS variable to vary the number of columns you want for each table.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" omit-xml-declaration="yes"/>
<xsl:variable name="ITEMS">3</xsl:variable>
<xsl:template match="//table">
<!-- Loop through the items in the first row -->
<xsl:for-each select="tr[position() = 1]/td">
<!-- Check if this item needs to be the start of a new row in a new table -->
<xsl:if test="position() mod $ITEMS = 1">
<!-- Get the current position which is used to get items from subsequent rows -->
<xsl:variable name="COLUMNNUMBER" select="position()"/>
<table>
<!-- Loop through all the rows in the table -->
<xsl:for-each select="../../tr">
<tr>
<!-- Output items within the required range using previously saved column number -->
<xsl:for-each select="td[position() >= $COLUMNNUMBER and position() < $COLUMNNUMBER + $ITEMS]">
<xsl:copy-of select="."/>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Here is my take at it:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:variable name="split" select="3" />
<xsl:template match="table">
<xsl:variable name="self" select="." />
<!-- select <td>1</td>, <td>4</td> -->
<xsl:for-each select="tr[1]/td[position() mod $split = 1]">
<xsl:apply-templates select="$self" mode="split">
<!-- calculate & pass the starting position for copying <td>s -->
<xsl:with-param name="start" select="$split * (position() - 1)" />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<!-- this just copies the table an passes on $start -->
<xsl:template match="table" mode="split">
<xsl:param name="start" select="0" />
<xsl:copy>
<xsl:apply-templates select="tr" mode="split">
<xsl:with-param name="start" select="$start" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- this copies <tr>/<td> based on $start -->
<xsl:template match="tr" mode="split">
<xsl:param name="start" select="0" />
<xsl:copy>
<xsl:copy-of select="td[
position() > $start and position() <= $start + $split
]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result:
<table>
<tr>
<td>1</td><td>2</td><td>3</td>
</tr>
<tr>
<td>A</td><td>B</td><td>C</td>
</tr>
</table>
<table>
<tr>
<td>4</td><td>5</td><td>6</td>
</tr>
<tr>
<td>D</td><td>E</td><td>F</td>
</tr>
</table>