Search code examples
xsltxml-parsingxslt-1.0xslt-2.0

sorting records based on field value


For the below XML input based on the Type field we are doing the sorting and it is working as expected with below XSLT code.. but the header information is missing in the output XML.

XML input

<?xml version="1.0" encoding="UTF-8" ?>
 <root>
  <ID>134</ID>
   <Allocation>9</Allocation>
  <Year>2021</Year>
   <Access>

    <Code>12</Code>
    <PCode>13</PCode>
    <Type>IO</Type>
  </Access>
   <Access>
    
   <Code>15</Code>
    <PCode>16</PCode>
    <Type>IO</Type>
   </Access>

   <Access>
    <Code>19</Code>
    <PCode>20</PCode>
    <Type>MC</Type>
    </Access>
    <Access>
    <Code>22</Code>
    <PCode>25</PCode>
    <Type>MC</Type>
   </Access>
   <Access>
    <Code>30</Code>
    <PCode>31</PCode>
    <Type>IO</Type>
    </Access>
   <Access>
    <Code>35</Code>
    <PCode>36</PCode>
    <Type>IO</Type>
   </Access>
   </root>

XSLT Code

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

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

<xsl:template match="root">
<xsl:copy>

<xsl:apply-templates select="Access">
   
        <xsl:sort select="Type" datatype="number"/>
    </xsl:apply-templates>
  
   </xsl:copy>
</xsl:template>

 </xsl:stylesheet>

output XML

<?xml version="1.0"?>
 <root>
   <Access>

    <Code>12</Code>
    <PCode>13</PCode>
    <Type>IO</Type>
</Access>
  <Access>
    
   <Code>15</Code>
    <PCode>16</PCode>
    <Type>IO</Type>
</Access>
  <Access>
<Code>30</Code>
    <PCode>31</PCode>
    <Type>IO</Type>
</Access>
  <Access>
   <Code>35</Code>
    <PCode>36</PCode>
    <Type>IO</Type>
</Access>
  <Access>
    <Code>19</Code>
    <PCode>20</PCode>
    <Type>MC</Type>
    </Access>
   <Access>
    <Code>22</Code>
    <PCode>25</PCode>
    <Type>MC</Type>
</Access>
 </root>

In the above output xml header fields(ID,Allocation,Year) are missing. Please help me on this.


Solution

  • How about just:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/root">
        <xsl:copy>
            <xsl:copy-of select="ID | Allocation | Year"/>
            <xsl:for-each select="Access">
                <xsl:sort select="Type"/>
                <xsl:copy-of select="."/>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    If you don't want to list all the other elements explicitly, you can change:

    <xsl:copy-of select="ID | Allocation | Year"/>
    

    to:

    <xsl:copy-of select="*[not(self::Access)]"/>
    

    or (in XSLT 2.0) to:

    <xsl:copy-of select="* except Access"/>
    

    Note that your instruction:

    <xsl:sort select="Type" datatype="number"/>
    

    makes no sense because the Type values are not numbers.