This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
RE: sorting a subset of elements
- From: Jarno dot Elovirta at nokia dot com
- To: <xsl-list at lists dot mulberrytech dot com>
- Date: Thu, 22 Aug 2002 09:30:01 +0300
- Subject: RE: [xsl] sorting a subset of elements
- Reply-to: xsl-list at lists dot mulberrytech dot com
Hi,
> I have created an xml document with over 300 items sorted by
> price. For the
> internet I want to display all items, however for print I only want to
> display the 90 most expensive and i want them sorted
> alpabetically. I am
> not sure how to accomplish this.
You can't sort, filter and sort again with XSLT 1.0; using XSLT 1.1 or 2.0 you could sort the items into a variable and sort it again. So, either do two transformations, where you sort by price and filter in the first one, and sort by name in the second one; or write a recursive template that will select the first 50 most expensive items, but that will probably be quite inefficient, e.g. (should work)
<?xml version='1.0' encoding='UTF-8' ?>
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match="itemlist">
<xsl:copy>
<xsl:call-template name="max-n">
<xsl:with-param name="ns" select="item" />
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:copy-of select="." />
</xsl:template>
<xsl:template name="max-n">
<xsl:param name="ns" select="/.." />
<xsl:param name="selected" select="/.." />
<xsl:param name="n" select="50"/>
<xsl:choose>
<xsl:when test="not(count($ns) = 0) and count($selected) < $n">
<xsl:variable name="max">
<xsl:call-template name="max">
<xsl:with-param name="ns" select="$ns" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="tbs" select="$ns[@price = $max]" />
<xsl:call-template name="max-n">
<xsl:with-param name="ns" select="$ns[not(@price = $max)]" />
<xsl:with-param name="selected" select="$selected | $ns[@price = $max][position() < ($n + 1 - count($selected))]" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$selected">
<xsl:sort select="@description" />
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="max">
<xsl:param name="ns" select="/.." />
<xsl:choose>
<xsl:when test="count($ns) > 2">
<xsl:variable name="c" select="ceiling(count($ns) div 2)" />
<xsl:variable name="head">
<xsl:call-template name="max">
<xsl:with-param name="ns" select="$ns[position() <= $c]" />
</xsl:call-template>
</xsl:variable>
<xsl:variable name="tail">
<xsl:call-template name="max">
<xsl:with-param name="ns" select="$ns[position() > $c]" />
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$head > $tail">
<xsl:value-of select="$head" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$tail" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:when test="count($ns) > 1">
<xsl:choose>
<xsl:when test="$ns[1]/@price > $ns[2]/@price">
<xsl:value-of select="$ns[1]/@price" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$ns[2]/@price" />
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$ns/@price" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
But you do not want that with 300 items, especially if just about every item has a unique price; so go with the two (chained) transformations.
Cheers,
Jarno
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list