Geert Josten wrote:
> Hi,
>
> Your expression "//book[(bookshelf =
> $bookshelfVar)]/author[not(.=preceding::author)]" is too strict (the
> predicate too tolerant). You need to limit the preceding::author part to
> match only authors that are on the same bookshelf. Similar thing for the
> publisher. :-)
Yes, that was it! Thanks very much for spotting the error--I just
couldn't figure out the needed logic and syntax for this. Our code
works now.
My example was contrived for the real problem I was trying to solve, but
for the benefit of others, this was the syntax I used:
<xsl:for-each select="//book[(./bookshelf =
$bookshelfVar)]/author[not(.=preceding::author[../bookshelf=$bookshelfVar])]">
<xsl:for-each select="//book[(./bookshelf = $bookshelfVar) and
(./author =
$authorVar)]/publisher[not(.=preceding::publisher[../author=$authorVar
and ../bookshelf=$bookshelfVar])]">
>
> Besides, I would recommend trying to use keys and grouping techniques
> like the Muenchian method. Something like:
>
Yes, I figured the Muenchian method would be *much* more efficient
anyway (for my work, we can have up to 5000 "books") but I was concerned
about not even being able to get the basic solution to work. I've done
Muenchian sorting once before for a two-level situation but not three so
I must appreciate the detailed solution you provided below. (Thanks
also for showing a cleaner way to handle carriage returns, leading
hyphens, etc.) I will be switching to this method next.
Regards,
Glen
Geert Josten wrote:
Actually, I meant something like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="bookshelves" match="bookshelf" use="." />
<xsl:key name="authors" match="author" use="concat(../bookshelf,
'-', .)" />
<xsl:key name="publishers" match="publisher" use="concat(../bookshelf,
'-', ../author, '-', .)" />
<xsl:template match="books">
<xsl:apply-templates select="book/bookshelf">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="bookshelf">
<xsl:if test="generate-id(.) = generate-id(key('bookshelves',
.)[1])">
<xsl:variable name="bookshelfVar" select="."/>
<xsl:variable name="authorVar" select="../author"/>
<xsl:text> </xsl:text>
<xsl:value-of select="."/>
<xsl:apply-templates select="/books/book[(bookshelf =
$bookshelfVar)]/author">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="author">
<xsl:if test="generate-id(.) = generate-id(key('authors',
concat(../bookshelf, '-', .))[1])">
<xsl:variable name="bookshelfVar" select="../bookshelf"/>
<xsl:variable name="authorVar" select="."/>
<xsl:text> --</xsl:text>
<xsl:value-of select="."/>
<xsl:apply-templates select="/books/book[(bookshelf =
$bookshelfVar) and (author = $authorVar)]/publisher">
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="publisher">
<xsl:if test="generate-id(.) = generate-id(key('publishers',
concat(../bookshelf, '-', ../author, '-', .))[1])">
<xsl:text> ----</xsl:text>
<xsl:value-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
It replaces // by explicit paths and preceding axis by keyed indexes..
Kind regards,
Geert
Drs. G.P.H. Josten
Consultant
Daidalos BV
Source of Innovation
Hoekeindsehof 1-4
2665 JZ Bleiswijk
Tel.: +31 (0) 10 850 1200
Fax: +31 (0) 10 850 1199
www.daidalos.nl
KvK 27164984
De informatie - verzonden in of met dit emailbericht - is afkomstig van
Daidalos BV en is uitsluitend bestemd voor de geadresseerde. Indien u dit
bericht onbedoeld hebt ontvangen, verzoeken wij u het te verwijderen. Aan dit
bericht kunnen geen rechten worden ontleend.
Van: Geert Josten [mailto:geert(_dot_)josten(_at_)daidalos(_dot_)nl]
Verzonden: donderdag 5 oktober 2006 8:13
Aan: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Onderwerp: RE: [xsl] Showing unique rows at multiple levels
Hi,
Your expression "//book[(bookshelf =
$bookshelfVar)]/author[not(.=preceding::author)]" is too
strict (the predicate too tolerant). You need to limit the
preceding::author part to match only authors that are on the
same bookshelf. Similar thing for the publisher. :-)
Besides, I would recommend trying to use keys and grouping
techniques like the Muenchian method. Something like:
(at top-level)
<xsl:key name="bookshelfs" match="bookshelf" use="." />
<xsl:key name="authors" match="author"
use="concat(../bookshelf, '-', .)" />
(inside bookshelf template)
<xsl:for-each select="key('bookshelfs', .)[1]">
...
</xsl:for-each>
(inside author template)
<xsl:for-each select="key('authors', concat(../bookshelf, '-', .)[1]">
...
</xsl:for-each>
Probably a lot quicker if your data file becomes larger.
Using // is usually very expensive in that case..
Kind regards,
Geert
--~------------------------------------------------------------------
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>
--~--