Kirk Evans Blog

.NET From a Markup Perspective

Splitting single column data into multiple column HTML tables

On the ASP.NET message boards, dorsai78664 asks how to create a multi-column table with single column data using XSLT. Given the input XML document:

<root>
 <ComputerName value =”ComputerA />
 <ComputerName value =”ComputerB />
 <ComputerName value =”ComputerC />
 <ComputerName value =”ComputerD />
 <ComputerName value =”ComputerE />
 <ComputerName value =”ComputerF />
 <ComputerName value =”ComputerG />
 <ComputerName value =”ComputerH />
 <ComputerName value =”ComputerI />
 <ComputerName value =”ComputerJ />
 </root>
 

Dorsai wanted to output this as an HTML table with each row containing only 6 columns.  The key is that the position() function is relative to the current node set. The pointer to the node (the context) is defined in the for-each select statement, so the first node selected is that with position = 1. The first tr is added to the result tree, and the current node (“.”) and its following 5 sibling nodes are selected and applied to the attribute template. This means that nodes 1-6 are selected in the first loop iteration. The mod() operation then selects node 7, because it is the next one where mod 6 = 1. The loop selects the current node (“.”), which is node 7, and its following 5 sibling nodes, selecting 7-12 and applying the template.

<xsl:stylesheet version =”1.0 xmlns:xsl =”http://www.w3.org/1999/XSL/Transform >
<xsl:template match =”/ >
<html>
<table>
<xsl:for-each select =”/root/ComputerName[position() mod 6 = 1] >
 <xsl:sort select =”@value order =”ascending />
<tr>
 <xsl:apply-templates select =”./@value | following-sibling::ComputerName[position() < 6]/@value />
 </tr>
 </xsl:for-each>
 </table>
 </html>
 </xsl:template>
<xsl:template match =”@value >
<td class =”normal >
 <xsl:value-of select =”. />
 </td>
 </xsl:template>
 </xsl:stylesheet>

The result is:

<html>
<table>
<tr>
 <td class =”normal >ComputerA</td>
 <td class =”normal >ComputerB</td>
 <td class =”normal >ComputerC</td>
 <td class =”normal >ComputerD</td>
 <td class =”normal >ComputerE</td>
 <td class =”normal >ComputerF</td>
 </tr>
<tr>
 <td class =”normal >ComputerG</td>
 <td class =”normal >ComputerH</td>
 <td class =”normal >ComputerI</td>
 <td class =”normal >ComputerJ</td>
 </tr>
 </table>
 </html>