tags:

views:

25

answers:

2

The XML within the 'formslist' variable is created using apply-templates. This snippet is from a 2.0 stylesheet.

<xsl:variable name="formlist">
    <forms>
     <FORM form_name="form1" print_seq="1200"/>
     <FORM form_name="form2" print_seq="1500"/>
     <FORM form_name="form3" print_seq="9000"/>
     <FORM form_name="form4" print_seq="5500"/>
    </forms>
</xsl:variable>

    <xsl:for-each select="$formslist/*">
     <xsl:sort select="FORM/@print_seq"/>
     <xsl:copy-of select="."/>
   </xsl:for-each>  

The XML outputs ok but it is not sorted by print_seq

A: 

That's because $formslist/* selects forms element.

You could declare $formlist as:

<xsl:variable name="formlist" as="element()"> 
    <forms> 
     <FORM form_name="form1" print_seq="1200"/> 
     <FORM form_name="form2" print_seq="1500"/> 
     <FORM form_name="form3" print_seq="9000"/> 
     <FORM form_name="form4" print_seq="5500"/> 
    </forms> 
</xsl:variable> 

But you will loose the forms element in the copy.

Other solution will be an identity rule with sorting. This stylesheet:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:variable name="formlist">
        <forms>
            <FORM form_name="form1" print_seq="1200"/>
            <FORM form_name="form2" print_seq="1500"/>
            <FORM form_name="form3" print_seq="9000"/>
            <FORM form_name="form4" print_seq="5500"/>
        </forms>
    </xsl:variable>
    <xsl:template match="/">
        <xsl:apply-templates select="$formlist" mode="copy"/>
    </xsl:template>
    <xsl:template match="node()|@*" mode="copy">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" mode="copy">
                <xsl:sort select="self::FORM/@print_seq"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Output:

<forms>
    <FORM form_name="form1" print_seq="1200"/>
    <FORM form_name="form2" print_seq="1500"/>
    <FORM form_name="form4" print_seq="5500"/>
    <FORM form_name="form3" print_seq="9000"/>
</forms>
Alejandro
A: 
<xsl:variable name="formlist">    
    <forms>    
     <FORM form_name="form1" print_seq="1200"/>    
     <FORM form_name="form2" print_seq="1500"/>    
     <FORM form_name="form3" print_seq="9000"/>    
     <FORM form_name="form4" print_seq="5500"/>    
    </forms>    
</xsl:variable>    

    <xsl:for-each select="$formslist/*">    
     <xsl:sort select="FORM/@print_seq"/>    
     <xsl:copy-of select="."/>    
   </xsl:for-each>

The problems with this code:

  1. The formlist variable has no specified type and by default its type is document-node(). This means that $formlist/* select the single top element forms and sorting a single element results in exactly this element (unchanged). This problem would have been avoided if the type of the variable had been specified as as="element()".

  2. Even if the above problem had been solved, the specified sort key FORM/@print_seq is incorrect -- a FORM element doesn't have a FORM child. The correct sort key would be just: @print_seq .

  3. Even if the first two problems above didn't exist, the sort would still be incorrect, because the sort key type is treated as string and not as a number. The correct <xsl:sort> instruction needs to have data-type="number" specified or the sort key itself should have been specified as xs:integer(@print_seq)

Solution:

Simply use:

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

 <xsl:variable name="formslist" as="element()">
    <forms>
     <FORM form_name="form1" print_seq="1200"/>
     <FORM form_name="form2" print_seq="1500"/>
     <FORM form_name="form3" print_seq="9000"/>
     <FORM form_name="form4" print_seq="5500"/>
    </forms>
</xsl:variable>

    <xsl:template match="/">
    <xsl:element name="{name($formslist)}">
        <xsl:for-each select="$formslist/*">
         <xsl:sort select="@print_seq" data-type="number"/>
         <xsl:copy-of select="."/>
       </xsl:for-each>
   </xsl:element>
    </xsl:template>
</xsl:stylesheet>

when this transformation is applied on any XML document (not used), the wanted, correct result is produced:

<forms>
    <FORM form_name="form1" print_seq="1200"/>
    <FORM form_name="form2" print_seq="1500"/>
    <FORM form_name="form4" print_seq="5500"/>
    <FORM form_name="form3" print_seq="9000"/>
</forms>
Dimitre Novatchev