Does anyone have a way to change the background color of every other row in a table with xsl-fo. I'm using nFOP to create pdf's and have accomplished most everything I've needed but would like to have say every other row have a light gray background. If I statically set the rows of the table this would be easy, but my rows are generated with an <xsl-for each> as I do not know ahead of time how many results I'll have in my xml.

Is there a way to tell how many rows end up in the table and then apply formating, or say apply conditional formatting to odd or even numbered rows?

Thanks in advance.

Dani AI

Generated

Short answer: use XPath/XSLT to detect odd/even rows and emit different FO for each case. is right to call out position() and ' modulus approach is exactly the common pattern. The XSL‑FO spec explicitly lists background properties for table-row, table-body, table-column and table-cell, so you can style rows at the FO level. (w3.org)

A tidy, maintainable pattern is to apply-templates to your row nodes and provide two templates (or two modes) that match odd and even positions. Put the visible background on the FO cell (more compatible) rather than relying on renderer-specific behavior of the row element:

<xsl:apply-templates select="rows"/>

<xsl:template match="row[position() mod 2 = 1]">
  <fo:table-row><xsl:apply-templates select="cell"/></fo:table-row>
</xsl:template>

<xsl:template match="row[position() mod 2 = 0]">
  <fo:table-row><xsl:apply-templates select="cell" mode="even"/></fo:table-row>
</xsl:template>

<xsl:template match="cell" mode="even">
  <fo:table-cell background-color="#f0f0f0"><fo:block><xsl:value-of select="."/></fo:block></fo:table-cell>
</xsl:template>

Practical notes: many FO engines (including FOP) support background-color, but renderer behavior varies — setting the color on each fo:table-cell or on the fo:block inside the cell is the most robust approach and avoids gaps around borders/padding. Use attribute-sets or templates to avoid repeating styling. Test page-break and header/footer cases since long tables can reflow differently across renderers. (data2type.de)

Recommended Answers

All 2 Replies

It's hard to tell without looking at what you're input and desired output are, but you can do this pretty easily. Make use of the position() function to determine what number position in the ancestry the node you're processing. Once you do that, you choose to apply one template for odds and one template for evens. Each one would do the exact same thing except change the color of the row.

That's a pretty simple thing to do. Create a variable called "evenOdd" and have it be even if the position() of the loop modulus 2 is equal to 0. If not, have it be odd. Let's say you have a calendar XML file with the following format (where the dots represent the values):

<root>
   <calendar>
      <event>
          ...
      </event>
      <event>
          ...
      </event>
      <event>
          ...
      </event>
      <event>
          ...
      </event>
      <event>
          ...
      </event>
   </calender>
</root>

To display the event data, you'll run an xsl:for-each loop where you'll output the <div> and the value inside of it (event), but you'll also create an attribute (class) that will determine whether the outputted div (for each event) is a even or odd.

<xsl:for-each select="/data/calendar">
   <div><xsl:value-of select="event"></div>

<xsl:attribute name="class">
   <xsl:choose>
      <xsl:when test="position() mod 2 = 0">
         <xsl:text>even</xsl:text>
      </xsl:when>
      <xsl:otherwise>
         <xsl:text>odd</xsl:text>
      </xsl:otherwise>
   </xsl:choose>
</xsl:attribute>

</xsl:for-each>

Hope that helped. If not, feel free to PM me and I'll go into greater detail or attempt helping you in any way you need help.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.