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]
Other format: [Raw text]

Re: Making groups of N elements --> Photo index


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>&#xa0;</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>&#xa0;</td>
</xsl:if>
<xsl:if test="not(../foto[@id>=current()/@id][current()/@id+8>@id][2])">
<td>&#xa0;</td>
</xsl:if>
<xsl:if test="not(../foto[@id>=current()/@id][current()/@id+8>@id][3])">
<td>&#xa0;</td>
</xsl:if>
<xsl:if test="not(../foto[@id>=current()/@id][current()/@id+8>@id][4])">
<td>&#xa0;</td>
</xsl:if>
<xsl:if test="not(../foto[@id>=current()/@id][current()/@id+8>@id][5])">
<td>&#xa0;</td>
</xsl:if>
<xsl:if test="not(../foto[@id>=current()/@id][current()/@id+8>@id][6])">
<td>&#xa0;</td>
</xsl:if>
<xsl:if test="not(../foto[@id>=current()/@id][current()/@id+8>@id][7])">
<td>&#xa0;</td>
</xsl:if>
<xsl:if test="not(../foto[@id>=current()/@id][current()/@id+8>@id][8])">
<td>&#xa0;</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


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