sortingxslt

Issue with preserving the unsorted elements while using xsl:sort


My xsl:sort is sorting as expected but is not giving the desired output.

Here is my sample input xml

<ns3:ASC858_004010 xmlns:ns3="http://sap.com">
<root>
    <name1/>
    <name2/>
    <loops>
        <name3/>
        <loop mode="2">
            <counter>2</counter>
        </loop>
        <loop mode="1">
            <counter>1</counter>
        </loop>
        <name4/>
    </loops>
    <name5/>
</root>
</ns3:ASC858_004010>

my xslt is:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="loops">
    <xsl:copy>
        <xsl:apply-templates select="loop">
            <xsl:sort select="counter"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

and I am getting

<ns3:ASC858_004010 xmlns:ns3="http://sap.com">
<root>
    <name1/>
    <name2/>
    <loops>
        <loop mode="1">
            <counter>1</counter>
        </loop>
        <loop mode="2">
            <counter>2</counter>
        </loop>
    </loops>
    <name5/>
</root>
</ns3:ASC858_004010>

my desired output is

<ns3:ASC858_004010 xmlns:ns3="http://sap.com">
<root>
    <name1/>
    <name2/>
    <loops>
        <name3/>
        <loop mode="1">
            <counter>1</counter>
        </loop>
        <loop mode="2">
            <counter>2</counter>
        </loop>
        <name4/>
    </loops>
    <name5/>
</root>
</ns3:ASC858_004010>

The name3 and name4 are missing in their places. I have taken name3 and name4 just as a sample, but there could be many more elements before and after the "loop" structures within "loops".

What am I missing?


Solution

  • Use e.g.

    <xsl:template match="loops">
        <xsl:copy>
            <xsl:apply-templates select="loop[1]/preceding-sibling::*"/>
            <xsl:apply-templates select="loop">
                <xsl:sort select="counter"/>
            </xsl:apply-templates>
            <xsl:apply-templates select="loop[last()]/following-sibling::*"/>
        </xsl:copy>
    </xsl:template>
    

    That should work out if there are only non loop elements before and after all loop elements but not in between.