xml-general mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Mike Brown <m...@skew.org>
Subject Re: simple (?) xsl question
Date Wed, 09 Feb 2000 04:12:27 GMT
I took xalan-dev out of the recipients list because this question does
not have anything to do with the development of the Xalan software. It
doesn't relate to any of the Apache XML projects, either, and really
should have been posted to the XSL list at mulberrytech.com instead of
the general@xml.apache.org list.

Nevertheless, it's an interesting challenge to come up with a generic
solution to this common problem.

> Let's say I'm doing an <xsl:for-each ...> over an unknown number of xml
> elements.  I want to format these elements to an HTML table that 4 columns
> wide.  Inside my <xsl:for-each ...>, how do I say "every fourth iteration,
> close the <html:tr> and open another <html:tr>"?

You don't. You need to change your approach to building tables. Rather than
thinking in terms of start tags and end tags, you must think in terms of
complete elements; assemble an entire table, table row, or table cell at
once.

<xsl:template match="/">
  <!-- number of columns desired -->
  <xsl:variable name="cols" select="4"/>
  <table>
    <!-- identify nodes to put in table -->
    <xsl:variable name="nodes" select="/lets/select/some/nodes"/>
    <!-- only look at 1st, 5th, 9th... node -->
    <xsl:for-each select="$nodes[(position() - 1) mod $cols = 0]">
      <!-- make a new row for that node -->
        <tr>
        <!-- make a note of this node's unique id -->
        <xsl:variable name="this_id" select="generate-id()"/>
        <!-- iterate through this node and its next 3 siblings -->
          <xsl:for-each select="self::* | following::*[. = $nodes][position() &lt;
$cols]">
          <!-- make a new cell for that node -->
          <td>
            <xsl:value-of select="."/>
          </td>
        </xsl:for-each>
        <!-- are we on the last row? are there cells remaining to fill in? -->
        <xsl:if test="position() = last() and count($nodes) mod $cols &gt; 0">
          <!-- fill in remaining cells -->
          <xsl:call-template name="filler_cells">
            <xsl:with-param name="cell_count" select="$cols - count($nodes) mod $cols"/>
          </xsl:call-template>
        </xsl:if>
      </tr>
    </xsl:for-each>
  </table>
</xsl:template>

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


I'm not sure this is the shortest solution, but it seems to work.

   - Mike
________________________________________________________________________
 Mike Brown / Hyperreal   |  Hyperreal http://www.hyperreal.org/music/
 PO Box 61334             |     XML & XSL http://www.skew.org/xml/
 Denver CO 80206-8334 USA |       http://www.hyperreal.org/~mike/

Mime
View raw message