Re: [xsl] Adding rowspans to a table

Subject: Re: [xsl] Adding rowspans to a table
From: Evan Lenz <evan@xxxxxxxxxxxx>
Date: Tue, 21 Feb 2006 16:04:23 -0800
Hi Kevin,

This looked like a fun one to try out. Below is a pure XSLT 1.0 solution. It assumes "tr" and "td" for table rows and cells. A recursive function definition in XSLT 2.0 could have avoided the string-length() hack. And functional abstraction in general would probably make it cleaner.

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

 <!-- by default, copy everything unchanged -->
 <xsl:template match="@*|node()">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
 </xsl:template>

 <!-- keep the cell? if so, add rowspan? -->
 <xsl:template match="td">
   <xsl:variable name="position"
                 select="1 + count(preceding-sibling::td)"/>
   <xsl:variable name="cell-above"
                 select="../preceding-sibling::tr[1]/td[$position]"/>
   <xsl:variable name="cell-below"
                 select="../following-sibling::tr[1]/td[$position]"/>
   <!-- remove the <td> if it has the same value as the cell above -->
   <xsl:if test="not(. = $cell-above)">
     <xsl:copy>
       <!-- add rowspan attribute if the cell below has the same value -->
       <xsl:if test=". = $cell-below">
         <xsl:attribute name="rowspan">
           <xsl:variable name="tick-for-each-contiguous-cell-below">
             <xsl:apply-templates mode="tick" select="$cell-below"/>
           </xsl:variable>
           <xsl:variable name="contiguous-cells-below"
                         select="string-length(
                                  $tick-for-each-contiguous-cell-below)"/>
           <xsl:value-of select="1 + $contiguous-cells-below"/>
         </xsl:attribute>
       </xsl:if>
       <xsl:apply-templates select="@*|node()"/>
     </xsl:copy>
   </xsl:if>
 </xsl:template>

<!-- for building up a count of contiguously-valued cells in a column -->
<xsl:template match="td" mode="tick">
<xsl:variable name="position"
select="1 + count(preceding-sibling::td)"/>
<xsl:text>1</xsl:text>
<!-- Only process the cell below if it has the same value; -->
<xsl:apply-templates select="../following-sibling::tr[1]/td[$position]
[.=current()]"
mode="tick"/>
</xsl:template>


</xsl:stylesheet>

Hope this helps,

Evan Lenz
http://xmlportfolio.com
http://evanlenz.net/blog/


Kevin Bird wrote:
Hi

I have a three row table where each cell will have a numeric value. I
need to compare values from row[1] and row[2] and rowspan where values
match. I then need to do same for row[2] and row[3].



From this: ______________ |__|__|__|__|__| |__|__|__|__|__| |__|__|__|__|__|


To this:


 ______________
|  |__|__|  |__|
|__|  |__|__|  |
|__|__|__|__|__|


I'm sure someone has had to tackle this problem before. Are there any stylesheets out there that could help me arrive at a solution?

Thanks.

--
Kevin

Current Thread