RE: [xsl] Problem with sort order

Subject: RE: [xsl] Problem with sort order
From: "Jacoby, Peter R." <PJACOBY@xxxxxxxxxxxx>
Date: Tue, 22 Aug 2006 16:18:23 -0400
Hi, Per,

One option for this type of problem is to do two passes.  The first pass
allows
you to make the necessary changes, and the second pass is used to sort.  This
allows you to separate the logic.  The one catch is that in XSLT 1.0 you need
to
use the node-set extension of your processor.

Here is an example of how you could do it (I used MSXML):

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";

xmlns:msxml="urn:schemas-microsoft-com:xslt"

exclude-result-prefixes="msxml">
<xsl:output method="xml" omit-xml-declaration="no" indent="no"
encoding="UTF-8"/>

<xsl:template match="/">
	<xsl:apply-templates select="animal"/>
</xsl:template>

<xsl:template match="animal">
	<xsl:copy>
		<xsl:apply-templates select="species" />
	</xsl:copy>
</xsl:template>

<xsl:template match="species">
	<xsl:variable name="changedList">
		<xsl:for-each select="name">
			<xsl:choose>
				<xsl:when test="@language = 'Danish'">
					<name language="Latin"><xsl:value-of
select="."/></name>
				</xsl:when>
				<xsl:otherwise>
					<xsl:copy-of select="." />
				</xsl:otherwise>
			</xsl:choose>
		</xsl:for-each>
	</xsl:variable>

	<xsl:copy>
		<xsl:apply-templates select="msxml:node-set($changedList)/name">
			<xsl:sort select="@language" data-type="text"
order="ascending" />
		</xsl:apply-templates>
	</xsl:copy>
</xsl:template>

<xsl:template match="name">
	<xsl:copy-of select="." />
</xsl:template>

</xsl:stylesheet>


I first create a variable (named changedList) that stores the result of the
changes.  Then I apply templates to that variable in order to sort and copy
the
results.

I'm sure there is a way to do it in one pass, but I'm not sure it's worth it
because this allows your logic at each pass to get as complicated as you want
without affecting the other part.

Hope this helps, let us know if you have questions about it.

-Peter

-----Original Message-----
From: Per Eberg [mailto:aberg.per@xxxxxxxx]
Sent: Tuesday, August 22, 2006 2:23 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: [xsl] Problem with sort order

Hi,

In my xslt file, I want to examine the attributes of the xml elements,
transform some of them (if needed), and then sort the output after the
attributes. My problem is that the transformed attributes become sorted
after their "ingoing" value instead of their new value. The following
invented example shows the problem. According to the xsl 1.0
specs the output of the transformation should be sorted, but here it seems
like the input is being sorted. Does anyone know how I can get it right?

Thanks in advance,
Per

The xml-file:

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="xslt_file.xsl"?>
<animal>
    <species>
        <name language="English">Wolf</name>
        <name language="Spanish">Lobo</name>
        <name language="Danish">Canis Lupus</name>
        <name language="French">Loup</name>
    </species>
</animal>

The xsl-file:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
    <xsl:output method="xml"/>
    <xsl:template match="/animal">
        <animal>
            <xsl:apply-templates select="species"/>
        </animal>
    </xsl:template>
    <xsl:template match="species">
        <species>
            <xsl:for-each select="name">
            <xsl:sort select="@language"/>
               <xsl:choose>
                    <xsl:when test="@language='Danish'">
                        <name language="Latin"><xsl:value-of
select="."/></name>
                    </xsl:when>
                    <xsl:otherwise>
                        <name language="{@language}"><xsl:value-of
select="."/></name>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </species>
    </xsl:template>
</xsl:stylesheet>

The output:

<animal>
     <species>
          <name language="Latin">Canis Lupus</name>
          <name language="English">Wolf</name>
          <name language="French">Loup</name>
          <name language="Spanish">Lobo</name>
     </species>
</animal>

The desired output:

<animal>
     <species>
          <name language="English">Wolf</name>
          <name language="French">Loup</name>
          <name language="Latin">Canis Lupus</name>
          <name language="Spanish">Lobo</name>
     </species>
</animal>

Current Thread