[xsl] How to sort by elements of a function output?

Subject: [xsl] How to sort by elements of a function output?
From: Leo Studer <leo.studer@xxxxxx>
Date: Fri, 24 Apr 2009 18:04:39 +0200
Hello

I am using Saxon-SA9.1.0.6 to transform the following XML file:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="results1.xsl"?>

<results>
    <match date="1998-06-10">
        <team score="2">Brazil</team>
        <team score="1">Scotland</team>
    </match>
    <match date="1998-06-10">
        <team score="2">Morocco</team>
        <team score="2">Norway</team>
    </match>
    <match date="1998-06-16">
        <team score="1">Scotland</team>
        <team score="1">Norway</team>
    </match>
    <match date="1998-06-16">
        <team score="3">Brazil</team>
        <team score="0">Morocco</team>
    </match>
    <match date="1998-06-23">
        <team score="1">Brazil</team>
        <team score="2">Norway</team>
    </match>
    <match date="1998-06-23">
        <team score="0">Scotland</team>
        <team score="3">Morocco</team>
    </match>
</results>


with the stylesheet



<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform "
xmlns:fn="http://www.w3.org/2005/xpath-functions";
xmlns:xs="http://www.w3.org/2001/XMLSchema";
xmlns:my="http://leostuder.ch";
xmlns="http://www.w3.org/1999/xhtml";
exclude-result-prefixes="fn xs my">


<xsl:output method="xhtml" encoding="ISO-8859-1" indent="yes"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd "/>


<xsl:import-schema namespace="http://www.w3.org/1999/xhtml";
schema-location="http://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd "/>


<xsl:function name="my:MakeTableRow">
<xsl:param name="team"/>
<xsl:param name="matches"/>
<tr>
<td>
<xsl:value-of select="$team"/>
</td>
<td>
<xsl:value-of select="fn:count($matches)"/>
</td>
<xsl:variable name="won"
select="fn:count($matches[team[.=$team]/@score gt team[.!=$team]/@score])"
as="xs:integer"/>
<td>
<xsl:value-of select="$won"/>
</td>
<td>
<xsl:value-of
select="fn:count($matches[team[.=$team]/@score lt team[.!=$team]/@score])"/>
</td>
<xsl:variable name="drawn"
select="fn:count($matches[team[.=$team]/@score eq team[.!=$team]/@score])"
as="xs:integer"/>
<td>
<xsl:value-of select="$drawn"/>
</td>
<td>
<xsl:value-of select="fn:sum($matches/team[.=$team]/ @score)"/>
</td>
<td>
<xsl:value-of select="fn:sum($matches/team[.!=$team]/ @score)"/>
</td>
<td>
<xsl:value-of select="3*$won+$drawn"/>
</td>
</tr>
</xsl:function>


    <xsl:template match="/">
        <html xsl:validation="strict">
            <head>
                <title>Spielresultate</title>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="results">
        <h2>Results</h2>

        <table cellpadding="10">
            <thead>
                <tr>
                    <td>Team</td>
                    <td>Played</td>
                    <td>Won</td>
                    <td>Lost</td>
                    <td>Drawn</td>
                    <td>For</td>
                    <td>Against</td>
                    <td>Points</td>
                </tr>
            </thead>

<xsl:for-each-group select="/results/match" group- by="team">
<xsl:variable name="tableRow" select="my:MakeTableRow(current-grouping-key(),current-group())"/>
<xsl:copy-of select="$tableRow"/>
</xsl:for-each-group>


</table>

</xsl:template>

</xsl:stylesheet>



In the tag <xsl:for-each-group select="/results/match" group-by="team">
I would like to sort the outcome by the $tableRow/td[8] contents (i.e. the points) .
How do I do that?


The approach

<xsl:for-each-group select="/results/match" group-by="team">
<xsl:sort select="my:MakeTableRow(current-grouping- key(),current-group())/td[8]"
order="descending"/>
<xsl:copy-of select="my:MakeTableRow(current-grouping- key(),current-group())"/>
</xsl:for-each-group>


does not do the job, no error however. Calling the function my:MakeTableRow twice seems also quite off...

Any suggestions?

Thanks in advance
Leo

Current Thread