TAGS :Viewed: 1 - Published at: a few seconds ago

[ XSL: Sorting on a Hybrid XML File ]

I have an XML file which is an amalgam of two smaller XML files. While each of the two files has different enclosing tags, both have a particular field of the same name on which I would like to sort, using XSLT 1.0 only.

I have created the following XML / XSLT files to demonstrate the problem.

The desired output is: 1,2,3,4,5,6

But the actual output is: 1,3,5,2,4,6

In other words, each sub-file (<DataSet1> and<DataSet2>) is being sorted correctly, but the desired result is to have the file as a whole sorted correctly.

How can I correct this problem? (Please note that I cannot alter the XML file in any way below the level of <DataSet1> and<DataSet2>.)

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;xml-file&gt;
    &lt;DataSet1&gt;
        &lt;Table1&gt;
            &lt;Rank&gt;1&lt;/Rank&gt;
        &lt;/Table1&gt;
        &lt;Table1&gt;
            &lt;Rank&gt;5&lt;/Rank&gt;
        &lt;/Table1&gt;
        &lt;Table1&gt;
            &lt;Rank&gt;3&lt;/Rank&gt;
        &lt;/Table1&gt;
    &lt;/DataSet1&gt;
    &lt;DataSet2&gt;
        &lt;Table2&gt;
            &lt;Rank&gt;6&lt;/Rank&gt;
        &lt;/Table2&gt;
        &lt;Table2&gt;
            &lt;Rank&gt;2&lt;/Rank&gt;
        &lt;/Table2&gt;
        &lt;Table2&gt;
            &lt;Rank&gt;4&lt;/Rank&gt;
        &lt;/Table2&gt;
    &lt;/DataSet2&gt;
&lt;/xml-file&gt;

Here is the XSLT file I am using:

&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"&gt;

    &lt;xsl:template match="DataSet1|DataSet2"&gt;
        &lt;xsl:apply-templates&gt;
            &lt;xsl:sort select="Rank" order="ascending" /&gt;
        &lt;/xsl:apply-templates&gt;
    &lt;/xsl:template&gt;

    &lt;xsl:template match="Table1"&gt;
        &lt;xsl:value-of select="Rank"/&gt;&lt;br/&gt;
    &lt;/xsl:template&gt;

    &lt;xsl:template match="Table2"&gt;
        &lt;xsl:value-of select="Rank"/&gt;&lt;br/&gt;
    &lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

Answer 1


The problem with your approach is that this template:

<xsl:template match="DataSet1|DataSet2">

is actually instantiated twice - once for each DataSet. And each instance sorts it own nodes, so in the end you get two groups of Ranks, each sorted internally. Try instead:

<xsl:template match="/xml-file">
    <xsl:apply-templates select="DataSet1/Table1 | DataSet2/Table2">
        <xsl:sort select="Rank" data-type="number" order="ascending"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="Table1 | Table2">
    <xsl:value-of select="Rank"/><br/>
</xsl:template>

Or, if you prefer:

<xsl:template match="/xml-file">
    <xsl:apply-templates select="*/*/Rank">
        <xsl:sort select="." data-type="number" order="ascending"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="Rank">
    <xsl:value-of select="."/><br/>
</xsl:template>