sortingxslttemplate-matching

XSLT Sort on child subelements


I am trying to output this entire XML but with the EVENT elements sorted by ID. Being new to XSLT I thought I would still give it a try but after many attempts and reading other examples and how to guides I still can't get what I thought was a simple thing to work.

<?xml version="1.0" encoding="UTF-8"?>
<PublishWCWORKORDEROUT xmlns="http://www.xcessteel.com/maxo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creationDateTime="2021-05-10T08:23:18+00:00" transLanguage="EN" baseLanguage="EN" messageID="3116171.1620634998889850919" maxoVersion="7 6 20190514-1348 V7611-365" event="1">
  <WCWORKORDEROUTSet>
    <WORKORDER action="Replace">
      <ACTCATEGORY />
      <X_3857>1.1838832494481975E7</X_3857>
      <Y_3857>-2766476.1752903816</Y_3857>
      <SPEC>
        <ALNVALUE />
        <REFID xsi:nil="true" />
        <ASSETATTRID>ACCOUNT_NO</ASSETATTRID>
        <CHANGEBY>ADMIN</CHANGEBY>
      </SPEC>
      <SPEC>
        <ALNVALUE />
        <REFID xsi:nil="true" />
      </SPEC>
      <SPEC>
        <ALNVALUE />
        <REFID xsi:nil="true" />
        <ASSETATTRID>METER_LOCATION</ASSETATTRID>
      </SPEC>
      <EVENT>
        <ID>CCC333</ID>
        <WORKTYPE>UNPLANNED</WORKTYPE>
      </EVENT>
      <EVENT>
        <ID>AAA111</ID>
        <WORKTYPE>PLANNED</WORKTYPE>
      </EVENT>
      <EVENT>
        <ID>BBB222</ID>
        <WORKTYPE>SCHEDULED</WORKTYPE>
      </EVENT>
      <ASSIGNMENT>
        <AMCREW />
        <WPLABORID>209336</WPLABORID>
      </ASSIGNMENT>
      <WCWODETAILS>
        <REFID xsi:nil="true" />
        <CUSTOMERNAME />
        <WCREGION>SWR</WCREGION>
        <ID>96057400</ID>
      </WCWODETAILS>
    </WORKORDER>
  </WCWORKORDEROUTSet>
</PublishWCWORKORDEROUT>

I have tried with this XSLT but clearly it is not correct.

<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"/>

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

<xsl:template match="/PublishWCWORKORDEROUT">
    <xsl:copy>
        <xsl:apply-templates select="EVENT">
            <xsl:sort select="ID"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Solution

  • You have to declare the namespace xmlns="http://www.xcessteel.com/maxo" and then use that prefix in your match and the sorting could be done like this:

    EDIT on 2021-05-24 on 10:19: attribute action="Replace" was missing

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" 
      xmlns:maxo="http://www.xcessteel.com/maxo"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      
      <!-- identity transform -->
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="maxo:WORKORDER">
        <xsl:copy>
          <!-- Following line was missing -->
          <xsl:apply-templates select="@*"/>
          <xsl:apply-templates select="maxo:EVENT[1]/preceding-sibling::*"/>
          <xsl:apply-templates select="maxo:EVENT">
            <xsl:sort select="maxo:ID"/>
          </xsl:apply-templates>
          <xsl:apply-templates select="maxo:EVENT[ position()=last()]/following-sibling::*"/>
        </xsl:copy>
      </xsl:template>
      
    </xsl:stylesheet>
    

    And as an alternative, the following would work as well:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" 
      xmlns:maxo="http://www.xcessteel.com/maxo"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      
      <!-- identity transform -->
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="maxo:EVENT[not(preceding-sibling:: maxo:EVENT)]">
        <xsl:for-each select=".|following-sibling:: maxo:EVENT">
          <xsl:sort select="maxo:ID"/>
          <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
          </xsl:copy>
        </xsl:for-each>
        
      </xsl:template>
        
      <xsl:template match="maxo:EVENT[ preceding-sibling:: maxo:EVENT]"/>  
      
    </xsl:stylesheet>