Re: [xsl] alternate row color in a table

Subject: Re: [xsl] alternate row color in a table
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Mon, 18 Feb 2002 12:14:56 +0000
Hi Sébastien,

> I have different xml like this one and sometimes element <info1> or
> <info2> or <info3> or <info4> may be not present.
> In this case it seems to be impossible to use a test with position()
> mod 2.

As it stands, you're outputting a row for each of the relevant nodes
whether or not they exist; I guess that you are talking about what to
do if the rows themselves are optional.

You can use position() mod 2 as long as you can create a node set that
holds the nodes that you want to use to create the rows, and can sort
them in the order in which you want them to appear.

In your case, the node set that holds the nodes you want to appear in
the table can be created with the path:

  info3 | info2/@type | info4/subinfo

To sort them, in order to get the ordering that you want, you need to
create a series of xsl:sorts that sort first by whether the node is an
info3 element, then by whether it's a type attribute on an info2
element, then by whether it's a subinfo element on a info4 element,
which you can do with:

  <xsl:for-each select="info3 | info2/@type | info4/subinfo">
    <xsl:sort select="self::info3" order="descending" />
    <xsl:sort select="parent::info2 and not(self::node()) and
                      name() = 'type'" order="descending" />
    <xsl:sort select="parent::info4 and self::subinfo"
              order="descending" />
    <tr class="color{position() mod 2}">
      <td><xsl:value-of select="." /></td>

An alternative is to create the rows first, and then add the required
colour afterwards. For that, you need a node-set() extension function,
but they're not hard to find...

  <xsl:variable name="rows">
    <xsl:if test="info3">
      <tr><td><xsl:value-of select="info3"/></td></tr>
    <xsl:if test="info2/@type">
      <tr><td><xsl:value-of select="info2/@type"/></td></tr>
    <xsl:if test="info4/subinfo">
      <tr><td><xsl:value-of select="info4/subinfo"/></td></tr>
  <xsl:for-each select="exsl:node-set($rows)/tr">
    <tr class="color{position() mod 2}">
      <xsl:copy-of select="node()" />


This gets a lot easier in XSLT 2.0, since you can construct a sequence
that holds the nodes in the order you want them in the first place, as

  <xsl:for-each select="(info3, info2/@type, info4/subinfo)">
    <tr class="color{position() mod 2}">
      <td><xsl:value-of select="." /></td>



Jeni Tennison

 XSL-List info and archive:

Current Thread