Reputation: 133
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 > 10000 and current/@ID < 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
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
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 < 10000 and @ID > 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
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