title: Multiple element/attribute sorting in XSL
body: <p>I am trying to sort several levels of data using a XSL document. I got it to work but it is using a bunch of recursion.  I am trying to avoid this because I figured using multiple sorts withing a single node shold have worked.  Is there a way to change the XSL below to be less recursive?  I am sorting on USER/USERID, then ROLE/@name and finally ACTIONINFO/@actionfrom</p>
  
  <p>Working Stylesheet:
      <br>
        
        </p>
  
  <pre><code>  &lt;xsl:template match="/"&gt;
      &lt;xsl:apply-templates select="USERACTIONINFO"/&gt;
    &lt;/xsl:template&gt;
  
    &lt;xsl:template match="USERACTIONINFO"&gt;
      &lt;xsl:copy&gt;
        &lt;xsl:for-each select="USER"&gt;
          &lt;xsl:sort select="USERID"/&gt;
          &lt;xsl:copy&gt;
            &lt;xsl:copy-of select="USERID" /&gt;
            &lt;xsl:for-each select="ROLE"&gt;
              &lt;xsl:sort select="@name"/&gt;
              &lt;xsl:copy&gt;
                &lt;xsl:copy-of select="@name" /&gt;
                &lt;xsl:apply-templates select="ACTIONINFO"&gt;
                  &lt;xsl:sort select="@actionfrom"/&gt;
                &lt;/xsl:apply-templates&gt;
              &lt;/xsl:copy&gt;
            &lt;/xsl:for-each&gt;
          &lt;/xsl:copy&gt;
        &lt;/xsl:for-each&gt;
      &lt;/xsl:copy&gt;
    &lt;/xsl:template&gt;
  
    &lt;xsl:template match="*|@*|text()"&gt;
      &lt;xsl:copy&gt;
        &lt;xsl:apply-templates select="*|@*|text()"&gt;
        &lt;/xsl:apply-templates&gt;
      &lt;/xsl:copy&gt;
    &lt;/xsl:template
  &lt;/xsl:stylesheet&gt;
  </code></pre>
  
  <p>Some XML to test with:</p>
  
  <pre><code> &lt;USERACTIONINFO &gt;
    &lt;USER&gt;
      &lt;USERID&gt;SSSUSER&lt;/USERID&gt;
      &lt;ROLE name="ZZ_UPD"&gt;
        &lt;ACTIONINFO  actionfrom="ZC"  /&gt;
        &lt;ACTIONINFO  actionfrom="AC"  /&gt;
      &lt;/ROLE&gt;
      &lt;ROLE name="QQ_UPD"&gt;
        &lt;ACTIONINFO  actionfrom="AZCC11"  /&gt;
        &lt;ACTIONINFO  actionfrom="ACC11"  /&gt;
      &lt;/ROLE&gt;
    &lt;/USER&gt;
    &lt;USER&gt;
      &lt;USERID&gt;AAAUSER&lt;/USERID&gt;
      &lt;ROLE name="PP_UPD"&gt;
        &lt;ACTIONINFO actionfrom="ZZADBENF"  /&gt;
      &lt;/ROLE&gt;
      &lt;ROLE name="PP_BOEE"&gt;
        &lt;ACTIONINFO actionfrom="BOM02"  /&gt;
      &lt;/ROLE&gt;
      &lt;ROLE name="PP_SS"&gt;
        &lt;ACTIONINFO actionfrom="AZDBENF"  /&gt;
        &lt;ACTIONINFO actionfrom="ADDBEN" /&gt;
      &lt;/ROLE&gt;
    &lt;/USER&gt;
  &lt;/USERACTIONINFO&gt;
  </code></pre>
  
  <p>Actual CORRECT output:</p>
  
  <pre><code>   &lt;USERACTIONINFO&gt;
    &lt;USER&gt;
      &lt;USERID&gt;AAAUSER&lt;/USERID&gt;
      &lt;ROLE name="PP_BOEE"&gt;
        &lt;ACTIONINFO actionfrom="BOM02" /&gt;
      &lt;/ROLE&gt;
      &lt;ROLE name="PP_SS"&gt;
        &lt;ACTIONINFO actionfrom="ADDBEN" /&gt;
        &lt;ACTIONINFO actionfrom="AZDBENF" /&gt;
      &lt;/ROLE&gt;
      &lt;ROLE name="PP_UPD"&gt;
        &lt;ACTIONINFO actionfrom="ZZADBENF" /&gt;
      &lt;/ROLE&gt;
    &lt;/USER&gt;
    &lt;USER&gt;
      &lt;USERID&gt;SSSUSER&lt;/USERID&gt;
      &lt;ROLE name="QQ_UPD"&gt;
        &lt;ACTIONINFO actionfrom="ACC11" /&gt;
        &lt;ACTIONINFO actionfrom="AZCC11" /&gt;
      &lt;/ROLE&gt;
      &lt;ROLE name="ZZ_UPD"&gt;
        &lt;ACTIONINFO actionfrom="AC" /&gt;
        &lt;ACTIONINFO actionfrom="ZC" /&gt;
      &lt;/ROLE&gt;
    &lt;/USER&gt;
  &lt;/USERACTIONINFO&gt;
  </code></pre>
  
  <p>What I thought I should be able to do but didn't work:</p>
  
  <pre><code>&lt;xsl:stylesheet version='1.0'
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;  
    &lt;xsl:output method="xml" indent="yes"/&gt;
    &lt;xsl:output omit-xml-declaration="yes"/&gt;
  
      &lt;xsl:template match="/"&gt;
      &lt;xsl:apply-templates select="USERACTIONINFO"/&gt;
    &lt;/xsl:template&gt;
  
    &lt;xsl:template match="USERACTIONINFO"&gt;
      &lt;xsl:copy&gt;
        &lt;xsl:apply-templates select="USER"&gt;
          &lt;xsl:sort select="USERID"/&gt;
          &lt;xsl:sort select="ROLE/@name"/&gt;
          &lt;xsl:sort select="ROLE/ACTIONINFO/@actionfrom"/&gt;
        &lt;/xsl:apply-templates&gt;
      &lt;/xsl:copy&gt;
    &lt;/xsl:template&gt;
  
    &lt;xsl:template match="*|@*|text()"&gt;
      &lt;xsl:copy&gt;
        &lt;xsl:apply-templates select="*|@*|text()"/&gt;
      &lt;/xsl:copy&gt;
    &lt;/xsl:template&gt;
  &lt;/xsl:stylesheet&gt;
  </code></pre>