3

I'm trying to find a solution to the following problem.

I'm developing XSLT transformation (which is now about 40KB big) that is transforming quite complex XMLs into a quite simple structure which would like this:

<Records>
<Record key="XX">
</Record> 
<Record key="XX1">
</Record>
<Record key="XX2">
</Record>
<Record key="XX3">
</Record>
</Records>

I would like to have this output XML sorted according to Records/Record/@key values. The problem is that my XSLT produces this output unsorted and due to its complexity I am unable to sort it there. Is it possible to apply xsl:sort on the output XML? I know that I can prepare another XSLT transform, but in my case that's not the solution, as I'm limited to only one XSLT.. Please, help!...

0

3 Answers 3

3

Is it possible to apply xsl:sort on the output XML?

Yes, multipass processing is possible, and especially in XSLT 2.0 you don't even need to apply an xxx:node-set() extension on the result, because the infamous RTF type does no longer exist:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:variable name="vPass1">
   <!--
        Put/Invoke your cirrent code here   
        to generate the following           
-->
    <Records>
      <Record key="XX3">
      </Record>
      <Record key="XX2">
      </Record>
      <Record key="XX4">
      </Record>
      <Record key="XX1">
      </Record>
    </Records>
  </xsl:variable>

  <xsl:apply-templates select="$vPass1/*"/>
 </xsl:template>

 <xsl:template match="Records">
  <Records>
   <xsl:perform-sort select="*">
    <xsl:sort select="@key"/>
   </xsl:perform-sort>
  </Records>
 </xsl:template>
</xsl:stylesheet>

When this transformation is performed on any XML document (not used/ignored), the wanted, correct, sorted result is produced:

<Records>
   <Record key="XX1"/>
   <Record key="XX2"/>
   <Record key="XX3"/>
   <Record key="XX4"/>
</Records>

In XSLT 1.0 it is almost the same with the additional conversion of the result from RTF type to a normal tree:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 exclude-result-prefixes="ext">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <!--
        Put/Invoke your cirrent code here   
        to generate the following           
-->
    <Records>
      <Record key="XX3">
      </Record>
      <Record key="XX2">
      </Record>
      <Record key="XX4">
      </Record>
      <Record key="XX1">
      </Record>
    </Records>
  </xsl:variable>

  <xsl:variable name="vPass1"
                select="ext:node-set($vrtfPass1)"/>

  <xsl:apply-templates select="$vPass1/*"/>
 </xsl:template>

 <xsl:template match="Records">
  <Records>
   <xsl:for-each select="*">
    <xsl:sort select="@key"/>

    <xsl:copy-of select="."/>
   </xsl:for-each>
  </Records>
 </xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

5 Comments

thanks a lot for the answer.. I was trying to execute the first sample code, but it doesn't seem to work. It doesn't produce anything... .All in all, I get the idea. I'll keep on trying to figure it out by myself.
@LukaszBaran: How do you think I produced this code? I always test my code before publishing it. Actually, what you see as "Result" is always copied and pasted from the actual result in my test. If you have any problem in executing the first solution, this most probably means you didn't run it with an XSLT 2.0 processor. Get yourself one and try again. It is also possible that you replaced the comment with your code, and your code has templates that match the same nodes (the document-node() for example). It is always safer to put all code for a given pass in a named mode, for example "mPass1".
Right. I think this was caused by Xalan which I'm using for XSLT transformation.
@LukaszBaran: So, in this case you must use the XSLT 1.0 solution. If EXSLT isn't available, use Xalan's native extension function xxx:nodeset()
OK, it works! I have applied the latest version of Saxon. Thanks a lot, +1 and I'm accepting this solution.
3

40Kb is a lot of code for one stylesheet. When things get to this kind of scale, it's usually best to split a transformation into a pipeline of smaller transformations. If you have such a pipeline architecture, then adding a sort step at the end is trivial. There are plenty of technologies for managing a pipeline of transformations (XProc, Orbeon, xmlsh, ant, Coccoon) depending on your requirements. The benefit of pipelining is that it keeps your code modular and reusable.

Comments

1

As an addendum to Dimitre's excellent solution above, if you're using an XSLT 1.0 processor (for example, .NET), the following can give you a pointer as to how to use node-set: http://www.xml.com/pub/a/2003/07/16/nodeset.html#tab.namespaces

In my case, I was in .NET 1.1 (i.e. MSXML) and the solution looked something like:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:template match="/">            
        <xsl:variable name="vrtfPass1">
            <Records xmlns="">  
                    <xsl:apply-templates />
            </Records >            
        </xsl:variable>
        <xsl:variable name="vPass1" select="msxsl:node-set($vrtfPass1)"/>
        <xsl:apply-templates select="$vPass1/*" mode="sorting"/>
    </xsl:template>
    <xsl:template match="Records" mode="sorting">
        <Records>
       <xsl:for-each select="Record">
        <xsl:sort select="@key"/>
        <xsl:copy-of select="."/>
       </xsl:for-each>
      </Records>
    </xsl:template>
</xsl:stylesheet>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.