xsl-list
[Top] [All Lists]

Re: xslt to generate XSL-FO table-layout=fixed

2005-02-21 15:13:34
I've been working with something similar.  I should warn you that I'm
a little new to both xslt and xsl-fo myself and this mini-project was
my first with a table so that there might be a better way.  I'm going
to return to this one soon to improve it but it might give you some
ideas.

In our XML application we can't go by number of columns in the first
row since elements might be absent (indicating a empty cell needs to
be in the table).  So instead we have a "description" area that has
names of the columns.  We use this to calculate how many elements
there are and their widths.

The structure of the xml is along the lines of 

<spreadsheet>
   <description>
        <columns>
            <column>
                ......<columns>
       </columns>
 </description>
<table>
<row>
<foo>
<bar>
<foobar>
</row>
...
</table>
</spreadsheet>


XSLT-
This is taken from our template that initially calls the function:

<xsl:call-template name="createColumns">
                 <xsl:with-param name="columns"  
                                        
select="/spreadsheet/description/columns/column"/>
                 <xsl:with-param name="total" select="0"/>
               </xsl:call-template>

The following function takes a group of "columns" .  The base case is
the last column, for which it writes out a proportinal-column-width
that is 100 minus the total percentages of what has already been
processed.  If not the base case,  it creates a column by taking the
second and third character of 1/total number of columns.
(.33333333333333 becomes 33) and then calls this function with the
that number added to the total and one less element in the node set.

  <xsl:template name="createColumns">
    <xsl:param name="columns"/>
    <xsl:param name="total" />

    <!-- if last, end this madness -->
    <xsl:choose>
       <!-- base case -->
      <xsl:when test="count($columns) = 1">
        <xsl:element name="fo:table-column">
          <xsl:attribute name="column-width">
            <xsl:text>proportional-column-width(</xsl:text><xsl:value-of
select="100 - $total"/><xsl:text>)</xsl:text>
          </xsl:attribute>
        </xsl:element>
      </xsl:when>
      <!-- recursive -->
      <xsl:otherwise>
        <xsl:variable name="rawpercentage">
          <xsl:value-of select="1 div
count(/spreadsheet/description/columns/column)"/>
        </xsl:variable>
        <xsl:variable name="width">
          <xsl:value-of select="substring($rawpercentage,3,2)"/>
        </xsl:variable>
        <xsl:element name="fo:table-column">
          <xsl:attribute name="column-width">
          <xsl:text>proportional-column-width(</xsl:text><xsl:value-of
select="$width"/><xsl:text>)</xsl:text></xsl:attribute>
        </xsl:element>          
        <!-- recursive call -->
        <xsl:call-template name="createColumns">
            <xsl:with-param name="columns" select="$columns[position() > 1]" />
            <xsl:with-param name="total" select="$total + $width" />
          </xsl:call-template>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:template>


This workaround was created after playing around with the columns for
a while and reading through the fop mailing list as well as the
archives for this one.  I'm sure there are nicer and spiffer ways to
do this.  Also notice that it will not create columns of exact size
for odd numbers (the right one will be slightly bigger).

The actual xslt is a little more complex since we need to map the
elements to their row placement.  Probably the XML could be improved
too.



Jon Gorman

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



<Prev in Thread] Current Thread [Next in Thread>