This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Multiple Rows in a Table / Same Element


Pinto, Rebecca wrote:
> I am trying to create a Calendar table with a new row after every 7th day.
> Here is the XML I'm working with:
> 
> <Month>            
>             <day date="1" />
>             <day date="2"/>
>             <day date="3" />
> [...]
>             <day date="31"/>
> </Month>  

First I would constrain myself to a good template-based design pattern.
Once you've determined what days you're processing, any given day in the
set is going to be treated the same way, i.e. it gets a cell with the date
in it:

<xsl:template match="day">
  <td><xsl:value-of select="@date"/></td>
</xsl:template>

The trick is to choose the right days to process. You were on the right
track by looking at every 7th day. When processing each of those days,
you want to go find the next 6 to complete the row.

Be careful about the use of mod and position(); the first node is at
position 1, and you want positions 1, 8, 15, etc., not 0, 7, 14 -- so it
would be position() mod 7 = 1.

<xsl:template match="month">
  <xsl:for-each select="day[position() mod 7 = 1]">
    <tr>
      <xsl:apply-templates select=". | following-sibling::day[position() &lt; 7]"/>
    </tr>
  </xsl;for-each>
</xsl:template>

Your relatively flat schema lends itself well to the use of
following-sibling. If it were not so flat, another option is to get the
following 6 day elements by their position in the set of all day elements:

<xsl:template match="month">
  <xsl:variable name="currentmonth" select="."/>
  <xsl:for-each select="day[position() mod 7 = 1]">
    <xsl:variable name="pos" select="position()"/>
    <tr>
      <xsl:apply-templates select="$currentmonth/day[position() &gt;= $pos and position() &lt; $pos + 7]"/>
    </tr>
  </xsl;for-each>
</xsl:template>

However this would be wasteful in your case.

One thing to note is that HTML tables need to have all cell spaces
accounted for. If there are fewer than 7 days in the last set to process,
you'll be left with some unfilled cells. So before that </tr> I would add
something like this to make one big last cell:

<xsl:if test="last() &lt; position() + 6">
  <td colspan="{position() + 6 - last()}">&#160;</td>
</xsl:if>

or this plus the named template below:

<xsl:if test="last() &lt; position() + 6">
  <xsl:call-template name="make_empty_cells">
    <xsl:with-param name="count" select="position() + 6 - last()"/>
  </xsl:call-template>
</xsl:if>

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

   - Mike
____________________________________________________________________
Mike J. Brown, software engineer at         My XML/XSL resources:
webb.net in Denver, Colorado, USA           http://www.skew.org/xml/


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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]