Re: XSL Table Styling

Subject: Re: XSL Table Styling
From: Mike Brown <mike@xxxxxxxx>
Date: Wed, 19 Jul 2000 10:20:30 -0700 (PDT)
Scott Johnson wrote:
> What I'm trying to do is lay out two rows of data with 4 items per row

Generally when people ask questions about HTML tables, they've tried a
tag-based approach, which inevitably fails because they are thinking
about how to arbitrarily declare the beginning and end of each row. In
the well-formed world of XML and XSLT, one needs a more object-oriented
approach. If you break the problem down into the answers to these
questions, you might see your solution more quickly:

 - What always determines when a new row is added?
 - What always goes into each row?
 - What always goes into each cell?

In your case, for each "row" of data, you're wanting to create 3 table
rows. Your stylesheet is trying to create a new set of table rows for
each *unit* of data (each 'hit' element that is matched), so of course
you end up with too many table rows and not enough columns in your
table.

I'm guessing your XML looks something like

<result>
  <hit>
    <name>Foo</name>
    <small-image>foo.jpg</small-image>
    <short-desc>This is foo.</short-desc>
  </hit>
  ...
</result>

Here is one way to approach the problem, and it is flexible for any
number of desired columns with an unknown number of 'hit' elements.
It will also fill in cells in empty columns, in case the number of
'hit' elements isn't evenly divisible by the number of columns
desired. (untested code; watch for typos)

<xsl:template match="result">
  <xsl:variable name="cols" select="4"/>
  <xsl:variable name="all_hits" select="hit"/>
  <table>
    <!-- start a new data row for every 1st, 5th, 9th, etc. 'hit' element -->
    <xsl:for-each select="$all_hits[position() mod $cols = 1]">
      <xsl:variable name="this_hit_pos" select="position()"/>
      <xsl:variable name="current_row_hits" select="$all_hits[position() &gt;= $this_hit_pos and position() &lt; $this_hit_pos + $cols]"/>
      <!-- go generate the 3 table rows for this one data row -->
      <xsl:call-template name="make_table_rows">
        <xsl:with-param name="cols" select="$cols"/>
        <xsl:with-param name="current_row_hits" select="$current_row_hits"/>
      </xsl:call-template>
    </xsl:for-each>
  </table>
</xsl:template>

<xsl:template name="make_table_rows">
  <xsl:param name="cols" select="1"/>
  <xsl:param name="current_row_hits" select="/.."/>
  <!-- selects above are defaults in case nothing was passed in -->
  <xsl:if test="$current_row_hits">
    <xsl:variable name="num_empty_cols" select="$cols - $current_row_hits"/>
    <tr>
      <xsl:for-each select="$current_row_hits">
        <td width="175">
          <img width="175" height="175" src="{small-image}"/>
        </td>
      </xsl:for-each>
      <xsl:if test="$num_empty_cols"> <!-- true if not zero -->
        <xsl:call-template name="make_empty_cells">
          <xsl:with-param name="num" select="$num_empty_cols"/>
        </xsl:call-template>
      </xsl:if>
    </tr>
    <tr>
      <xsl:for-each select="$current_row_hits">
        <td width="175">
          <font face="Verdana" size="2">
            <b>
              <xsl:value-of select="name"/>
            </b>
          </font>
        </td>
      </xsl:for-each>
      <xsl:if test="$num_empty_cols"> <!-- true if not zero -->
        <xsl:call-template name="make_empty_cells">
          <xsl:with-param name="num" select="$num_empty_cols"/>
        </xsl:call-template>
      </xsl:if>
    </tr>
    <tr>
      <xsl:for-each select="$current_row_hits">
        <td width="175">
          <font face="Verdana" size="1">
            <xsl:value-of select="short-desc"/>
          </font>
        </td>
      </xsl:for-each>
      <xsl:if test="$num_empty_cols"> <!-- true if not zero -->
        <xsl:call-template name="make_empty_cells">
          <xsl:with-param name="num" select="$num_empty_cols"/>
        </xsl:call-template>
      </xsl:if>
    </tr>
  </xsl:if>
</xsl:template>

<xsl:template name="make_empty_cells">
  <xsl:with-param name="num" select="0"/>
  <xsl:if test="$num">
    <td>&#160;</td>
    <xsl:call-template name="make_empty_cells">
      <xsl:with-param name="num - 1"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

-Mike


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


Current Thread