Placing a List of Items into a Table
A common transformation is to place a list of items into a grid or table. 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>
Repeat through each product element, but use the <xsl:if>
element 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 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>
Example
This example demonstrates the table code snippets that are shown above.
XML File (product-list.xml)
<?xml version='1.0'?> <?xml-stylesheet type="text/xsl" href="product-list.xsl"?> <products> <product>ActiMates Arthur</product> <product>ActiMates Barney</product> <product>ActiMates DW</product> <product>ActiMates PC Pack</product> <product>ActiMates TV Pack</product> <product>Arthur's Brainteasers</product> <product>Arthur's Math Carnival</product> <product>Arthur's Reading Roundup</product> <product>Barney fun on the Farm</product> <product>Barney goes to the Circus</product> <product>Barney under the Sea</product> </products>
XSLT File (product-list.xsl)
<?xml version='1.0'?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <HTML> <BODY STYLE="font:bold 10pt Arial"> <DIV>Two column table:</DIV> <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> <BR/> <DIV>Three column table:</DIV> <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> </BODY> </HTML> </xsl:template> </xsl:stylesheet>
Formatted Output
Processor Output
A portion of the output stream is shown here.
<HTML> <BODY STYLE="font:bold 10pt Arial"> <DIV>Two column table:</DIV> <TABLE BORDER="1"> <TR> <TD>ActiMates Arthur</TD> <TD>ActiMates Barney</TD> </TR> <TR> <TD>ActiMates DW</TD> <TD>ActiMates PC Pack</TD> </TR> ... </TABLE><BR><DIV>Three column table:</DIV> <TABLE BORDER="1"> <TR> <TD>ActiMates Arthur</TD> <TD>ActiMates Barney</TD> <TD>ActiMates DW</TD> </TR> <TR> <TD>ActiMates PC Pack</TD> ... </TR> </TABLE> </BODY> </HTML>