Placing a List of Items into a Grid
A version of this page is also available for
4/8/2010
Placing a list of items into a grid or table is a frequently requested transformation. Given a list of product names, you might want to present them two across in a table, as follows.
product 1 |
product 2 |
product 3 |
product 4 |
Items must be grouped in pairs into table rows. XSLT currently does not have a built-in mechanism to handle arbitrary grouping. A combination of the <xsl:if> element with the test attribute and the following-sibling axis can be used to approximate this behavior. The following template turns a list of product elements into a two-column table.
<TABLE BORDER="1">
<xsl:for-each select="products/product">
<xsl:if test="(position() mod 2) = 1">
<TR>
<TD><xsl:value-of select="."/></TD>
<TD><xsl:value-of select="following-sibling::product[position()=1]"/></TD>
</TR>
</xsl:if>
</xsl:for-each>
</TABLE>
First, you iterate through each product element but use an <xsl:if> with the expression position() mod 2 = 1
to isolate only those products that should start a new row (every other product). The name of this product also is placed in the first cell in the row. Then you make another cell and place within it the next child — the one filtered out using the <xsl:if>. The query to select the next element navigates to the parent and obtains a set of following siblings.
Three-column tables can be created by adding another cell to the row to obtain another sibling element, and adjusting the expression to allow only every third element to create a new row. You can extrapolate this mechanism to create tables with even more columns.
<TABLE BORDER="1">
<xsl:for-each select="products/product">
<xsl:if test="(position() mod 3) = 1">
<TR>
<TD><xsl:value-of select="."/></TD>
<TD><xsl:value-of select="following-sibling::product[position()=1]"/></TD>
<TD><xsl:value-of select="following-sibling::product[position()=2]"/></TD>
</TR>
</xsl:if>
</xsl:for-each>
</TABLE>