Jarrett Phillips
Jarrett Phillips

Reputation: 133

Alternate Row Color of Table using XSLT

I have an XSLT where I want to alternate the row colors of an output table. I know that you can use the code such as in this example:

<table>
<tr>
    <td>Name</td>
    <td>ID</td>
</tr>
<xsl:for-each select="//Book">
    <xsl:variable name="altColor">
        <xsl:choose>
            <xsl:when test="position() mod 2 = 0">#FFFFFF</xsl:when>
            <xsl:otherwise>#D3DFEE</xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <tr bgcolor="{$altColor}">
        <td><xsl:value-of select="current()/@name"/></td>
        <td><xsl:value-of select="current()/@ID"/></td>
    </tr>
</xsl:for-each>
</table>

which works fine however, I have a few instances where I need to include some if statements within the for-each, such as.

<table>
<tr>
    <td>Name</td>
    <td>ID</td>
</tr>
<xsl:for-each select="//Book">
    <xsl:variable name="altColor">
        <xsl:choose>
            <xsl:when test="position() mod 2 = 0">#FFFFFF</xsl:when>
            <xsl:otherwise>#D3DFEE</xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:if test="current()/@ID &gt; 10000 and current/@ID &lt; 6000">
        <tr bgcolor="{$altColor}">
            <td><xsl:value-of select="current()/@name"/></td>
            <td><xsl:value-of select="current()/@ID"/></td>
        </tr>
    </xsl:if>
</xsl:for-each>
</table>

Then it doesn't work because it may skip an item at a position in the for-each and I end up with randomly alternating row colors or it may start at an incorrect position where the rows alternate starting with the incorrect color.

I've tried adding an xsl:sort, which doesn't really fix the problem. Is there a way to avoid this snag?

Upvotes: 2

Views: 10433

Answers (3)

user4618214
user4618214

Reputation: 21

Try with the following code:

tr[position() mod 2 =0]

<xsl:template match="n1:tr[position() mod 2 =0]">
 
   <tr bgcolor="#aaaaaa">
 
     <xsl:apply-templates/>

    </tr> 
  </xsl:template>
  


  <xsl:template match="n1:tr[position() mod 2 =1]">

    <tr bgcolor="#aaaaff">

      <xsl:apply-templates/>

    </tr>

  </xsl:template>

Upvotes: 2

Wayne
Wayne

Reputation: 60414

The simplest solution (taking your sample stylesheet as representative of your actual needs) is to only loop over the desired nodes in the first place. Like this:

<xsl:template match="/">
    <table>
        <tr>
            <td>Name</td>
            <td>ID</td>
        </tr>
        <xsl:for-each select="//Book[@ID &lt; 10000 and @ID &gt; 6000]">
            <xsl:variable name="altColor">
                <xsl:choose>
                    <xsl:when test="position() mod 2 = 0">#FFFFFF</xsl:when>
                    <xsl:otherwise>#D3DFEE</xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
        <tr bgcolor="{$altColor}">
            <td><xsl:value-of select="@name" /></td>
            <td><xsl:value-of select="@ID" /></td>
        </tr>
        </xsl:for-each>
    </table>
</xsl:template>

In other words, instead of conditionally including nodes in the body of the for-each simply select only those nodes you need. By doing this, position() will be relative to the set that you're iterating and it will work as expected.

For example, this (simplified) input:

<r>
    <Book ID="6200"/>
    <Book ID="7100"/>
    <Book/>
    <Book/>
    <Book ID="8000"/>
    <Book/>
    <Book ID="9001"/>
    <Book ID="9002"/>
</r>

Produces the correct alternation:

<table>
    <tr>
        <td>Name</td>
        <td>ID</td>
    </tr>
    <tr bgcolor="#D3DFEE">
        <td />
        <td>6200</td>
    </tr>
    <tr bgcolor="#FFFFFF">
        <td />
        <td>7100</td>
    </tr>
    <tr bgcolor="#D3DFEE">
        <td />
        <td>8000</td>
    </tr>
    <tr bgcolor="#FFFFFF">
        <td />
        <td>9001</td>
    </tr>
    <tr bgcolor="#D3DFEE">
        <td />
        <td>9002</td>
    </tr>
</table>

Upvotes: 0

Igor Cunko
Igor Cunko

Reputation: 59

one simple solution would be to remember last color used and than use opposing one instead basing your choice on position() and also you should move choice inside test for row

here is pseudo code

currentColor = color1
for each 
if ( id > 10000 and id < 6000 ) {
  if ( currentColor == color1 )
      currentColor= color2
  else 
      currentColor = color1
  showDataInColor(currentColor)
}

Upvotes: 0

Related Questions