Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSLT 1.0 sort elements

Tags:

sorting

xml

xslt

I have the following XML document:

<?xml version="1.0" encoding="UTF-8"?>
<objects>
    <object>Clutch</object>
    <object>Gearbox</object>
    <object>Cylinder head</object>
    <object>Starter</object>
    <object>Airbox</object>
    <object>Inlet manifold</object>
</objects>

And the following XSLT document:

<?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" indent="yes"/>

    <xsl:template match="objects">
        <parts>
            <xsl:apply-templates>
                <xsl:sort select="object"/>
            </xsl:apply-templates>
        </parts>
    </xsl:template>

    <xsl:template match="object">
        <part>
            <xsl:apply-templates/>
        </part>
    </xsl:template>

</xsl:stylesheet>

When applied I am getting the following output as expected, but it is not being sorted:

<?xml version="1.0" encoding="UTF-8"?>
<parts>
    <part>Clutch</part>
    <part>Gearbox</part>
    <part>Cylinder head</part>
    <part>Starter</part>
    <part>Airbox</part>
    <part>Inlet manifold</part>
</parts>

Why is the <xsl:sort select="object"/> not being applied ?

like image 511
general exception Avatar asked Jul 17 '12 12:07

general exception


1 Answers

The reason is here:

      <parts>
          <xsl:apply-templates>
              <xsl:sort select="object"/>
          </xsl:apply-templates>
      </parts>

This applies templates to the children (object) of the current node (objects) and sorts them by the string value of their first object child.

However in the provided XML document an object doesn't have any object children -- so they all have the same sort-key -- the empty string -- and their original order isn't changed by the sort operation.

Solution:

        <parts>
            <xsl:apply-templates>
                <xsl:sort select="."/>
            </xsl:apply-templates>
        </parts>

The complete transformation becomes:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="objects">
    <parts>
     <xsl:apply-templates>
        <xsl:sort select="."/>
     </xsl:apply-templates>
    </parts>
 </xsl:template>

 <xsl:template match="object">
  <part>
     <xsl:apply-templates/>
  </part>
 </xsl:template>
</xsl:stylesheet>

and when it is applied to the provided XML document:

<objects>
    <object>Clutch</object>
    <object>Gearbox</object>
    <object>Cylinder head</object>
    <object>Starter</object>
    <object>Airbox</object>
    <object>Inlet manifold</object>
</objects>

the wanted, correct result is produced:

<parts>
   <part>Airbox</part>
   <part>Clutch</part>
   <part>Cylinder head</part>
   <part>Gearbox</part>
   <part>Inlet manifold</part>
   <part>Starter</part>
</parts>
like image 176
Dimitre Novatchev Avatar answered Sep 24 '22 09:09

Dimitre Novatchev