Interesting and very short solution, although I did not test it.
My "simple" solution (which actually works) looks like this:
<xsl:variable name="Rows">3</xsl:variable>
<xsl:variable name="Columns">4</xsl:variable>
<xsl:template name="item-table">
<!-- As Michael, I used a variable to manage sorting the items -->
<xsl:variable name="SortedItems">
<xsl:for-each select="//items">
<xsl:sort select="date" order="descending"/>
<xsl:sort select="name" order="ascending"/>
<xsl:if test="position() le $Rows * $Columns">
<xsl:sequence select="."/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- I then walk the sorted items by the first one of each row -->
<xsl:for-each select="$SortedItems/item">
<xsl:if test="(position() mod $Columns) eq 1">
<xsl:variable name="RowItems"
select="following-sibling::node()[position() lt number($Columns)]"/>
<tr>
<!-- First Column -->
<td>
<!-- Add rowspan="$Columns" if there are no other
items in this row -->
<xsl:if test="not(count($RowItems))">
<xsl:attribute name="colspan">
<xsl:value-of select="$Columns"/>
</xsl:attribute>
</xsl:if>
<!-- Insert formatted item data -->
<xsl:apply-templates select="." mode="cell-content"/>
</td>
<!-- Create other columns in current row -->
<xsl:for-each
select="following-sibling::node()[position() lt number($Columns)]">
<td>
<!-- If current node is last of current row add
colspan=".." attribute -->
<xsl:if
test="count(following-sibling::node()[position() lt number($Columns)])
eq 0 and
not(position() eq number($Columns)-1)">
<xsl:attribute name="colspan">
<xsl:value-of select="number($Columns) -
position()"/>
</xsl:attribute>
</xsl:if>
<!-- Insert formatted item data -->
<xsl:apply-templates select="." mode="cell-content"/>
</td>
</xsl:for-each>
</tr>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="//item" mode="cell-content">
<xsl:value-of select="name"/>
</xsl:template>
Probably not the easiest way, but to me it seemed to be the most ovious one.
Any tips, hints, comments, disagreements?
Regards,
Jannis
Michael Kay schrieb:
First sort:
<xsl:variable name="sorted-names" as="element(td)*">
<xsl:perform-sort select="item">
<xsl:sort select="date" order="descending"/>
<td><xsl:sequence select="string(name)"/></td>
</xsl:perform-sort>
</xsl:variable>
Then group:
<xsl:variable name="last-colspan"
select="$columns - (count($sorted-names) mod $columns) + 1
<xsl:for-each-group select="$sorted-names"
group-adjacent="position()-1 idiv $columns">
<tr>
<xsl:for-each select="current-group()">
<xsl:choose>
<xsl:when test=". is $sorted-names[last()] and $last-colspan ne 1">
<td colspan="{$last-colspan}">
<xsl:sequence select="string(.)"/>
</td>
<xsl:otherwise>
<xsl:sequence select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:for-each-group>
Not tested.
Michael Kay
http://www.saxonica.com/
-----Original Message-----
From: Jannis Pohlmann [mailto:info(_at_)sten-net(_dot_)de]
Sent: 12 December 2004 03:58
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] Transform list of elements to a sorted and
dynamic HTML table
Good morning,
I have a list of items, e.g.:
<item>
<name>Adoreable</name>
<date>2004-12-11</date>
</item>
<item>
<name>Adjustable</name>
<date>2004-12-11</date>
</item>
<item>
<name>Bulk</name>
<date>2004-12-10</date>
</item>
<item>
<name>Condensed</name>
<date>2004-12-12</date>
</item>
<item>
<name>Compromise</name>
<date>2004-11-08</date>
</item>
and I want them to be transformed to a sorted and dynamic
(columns and rows
adjustable by variables - $Columns and $Rows) HTML table (using
recent Version of Saxon and XSLT2.0). The sort element are
the <date/>-Elements
(descending), so the table output had to look like this
($Columns = 2, $Rows = 2):
<table>
<tr>
<td>Condensed</td>
<td>Adjustable</td>
</tr>
<tr>
<td>Adoreable</td>
<td>Bulk</td>
</tr>
<tr>
<td colspan="2">Compromise</td>
</tr>
</table>
If there are not enough items to fill the columns of the last
row its last <td> should
have a "colspan" attribute in order to satisfy layout
requirements. No empty
rows should be created (e.g. if there are not enough items to
fill all <$Rows> rows).
As you may see there exists a second sort element (<name/>,
ascending) in my example
but this is no must-have feature.
An alternative way might be to select the first <$Columns *
$Rows> items (sorted descendingly
by <date/>, of course) - but I see no solution for this, right now.
Is there a way to handle this problem with the power of XSLT?
Regards,
Jannis
--~------------------------------------------------------------------
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>
--~--
--~------------------------------------------------------------------
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>
--~--
--~------------------------------------------------------------------
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>
--~--