RE: [xsl] xsl:sort descending causes attribute nodes to be created after children, causing an error

Subject: RE: [xsl] xsl:sort descending causes attribute nodes to be created after children, causing an error
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 16 Jan 2007 13:32:44 -0000
            <xsl:apply-templates select="node() | @*">
                <xsl:sort
                    select="text()"
                    order="descending" />
            </xsl:apply-templates>

For attribute nodes the value of the sort key (child::text()) will always be
an empty sequence. An empty sequence sorts before any other value, so in
descending order it sorts last, and since the template with match="@*"
creates attribute nodes, you will be adding attributes to the parent after
the children, which is an error.

This behaviour is certainly correct, and I'm not sure which part of it you
are questioning.

Incidentally, if any of your child elements contains an embedded comment,
the sort will fail because text() selects more than one node, and it's an
error in 2.0 for the sort key to be a sequence longer than one (in 1.0 all
but the first are ignored).

Michael Kay
http://www.saxonica.com/

> -----Original Message-----
> From: Abel Braaksma [mailto:abel.online@xxxxxxxxx] 
> Sent: 16 January 2007 13:01
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: [xsl] xsl:sort descending causes attribute nodes to 
> be created after children, causing an error
> 
> Hi XSLT'ers,
> 
> The following issue is easy to workaround, but I am wondering 
> if this is correct behavior after the XSLT 2 (or even 1) 
> recommendation.
> 
> With an xsl:apply-template that includes attribute nodes in 
> its select-attribute, and you apply an xsl:sort on the 
> children, then it happens that the attribute nodes are 
> created after the children when the order of xsl:sort is 
> descending. I tried google on this, but couldn't find 
> something useful.
> 
> The example below throws the following error:
> "An attribute node (count) cannot be created after the 
> children of the containing element"
> 
> I did not try other parsers. The xslt employs a simple copy 
> idiom and sorts the rows of the input in $data. Call the XSLT 
> on itself to see the error or the results:
> 
> <xsl:stylesheet
>     xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>     version="2.0">
> 
>     <xsl:output indent="yes" />
>    
>     <xsl:variable name="data">
>         <rows count="3">
>             <row>bbbb</row>
>             <row>aaaa</row>
>             <row>cccc</row>
>         </rows>
>     </xsl:variable>
>    
>     <xsl:template match="/">
>         <xsl:apply-templates select="$data/*" />
>     </xsl:template>
>    
>     <xsl:template match="node() | @*">
>         <xsl:copy>
>             <xsl:apply-templates select="node() | @*" />
>         </xsl:copy>
>     </xsl:template>
> 
>     <xsl:template match="rows">
>         <xsl:copy>
>             <xsl:apply-templates select="node() | @*">
>                 <xsl:sort
>                     select="text()"
>                     order="descending" />
>             </xsl:apply-templates>
>         </xsl:copy>
>     </xsl:template>
> 
> </xsl:stylesheet>
> 
> 
> Any thoughts on this? Is this behavior desired and/or 
> required, or is this the processor's mistake?
> 
> Btw: a possible workaround is to apply the attribute node first.
> 
> Cheers,
> -- Abel Braaksma
>    http://www.nuntia.nl

Current Thread