This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: Making groups of N elements --> Photo index
- From: Antonio Fiol <fiol at w3ping dot com>
- To: xsl-list at lists dot mulberrytech dot com
- Date: Wed, 12 Jun 2002 14:14:56 +0200
- Subject: Re: [xsl] Making groups of N elements --> Photo index
- References: <003701c211f7$cc06fec0$6401a8c0@pcukmka>
- Reply-to: xsl-list at lists dot mulberrytech dot com
Dear Mr. Kay,
Thank you for your advice about the result tree fragments. I found that
feature very useful.
What is xx:node-set() ? Is it something portable?
I did it _without_ that function, as follows (comments welcome).
I find it nicer than the preceding way, but I still dislike my [@id>=current()/@id] condition.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Following Michael Kay's advice on result tree fragments -->
<xsl:variable name="allphotos">
<xsl:apply-templates select="/fotos/foto" mode="identity">
<xsl:sort order="ascending" select="@id" data-type="number" />
</xsl:apply-templates>
<foto id="100000000000" dummy="logo" src="logo.gif" href="http://homepage" />
<foto id="100000000001" dummy="yes" />
<foto id="100000000002" dummy="yes" />
<foto id="100000000003" dummy="yes" />
<foto id="100000000004" dummy="yes" />
<foto id="100000000005" dummy="yes" />
<foto id="100000000006" dummy="yes" />
<foto id="100000000007" dummy="yes" />
</xsl:variable>
<!-- A template to assist in sorting -->
<xsl:template match="foto" mode="identity">
<foto id="{@id}" />
</xsl:template>
<!-- Main template -->
<xsl:template match="/">
<html><body>
<table border="0" cellpadding="0" cellspacing="0">
<!-- Instead of (@id mod 8) I prefer (position() mod 8), as it allows id holes -->
<!-- A row never starts on a dummy="yes" photo. However, it may start by a dummy="logo" -->
<xsl:for-each select="$allphotos/foto[(position() mod 8) = 1 and not(@dummy='yes')]">
<tr>
<!-- Transform the <foto/> elements into <td/> elements with the right content (3 different templates) -->
<!-- Output on each row the first eight foto elements with an id greater or equal than the first in the row -->
<xsl:apply-templates select="$allphotos/foto[@id>=current()/@id][8>=position()]" mode="td" />
</tr>
</xsl:for-each>
</table>
</body></html>
</xsl:template>
<xsl:template match="foto[not(@dummy)]" mode="td">
<td><a href="{@id}.jpg"><img border="0" src="{@id}.small.jpg" /></a></td>
</xsl:template>
<xsl:template match="foto[@dummy='yes']" mode="td">
<td> </td>
</xsl:template>
<xsl:template match="foto[@dummy='logo']" mode="td">
<td><a href="{@href}"><img border="0" src="{@src}" /></a></td>
</xsl:template>
</xsl:stylesheet>
I post it here because someone might find it useful. Feel free to use it
if that's your case.
Antonio
Michael Kay wrote:
Better to do the transformation in two phases: sorting first, then
grouping. The intermediate results go on a temporary tree ("result tree
fragment") which you can access using the xx:node-set() extension
function.
You could add the dummy photos into the intermediate result during the
sort phase, to simplify the logic of the grouping phase. Sort the union
of the actual photos and xx:node-set($dummy-photos/*[position() < 8 -
($num-photos mod 8)], or something similar, where $dummy-photos is
something like
<xsl:variable name="dummy-photos">
<foto id="100000000000000000000" dummy="yes"/>
<foto id="100000000000000000001" dummy="yes"/>
.. repeated 8 times ..
</xsl:variable>
Michael Kay
Software AG
home: Michael.H.Kay@ntlworld.com
work: Michael.Kay@softwareag.com
-----Original Message-----
From: owner-xsl-list@lists.mulberrytech.com
[mailto:owner-xsl-list@lists.mulberrytech.com] On Behalf Of
Antonio Fiol
Sent: 12 June 2002 10:01
To: xsl-list@lists.mulberrytech.com
Subject: [xsl] Making groups of N elements --> Photo index
Hello,
The following stylesheet does what I need, but I find it very ugly.
The idea is that I have an unsorted XML source as:
<fotos>
<foto id="3" />
<foto id="1" />
<foto id="2" />
...
<foto id="NNN" />
</fotos>
The quantity of <foto/> is not determined.
I would like to generate a "photo index", i.e. a picture containing
small versions of all photos, arranged by rows of 8 photos.
I can make it dynamically adaptable by simply sticking the
photos one to
the other, but I'd prefer to have the image arranged as a table, with
eight cells per row.
Additionally, I would like to add blank cells at the end so that the
last row is complete.
Eventually (not done on this stylesheet), I may want to add a "logo"
image at the end, as if one more photo was present on the XML source.
Here's the "beast":
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="/">
<html><body>
<table border="0" cellpadding="0" cellspacing="0">
<xsl:for-each select="fotos/foto[(@id mod 8) = 1]">
<xsl:sort order="ascending" select="@id" data-type="number" />
<tr>
<xsl:apply-templates
select="../foto[@id>=current()/@id][current()/@id+8>@id]">
<xsl:sort order="ascending" select="@id" data-type="number" />
</xsl:apply-templates>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][1])">
<td> </td>
</xsl:if>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][2])">
<td> </td>
</xsl:if>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][3])">
<td> </td>
</xsl:if>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][4])">
<td> </td>
</xsl:if>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][5])">
<td> </td>
</xsl:if>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][6])">
<td> </td>
</xsl:if>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][7])">
<td> </td>
</xsl:if>
<xsl:if
test="not(../foto[@id>=current()/@id][current()/@id+8>@id][8])">
<td> </td>
</xsl:if>
</tr>
</xsl:for-each>
</table>
</body></html>
</xsl:template>
<xsl:template match="foto">
<td><a href="{@id}.jpg"><img border="0"
src="{@id}.small.jpg" /></a></td> </xsl:template>
</xsl:stylesheet>
Comments on what I dislike:
I dislike using [(@id mod 8) = 1], but I am afraid I cannot
do that much
differently.
I dislike the ../[@id>=current()/@id][current()/@id+8>@id] couple of
conditions which give me the eight <foto/> that are to be in the same
row as the first one. I am pretty sure that it can be done better.
But what I especially dislike (like in hate) the way I completed the
last (or any photo-missing intermediate) row. That is, the
eight xsl:if
conditions that fill the right of the row.
Moreover, I dislike the fact that I count on the IDs not only
for order
but also for placement. I would like to be able to remove a
photo if I
wish, without changing the other photo's ID.
So, for this last reason, I'm afraid a serious change has to
be done to
the stylesheet. But I could not think of how to do it when I
wrote the
stylesheet yesterday.
Any hints? Maybe keys may help? If so, how?
Thank you very much.
Antonio Fiol
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
.
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list