RE: [xsl] Sorting Problem

Subject: RE: [xsl] Sorting Problem
From: "Dev Chandramani" <devc33@xxxxxxxxxxx>
Date: Thu, 13 Sep 2001 00:02:52 +0100
Hi Joerg,

First of all I must thank you for all your help.
The solution you provided works wonderfully.
However, i still have a few problems.

I actually have more fields in my input xml doc i wish to extract and I am
having problems
doing so.

My xml doc is as follows :

<records>
	<pupil>
		<name>Smith</name>
		<school>Oxford</school>
		<town>Leeds</town>
		<index>1</index>
	</pupil>
	<pupil>
		<name>Jones</name>
		<school>Eton</school>
		<town>London</town>
		<index>1</index>
	</pupil>
	<pupil>
		<name>Johnson</name>
		<school>Eton</school>
		<town>London</town>
		<index>2</index>
	</pupil>
	<pupil>
		<name>Davis</name>
		<school>Oxford</school>
		<town>Manchester</town>
		<index>2</index>
	</pupil>
	<pupil>
		<name>Jones</name>
		<school>Oxford</school>
		<town>Glasgow</town>
		<index>3</index>
	</pupil>
	<pupil>
		<name>Jones</name>
		<school>Cambridge</school>
		<town>Liverpool</town>
		<index>1</index>
	</pupil>
	<pupil>
		<name>Davis</name>
		<school>Oxford</school>
		<town>Birmingham</town>
		<index>4</index>
	</pupil>
	<pupil>
		<name>Davis</name>
		<school>Cambridge</school>
		<town>Newcastle</town>
		<index>2</index>
	</pupil>
	<pupil>
		<name>Johnson</name>
		<school>Cambridge</school>
		<town>Newcastle</town>
		<index>3</index>
	</pupil>
</records>

The <town> field relates to where the pupil lives.
The <index> field is incremented per individual school.
So as well as sorting the records by name and then ordering by school using
the valuation field, I also
want to pull out <town> field.

So for the above data I want to format the output as follows
(using the valuations you gave each school before) :

<records>
	<pupil>
		<name>Jones</name>
		<school>Cambridge</school>
		<town>Liverpool</town>
	</pupil>
	<pupil>
		<name>Davis</name>
		<school>Cambridge</school>
		<town>Newcastle</town>
	</pupil>
	...
</records>

So for if a <name> occurs many times I want the <school> field using the
valuations and I also want the corresponding <town> field from the
<pupil> record that matches the <name> and <school> field.
The first matching <town> field will do.
I know i may be appearing a bit cheeky now but for the <name>
fields that only occur once I want them to be ordered using the <index>
field and then the <school> field using the valuations.
i.e so all the indexes of 1 appear first ordere by school valuation, then
all the 2's appear ordered by school valuation.

I know I may be asking a lot of you so tell me if I'm asking too much.
Its just that I'm pretty new to XSL and i'm fascinated by how much
can be achieved by it.

Thanks again for all your help.

Regards,
Dev.

-----Original Message-----
From: owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx
[mailto:owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx]On Behalf Of Jörg Heinicke
Sent: 12 September 2001 22:46
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Sorting Problem


Hi Dev,

I think I understood: You want to know the "highest" school, which a pupil
with this or that name attends.

I build a dynamical version, I hope it was not to much "fun-work". I added
the ranking-information to the XML like the following:

<records>
    <pupil/>
    ...
    <schools>
        <school valuation="1">Cambridge</school>
        <school valuation="2">Oxford</school>
        <school valuation="3">Eton</school>
    </schools>
</records>

You can put this information to an extra-file or anywhere you want, you only
must adapt the stylesheet then.

Furthermore I don't know if it's a very nice solution, maybe somebody has a
better one.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.0">
    <xsl:output indent="yes"/>
    <xsl:key name="pupils" match="pupil" use="name"/>

    <xsl:template match="records">
        <xsl:copy>
            <xsl:apply-templates
select="pupil[count(.|key('pupils',name)[1])=1]">
                <xsl:sort select="count(key('pupils',name))"
order="descending"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="pupil">
        <xsl:copy>
            <xsl:apply-templates select="name"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="name">
        <xsl:copy>
            <xsl:value-of select="."/>
        </xsl:copy>
        <school>
            <xsl:call-template name="getSchool">
                <xsl:with-param name="schools">
                    <xsl:for-each select="key('pupils',.)/school">
                        <xsl:value-of select="text()"/>
                    </xsl:for-each>
                </xsl:with-param>
            </xsl:call-template>
        </school>
    </xsl:template>

    <xsl:template name="getSchool">
        <xsl:param name="schools"/>
        <xsl:param name="valuation" select="'1'"/>
        <xsl:choose>
            <xsl:when
test="contains($schools,/records/schools/school[@valuation=$valuation])">
                <xsl:value-of
select="/records/schools/school[@valuation=$valuation]"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="getSchool">
                    <xsl:with-param name="schools" select="$schools"/>
                    <xsl:with-param name="valuation" select="$valuation +
1"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Do you understand the stylesheet? The working with keys, especially the
'count(.|key('pupils',name)[1])=1'-construct? This is the 'grouping using
the muenchian method'. More information on this you can find here:
http://www.jenitennison.com/xslt/grouping/muenchian.html.

Hope this helps for the first.

Joerg


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread