sorting and filtering oh my!

S

snafu7x7

Hope someone in here can help me with this one, its got me stumped.

I have XML data for a CD collection and a stylesheet that I have setup
to sort it as need be (i.e. by artist, by album name, etc). However,
since the library is rather large I want the stylesheet to be able to
accept parameters for a range of items to return (say the first 100,
or the last 50, or whatever). How can I accomplish this in conjunction
with my sorting?

Here is some sample XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<library>
<album>
<ID>1234</ID>
<Name><![CDATA[Paul's Boutique]]></Name>
<Artist><![CDATA[The Beastie Boys]]></Artist>
<Genre><![CDATA[Rap/Hip-Hop]]></Genre>
<Rating>8.5</Rating>

</album>

<album>
<ID>5678</ID>
<Name><![CDATA[Document]]></Name>
<Artist><![CDATA[R.E.M]]></Artist>
<Genre><![CDATA[Rock]]></Genre>
<Rating>7</Rating>

</album>

<album>
<ID>9988</ID>
<Name><![CDATA[Kind Of Blue]]></Name>
<Artist><![CDATA[Miles Davis]]></Artist>
<Genre><![CDATA[Jazz]]></Genre>
<Rating>8.9</Rating>

</album>

</library>


And my stylesheet (note the variables I have declared for start and
end index):

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:eek:utput encoding="utf-8" method="xml" indent="yes"/>

<xsl:param name="startIndex" select="0" />
<xsl:param name="endIndex" select="10" />

<xsl:template match="library">

<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="text" select="Artist" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>

</xsl:template>

<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

</xsl:stylesheet>
 
J

Joe Kesselman

snafu7x7 said:
since the library is rather large I want the stylesheet to be able to
accept parameters for a range of items to return (say the first 100,
or the last 50, or whatever). How can I accomplish this in conjunction
with my sorting?

Interesting question.

If you look at the spec's example of numbering
(http://www.w3.org/TR/xslt#number), you'll see that position() within
the body of a for-each reports the position *after* sorting. So that's
one approach -- for-each over the sorted set, test position(), and only
apply-templates if the position is within the range you're interested in.

There are probably a dozen other ways to accomplish this. I'd suggest
checking the sorting section of the XSLT FAQ website -- wonderful
resource! -- and possibly other related sections as well, to see if
someone has contributed a more elegant solution.
 
P

Pavel Lepin

Joe Kesselman said:
If you look at the spec's example of numbering
(http://www.w3.org/TR/xslt#number), you'll see that
position() within the body of a for-each reports the
position *after* sorting. So that's one approach --
for-each over the sorted set, test position(), and only
apply-templates if the position is within the range you're
interested in.

I'm probably missing your point, but the same applies to
template matches (which seems only natural to me, since
both xsl:for-each and xsl:apply-templates define an
ordering on the current node list when invoked with
xsl:sort).

pavel@debian:~/dev/xslt$ a sortpos.xml
<data>
<elt-0 sort="0"/>
<elt-1 sort="2"/>
<elt-2 sort="7"/>
<elt-3 sort="1"/>
<elt-4 sort="6"/>
<elt-5 sort="8"/>
<elt-6 sort="3"/>
<elt-7 sort="4"/>
<elt-8 sort="9"/>
<elt-9 sort="5"/>
</data>
pavel@debian:~/dev/xslt$ a sortpos.xsl
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="limit" select="3"/>
<xsl:eek:utput indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<result>
<xsl:apply-templates select="*" mode="sort-limit">
<xsl:sort select="@sort"/>
</xsl:apply-templates>
</result>
</xsl:template>
<xsl:template match="@*|node()" mode="sort-limit">
<xsl:if test="position() &lt;= $limit">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
pavel@debian:~/dev/xslt$ xsltproc sortpos.xsl sortpos.xml
<?xml version="1.0"?>
<result>
<elt-0 sort="0"/>
<elt-3 sort="1"/>
<elt-1 sort="2"/>
</result>
pavel@debian:~/dev/xslt$
 
J

Joe Kesselman

Pavel said:
I'm probably missing your point, but the same applies to
template matches (which seems only natural to me, since
both xsl:for-each and xsl:apply-templates define an
ordering on the current node list when invoked with
xsl:sort).

Thought it might but hadn't checked, and depending on what the user
wants to do that might involve using modes to distinguish the cases
where the limit is to be checked from those where it shouldn't be.

As I said: XSLT is a programming language, so there are generally
multiple reasonable solutions to any "how can I" question.
 
J

Joe Kesselman

(... Yes, I know, the "avoid for-each" philosophy. I'm not dogmatic
about that.)
 
P

Pavel Lepin

Joe Kesselman said:
Thought it might but hadn't checked, and depending on what
the user wants to do that might involve using modes to
distinguish the cases where the limit is to be checked
from those where it shouldn't be.

As I said: XSLT is a programming language, so there are
generally multiple reasonable solutions to any "how can I"
question.

Joe Kesselman said:
(... Yes, I know, the "avoid for-each" philosophy. I'm not
dogmatic about that.)

No, that wasn't my point in this case, actually. :) It's
just that your explanation sounded (to me, at least) as if
position() takes ordering defined by xsl:sort into the
account only in context of xsl:for-each, so I wanted to
clarify that this applies whenever ordered current node
lists are involved.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,150
Members
46,696
Latest member
BarbraOLog

Latest Threads

Top