[xsl] Transformation for FO table widths

Subject: [xsl] Transformation for FO table widths
From: Gustaf Liljegren <gustaf.liljegren@xxxxxx>
Date: Mon, 29 Apr 2002 19:29:56 +0200
Here's a pretty complex transformation problem.

I have a document type that uses a subset of HTML 3.2 for tables (due to a
limitation in my XML editor). Each TH and TD may have a WIDTH attribute,
that I intend to map to the common width attribute in FO. I know the real
way in XSL is to use fo:table-column with column-width, but due to another
limitation in my FO engine, I can't. Fortunately, the width attribute in FO
seem to work on table-cells too.

I want to use WIDTH attributes only on the *first* row in a table, and all
values should be written in percent in the FO. The rows can be set both in
percent and *pixels* in the XML editor. There may also be elements without
WIDTH attributes. Currentlt, I don't handle these at all. Here's an example
with both percent and pixel values:

30% 400 50 10%

The original percent values are transfered directly to the FO. Pixel nodes
are converted to percent nodes with a long mathematical expression. The
problems seem to start when I sum up percent values and pixel values in two
node-sets:

  <!-- Match the first row in any table -->
  <xsl:template match="TR[1]">
    <fo:table-row>
      <xsl:if test="TH/@WIDTH | TD/@WIDTH">
        <!-- Get @WIDTH-nodes with percent values -->
        <xsl:variable name="percent-nodes">
          <xsl:value-of select="TH[contains(@WIDTH, '%')] |
                                TD[contains(@WIDTH, '%')]"/>
        </xsl:variable>

There's a similar variable for pixel values. I guess there's something
wrong with my use of the contains() function. Another approach I've tried
is this:

        <xsl:variable name="percent-nodes">
          <xsl:for-each select="TH | TD">
            <xsl:if test="contains(@WIDTH, '%')">
              <xsl:value-of select="@WIDTH"/>
            </xsl:if>
          </xsl:for-each>
        </xsl:variable>

But this code will only get the first percent node. What I do next is to
sum up these values, like this:

  <!-- Sum up percent values -->
  <xsl:variable name="percent-sum"
    select="sum(number(substring-before($percent-nodes, '%')))"/>
  <!-- Sum up pixel values -->
  <xsl:variable name="pixelsumma"
    select="sum(number($pixel-nodes))"/>

Finally, here's the code that constructs the table cells:

  <xsl:for-each select="TH | TD">
    <fo:table-cell>
      <xsl:choose>
        <xsl:when test="contains(@WIDTH, '%')">
          <xsl:attribute name="width">
            <xsl:value-of select="@WIDTH"/>
          </xsl:attribute>
        </xsl:when>
        <xsl:otherwise>
          <xsl:attribute name="width">
            <xsl:value-of select="number(@WIDTH) * 
              (100 - $percent-sum) div (100 * $pixel-sum)"/>
          </xsl:attribute>
        <xsl:otherwise>
      </xsl:choose>
      <fo:block>
        <xsl:apply-templates/>
      </fo:block>
    </fo:table-cell>
  </xsl:for-each>

That's all.

Gustaf


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread