Home > Mobile >  XSL apply-templates with sorting does not sort
XSL apply-templates with sorting does not sort

Time:05-18

I have an XML document

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <timeperiods>
        <timeperiod>
            <day>1</day>
            <period>1</period>
        </timeperiod>
        <timeperiod>
            <day>1</day>
            <period>2</period>
        </timeperiod>
        <timeperiod>
            <day>2</day>
            <period>1</period>
        </timeperiod>
        <timeperiod>
            <day>2</day>
            <period>2</period>
        </timeperiod>
    </timeperiods>
</document>

I am applying an XSL as follows

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:template match="/">
        <xsl:apply-templates select="/document/timeperiods">
            <xsl:sort select="number(period)" data-type="number" order="descending"/>
            <xsl:sort select="number(day)" data-type="number" order="descending"/>
        </xsl:apply-templates>
    </xsl:template>
    
    <xsl:template match="timeperiod">
        <xsl:value-of select="concat(period, '-', day, ' ')"/>
    </xsl:template>
</xsl:stylesheet>

I would expect that my template timeperiod would result in 1-1 1-2 2-1 2-2, but instead it results in 1-1 2-1 1-2 2-2, which is the original order in the XML file.

I played around with the number() function and the attributes data-type and order, but no matter which variant I applied, I am always getting the same result.

What am I missing here?

CodePudding user response:

There is only one element named timeperiods, and sorting a sequence of length one is not going to be useful.

You want to sort the timeperiod elements, so those are the ones you should select. You haven't given the context of the xsl:apply-templates instruction; obviously that will affect how you select them.

CodePudding user response:

To get a result like the one you expect, change:

    <xsl:apply-templates select="/document/timeperiods">
        <xsl:sort select="number(period)" data-type="number" order="descending"/>
        <xsl:sort select="number(day)" data-type="number" order="descending"/>
    </xsl:apply-templates>

to:

    <xsl:apply-templates select="/document/timeperiods/timeperiod">
        <xsl:sort select="period" data-type="number" order="ascending"/>
        <xsl:sort select="day" data-type="number" order="ascending"/>
    </xsl:apply-templates>

Or do simply:

XSLT 2.0

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
    
<xsl:template match="/document">
    <xsl:for-each select="timeperiods/timeperiod">
        <xsl:sort select="period" data-type="number" order="ascending"/>
        <xsl:sort select="day" data-type="number" order="ascending"/>
        <xsl:value-of select="period, day" separator="-"/>
        <xsl:text> </xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>
  • Related