xsl-list
[Top] [All Lists]

Unusual? table layout task

2004-06-17 10:43:51
I was asked to create a set of named templates that
could take a set of elements and render them in a
table progressing vertically down each column, with
numbering.

For instance:

<items>
  <item>one</item>
  <item>two</item>
  <item>three</item>
  <item>four</item>
</items>

would transform to:

    1. one         3. three
    2. two         4. four

One of the requirement is that the node "item" would
not be fixed, they wanted to be able to pass in a node
name.  I believe this precludes some of the standard
solutions because you can't create and call template
names dynamically.

What I did was to write a set of recursive named
templates, to which you can pass the element name, the
number of columns desired, etc.

The 1st template recurses down the number of rows that
will be needed.  It then calls a 2nd template that
recurses across each row rendering each element.

Does that sound like a reasonable solution, or is
there a much better way to do it?

I will include my working solution (for FOP) at the
end of the email.

Thanks,  Mike



  <!--  Layout a group of elements in a table,        
               -->
  <!--  ordered vertically down each column           
               -->
  <!--                                                
               -->
  <!--  itemNode:     the element name to render in a
table           -->
  <!--  columns:      the number of columns to create 
               -->
  <!--  columnWidth:  the width of each column        
               -->
  <!--  indent:       start-indent value for the table
               -->
  <!--  numberFormat: the xsl:number format used to
number the items  -->

  <xsl:template name="tableLayoutVertFlow">
    <xsl:param name="itemNode"/>
    <xsl:param name="columns"/>
    <xsl:param name="columnWidth"/>
    <xsl:param name="indent"/>
    <xsl:param name="numberFormat"/>

    <!--  How many items will go into the table?  -->
    <xsl:variable name="itemCount">
      <xsl:value-of
select="count(*[name()=$itemNode])"/>
    </xsl:variable>

    <!--  How many rows will the table have?  -->
    <xsl:variable name="rows">
      <xsl:value-of select="ceiling($itemCount div
$columns)"/>
    </xsl:variable>


    <fo:table table-layout="fixed"
start-indent="{$indent}">

      <xsl:if test="$indent = ''">
        <xsl:attribute
name="start-indent">0cm</xsl:attribute>
      </xsl:if>

      <!--  Create the number of columns we need in
the table  -->
      <xsl:call-template name="makeTableColumns">
        <xsl:with-param name="count">
          <xsl:value-of select="$columns"/>
        </xsl:with-param>
        <xsl:with-param name="width">
          <xsl:value-of select="$columnWidth"/>
        </xsl:with-param>
      </xsl:call-template>

      <fo:table-body>

        <!--  Call a recursive routine that lays out
each table row  -->
        <xsl:call-template name="startTableRow">
          <xsl:with-param name="itemNode">
            <xsl:value-of select="$itemNode"/>
          </xsl:with-param>
          <xsl:with-param name="rows">
            <xsl:value-of select="$rows"/>
          </xsl:with-param>
          <xsl:with-param name="columns">
            <xsl:value-of select="$columns"/>
          </xsl:with-param>
          <xsl:with-param name="itemCount">
            <xsl:value-of select="$itemCount"/>
          </xsl:with-param>               
          <xsl:with-param name="curRow">
            <xsl:value-of select="1"/>
          </xsl:with-param>
          <xsl:with-param name="numberFormat">
            <xsl:value-of select="$numberFormat"/>
          </xsl:with-param>
        </xsl:call-template>

      </fo:table-body>
    </fo:table>

  </xsl:template>

  <!--  This is a recursive routine that is called for
each table row       -->
  <!--  It is called initially with a curRow value of
1, and then recurses  -->
  <!--  until the last row has been rendered          
                     -->
  <xsl:template name="startTableRow">
    <xsl:param name="itemNode"/>
    <xsl:param name="rows"/>
    <xsl:param name="columns"/>
    <xsl:param name="itemCount"/>
    <xsl:param name="curRow"/>
    <xsl:param name="numberFormat"/>

    <!--  Handle this row  -->
    <fo:table-row>

      <xsl:call-template name="processTableRow">
        <xsl:with-param name="itemNode">
          <xsl:value-of select="$itemNode"/>
        </xsl:with-param>
        <xsl:with-param name="rows">
          <xsl:value-of select="$rows"/>
        </xsl:with-param>
        <xsl:with-param name="columns">
          <xsl:value-of select="$columns"/>
        </xsl:with-param>
        <xsl:with-param name="itemCount">
          <xsl:value-of select="$itemCount"/>
        </xsl:with-param>               
        <xsl:with-param name="curRow">
          <xsl:value-of select="$curRow"/>
        </xsl:with-param>
        <xsl:with-param name="curCol">
          <xsl:value-of select="1"/>
        </xsl:with-param>
        <xsl:with-param name="numberFormat">
          <xsl:value-of select="$numberFormat"/>
        </xsl:with-param>
      </xsl:call-template>

    </fo:table-row>

    <!--  If this is not the last row, then bump the
row count and recurse  -->
    <xsl:if test="$curRow &lt; $rows">  
      <xsl:call-template name="startTableRow">
        <xsl:with-param name="itemNode">
          <xsl:value-of select="$itemNode"/>
        </xsl:with-param>
        <xsl:with-param name="rows">
          <xsl:value-of select="$rows"/>
        </xsl:with-param>
        <xsl:with-param name="columns">
          <xsl:value-of select="$columns"/>
        </xsl:with-param>
        <xsl:with-param name="itemCount">
          <xsl:value-of select="$itemCount"/>
        </xsl:with-param>               
        <xsl:with-param name="curRow">
          <xsl:value-of select="$curRow + 1"/>
        </xsl:with-param>
        <xsl:with-param name="numberFormat">
          <xsl:value-of select="$numberFormat"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:if>

  </xsl:template>


  <!--  This is a recursive routine that is called for
each column in a table row  -->
  <!--  It is called initially with a curCol value of
1, and then recurses        -->
  <!--  until the last column in the row has been
rendered                        -->
  <xsl:template name="processTableRow">
    <xsl:param name="itemNode"/>
    <xsl:param name="rows"/>
    <xsl:param name="columns"/>
    <xsl:param name="itemCount"/>
    <xsl:param name="curRow"/>
    <xsl:param name="curCol"/>
    <xsl:param name="numberFormat"/>

    <!--  Calculate the position in the node list that
we should operate on  -->
    <xsl:variable name="index">
      <xsl:value-of select="$curRow + (($curCol - 1) *
$rows)"/>
    </xsl:variable>


    <fo:table-cell>
      <fo:block>
            
        <!--  If we are still in bounds, render item
value, otherwise we want a nice empty cell  -->
        <xsl:if test="$index &lt;= $itemCount">
        
          <!--  If we have a number format, then
render the item number  -->
          <xsl:if test="$numberFormat != ''">
            <fo:inline font-weight="bold"><xsl:number
format="{$numberFormat}" value="$index"/>.
</fo:inline> 
          </xsl:if>
          
          <!--  Render the item value  -->
          <xsl:value-of
select="*[name()=$itemNode][$index]"/>
          
        </xsl:if>
      </fo:block>
    </fo:table-cell>

    <!--  If we haven't reached the end of the row,
bump the column count and recurse  -->
    <xsl:if test="$curCol &lt; $columns">

      <xsl:call-template name="processTableRow">
        <xsl:with-param name="itemNode">
          <xsl:value-of select="$itemNode"/>
        </xsl:with-param>
        <xsl:with-param name="rows">
          <xsl:value-of select="$rows"/>
        </xsl:with-param>
        <xsl:with-param name="columns">
          <xsl:value-of select="$columns"/>
        </xsl:with-param>
        <xsl:with-param name="itemCount">
          <xsl:value-of select="$itemCount"/>
        </xsl:with-param>               
        <xsl:with-param name="curRow">
          <xsl:value-of select="$curRow"/>
        </xsl:with-param>
        <xsl:with-param name="curCol">
          <xsl:value-of select="$curCol + 1"/>
        </xsl:with-param>
        <xsl:with-param name="numberFormat">
          <xsl:value-of select="$numberFormat"/>
        </xsl:with-param>
      </xsl:call-template>

    </xsl:if>

  </xsl:template>




  <xsl:template name="makeTableColumns">
    <xsl:param name="count"/>
    <xsl:param name="width"/>

    <xsl:if test="$count > 1">  
      <xsl:call-template name="makeTableColumns">
        <xsl:with-param name="count"
select="round($count - 1)"/>
        <xsl:with-param name="width" select="$width"/>
      </xsl:call-template>
    </xsl:if>

    <fo:table-column column-width="{$width}"/>

  </xsl:template>







                
__________________________________
Do you Yahoo!?
Yahoo! Mail - Helps protect you from nasty viruses.
http://promotions.yahoo.com/new_mail


<Prev in Thread] Current Thread [Next in Thread>
  • Unusual? table layout task, Mike Kellstrand <=