xslt-2.0xslt-3.0

Issue in Sort only particular segments which is having duplicate values


I am trying to use XSLT to sort only specific segments when it is having same /header/doc/root/mat segments, if this case exist then //FIELD3 must be used as key to sort the entire segments, other segments we can keep in the same position which they belongs to, i have tried XSLT but its not giving me the output. please help me here.

Input

<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
   <DOC BEGIN="1"> 
          <EDI_40>
          <Field1>123</Field1>
          </EDI_40>   
          <E_E20>
         <ROOT SEGMENT="1">
            <POS>000020</POS>
            <MAT>1234</MAT>
            <FIELD3>4199</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>            
         </ROOT>   
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4199BI015</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN1</PQ>             
            </CHILD>            
         </ROOT>
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4184AI015</FIELD3>
            <QUAN>1026</QUAN>
           <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD> 
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD>            
         </ROOT>
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4200AI015</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN3</PQ>             
            </CHILD>           
         </ROOT>
              <ROOT SEGMENT="1">
            <POS>000030</POS>
            <MAT>123</MAT>
            <FIELD3>4200AI</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>           
         </ROOT>
         </E_E20>
   </DOC>
</HEADER>

**output **

<?xml version="1.0" encoding="UTF-8"?>
<HEADER>
   <DOC BEGIN="1">  
          <EDI_40>
          <Field1>123</Field1>
          </EDI_40>   
          <E_E20>
         <ROOT SEGMENT="1">
            <POS>000020</POS>
            <MAT>1234</MAT>
            <FIELD3>4199</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>            
         </ROOT> 

         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4184AI015</FIELD3>
            <QUAN>1026</QUAN>
           <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD> 
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN2</PQ>            
            </CHILD>            
         </ROOT>         
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4199BI015</FIELD3>
            <QUAN>3420</QUAN>
            <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN1</PQ>             
            </CHILD>            
         </ROOT>
         
         <ROOT SEGMENT="1">
            <POS>000010</POS>
            <MAT>123456</MAT>
            <FIELD3>4200AI015</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN3</PQ>             
            </CHILD>           
         </ROOT>
              <ROOT SEGMENT="1">
            <POS>000030</POS>
            <MAT>123</MAT>
            <FIELD3>4200AI</FIELD3>
            <QUAN>1197</QUAN>
             <CHILD SEGMENT="1">
               <POS>000010</POS>
               <PQ>UN</PQ>             
            </CHILD>           
         </ROOT>
          </E_E20>
   </DOC>
</HEADER>

XSLT I used

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//ROOT">
<ROOT>
<xsl:for-each select="distinct-values(//ROOT/@MAT)">
<xsl:sort select="." data-type="number"/>
<xsl:apply-templates select="//ROOT/FIELD3[@MAT = current()]"/>
</xsl:for-each>
</ROOT>
</xsl:template>
<xsl:template match="HEADER">
<xsl:copy/>
</xsl:template>
 
</xsl:stylesheet>

Solution

  • It not quite clear what you want but if you group by MAT and then sort each group by FIELD3 you might get what you want:

      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="DOC">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:for-each-group select="ROOT" group-by="MAT">
            <xsl:apply-templates select="current-group()">
              <xsl:sort select="FIELD3"/>
            </xsl:apply-templates>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
    

    Online fiddle using Saxon HE 12.

    For your edited sample it appears there is just a different container element for the ROOT elements, so you want

      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="E_E20">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:for-each-group select="ROOT" group-by="MAT">
            <xsl:apply-templates select="current-group()">
              <xsl:sort select="FIELD3"/>
            </xsl:apply-templates>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
    

    for that sample.