Re: [xsl] recursive sorting by element name

Subject: Re: [xsl] recursive sorting by element name
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 29 Nov 2007 12:21:58 -0500
Davis,

It's difficult to see why you're getting the inconsistent behavior without more info, and in particular who (if anyone) is out of conformance here. But a workaround shouldn't be too hard in any case. Try this:

<xsl:template match="node()">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <!-- copy all the attributes before
         applying templates to the children only -->
    <xsl:apply-templates select="node()">
      <xsl:sort select="@typeName"/>
      <xsl:sort select="name(.)"/>
      <xsl:sort/>
    </xsl:apply-templates>
  </xsl:copy>
</xsl:template>

Cheers,
Wendell

At 11:22 AM 11/29/2007, you wrote:
Hi, a follow-up question...

I am running into some issues / inconsistencies running this
transformation on command line vs. within java vs. which platform I
run it on.  I'm hoping the list might have some pointers on how to
resolve this.

Here is the XSLT (slightly modified from what Ken posted):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
        xmlns:xalan="http://xml.apache.org/xslt"; >

    <!-- The xalan param gets back indentation that seems to be broken
in the java api  -->
    <xsl:output method="xml" indent="yes" encoding="UTF-8"
xalan:indent-amount="4"/>
    <xsl:strip-space elements="*" />

        <xsl:template match="/">
                <xsl:apply-templates />
        </xsl:template>

        <xsl:template match="@*|node()">
                <xsl:copy>
                        <xsl:apply-templates select="@*|node()">
                                <xsl:sort select="@typeName"/>
                                <xsl:sort select="name(.)"/>
                                <xsl:sort />
                        </xsl:apply-templates>
                </xsl:copy>
        </xsl:template>

</xsl:stylesheet>

When I run this on Ubuntu Linux 7.10 (fully updated) using xsltproc, I
encounter this bug:

https://bugs.launchpad.net/ubuntu/+source/libxml2/+bug/147144

Namely, it reports the error:

runtime error: file SortCollections.xsl line 40 element copy
Attribute nodes must be added before any child nodes to an element.

When I run this on Mac OS X 1.5 (Leopard -- fully updated) using
xsltproc, it does exactly what I want with no problems.

When I run this script from Java 1.6  (using JAXB) with the code
below, the identity transform does not copy all the attributes over.
I end up with missing attributes, and I have no idea why.

This behavior with Java is seen on both Windows XP platform and Ubuntu
Linux.  We want to call the script from java -- since it is being used
with JAXB to serialize/de-serialize a collection, and then we use the
XSLT to sort it and do an XML-diff in unit tests to detect changes.
Does anyone have any workaround or solution to getting a consistent
solution ??  Thanks in advance!  I have also posted below a sample XML
input file that causes this behavior.

--JAVA SNIPPET--

import javax.xml.bind.Marshaller;
import javax.xml.bind.JAXBSource;
import javax.xml.bind.JAXBContext;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

Object object; // the object to be marshalled to XML
OutputStream output; // the output stream

final Marshaller marshaller = getContext().createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
final JAXBSource source = new JAXBSource(marshaller, object);
final StreamResult result = new StreamResult(output);
// run XSLT script
final StreamSource stylesource = new
StreamSource(XmlReaderWriter.class.getResourceAsStream(XSLT));
final Transformer transformer =
TransformFactory.newInstance().newTransformer(stylesource);
transformer.transform(source, result);

--END JAVA SNIPPET--

<?xml version="1.0" encoding="UTF-8"?>
<DictionaryModel>
<DictionaryModelDescriptor about="modelName1/modelVersion1">
<modelName>modelName1</modelName>
<modelVersion>modelVersion1</modelVersion>
</DictionaryModelDescriptor>
<DictionaryParts>
<DictionaryPart abstract="false" typeName="part.full1">
<children/>
<parents/>
<DictionaryProperties/>
<feature>feature.empty3</feature>
<maxCardinality>2</maxCardinality>
<minCardinality>1</minCardinality>
<parentComposition>feature.empty2</parentComposition>
<role>role</role>
<sequence>1</sequence>
</DictionaryPart>
<DictionaryPart abstract="false" typeName="part.full5">
<children/>
<parents/>
<DictionaryProperties/>
<feature>feature.empty13</feature>
<maxCardinality>2</maxCardinality>
<minCardinality>1</minCardinality>
<parentComposition>feature.empty12</parentComposition>
<role>role</role>
<sequence>1</sequence>
</DictionaryPart>
</DictionaryParts>
<DictionaryAssociations>
<DictionaryAssociation abstract="false" typeName="association.empty1">
<children/>
<parents/>
<DictionaryProperties/>
</DictionaryAssociation>
<DictionaryAssociation
compositionType="BIDIRECTIONAL_ASSOCIATION" abstract="false"
typeName="association.full2">
<children/>
<parents/>
<DictionaryProperties>


<DictionaryProperty>simple.property.empty4</DictionaryProperty>

<DictionaryProperty>composite.property.empty4</DictionaryProperty>
            </DictionaryProperties>
            <sourcePart>part.full2</sourcePart>
            <targetPart>part.full3</targetPart>
            <resolverStrategy>resolver.strategy</resolverStrategy>
        </DictionaryAssociation>
    </DictionaryAssociations>
    <DictionaryFeatures>
        <DictionaryFeature composite="false" abstract="false"
typeName="feature.empty1">
            <children/>
            <parents/>
            <DictionaryProperties/>
            <associations/>
            <parentComposites/>
            <parts/>
        </DictionaryFeature>
        <DictionaryFeature composite="true" compositionType="SEQUENCE"
abstract="true" typeName="feature.full8">
            <children>
                <child>feature.empty9</child>
            </children>
            <parents/>
            <DictionaryProperties>

<DictionaryProperty>composite.property.empty5</DictionaryProperty>

<DictionaryProperty>simple.property.empty5</DictionaryProperty>
</DictionaryProperties>
<associations>
<association>association.empty3</association>
<association>association.empty4</association>
</associations>
<parentComposites>
<parentComposite>feature.empty10</parentComposite>
</parentComposites>
<parts>
<part>part.empty4</part>
</parts>
<code>code</code>
</DictionaryFeature>
</DictionaryFeatures>
<DictionaryPropertyNodes>
<DictionaryPropertyNode abstract="false"
typeName="property.node.empty1">
<children/>
<parents/>
<DictionaryProperties/>
</DictionaryPropertyNode>
<DictionaryPropertyNode abstract="false" typeName="property.node.full3">
<children>
<child>property.node.empty4</child>
</children>
<parents>
<parent>property.node.empty5</parent>
</parents>
<DictionaryProperties>


<DictionaryProperty>composite.property.empty11</DictionaryProperty>

<DictionaryProperty>simple.property.empty8</DictionaryProperty>
            </DictionaryProperties>
        </DictionaryPropertyNode>
    </DictionaryPropertyNodes>
    <DictionaryProperties>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="CompositeDictionaryProperty" propertyType="COMPOSITE_ROOT"
inherited="false" typeName="composite.property.empty1">
            <maxCardinality>2147483647</maxCardinality>
            <minCardinality>-2147483648</minCardinality>
            <children/>
        </DictionaryProperty>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="CompositeDictionaryProperty" propertyType="COMPOSITE_ROOT"
inherited="false" typeName="composite.property.empty2">
            <maxCardinality>2147483647</maxCardinality>
            <minCardinality>-2147483648</minCardinality>
            <children/>
        </DictionaryProperty>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="CompositeDictionaryProperty" propertyType="COMPOSITE_ROOT"
inherited="false" typeName="composite.property.empty3">
            <maxCardinality>2147483647</maxCardinality>
            <minCardinality>-2147483648</minCardinality>
            <children/>
        </DictionaryProperty>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="CompositeDictionaryProperty" propertyType="COMPOSITE_CHILD"
inherited="true" typeName="composite.property.full6">
            <code>code</code>
            <maxCardinality>3</maxCardinality>
            <minCardinality>2</minCardinality>
            <parentObject>feature.empty14</parentObject>
            <parentProperty>composite.property.empty8</parentProperty>
            <rootProperty>composite.property.empty7</rootProperty>
            <children>
                <child>simple.property.empty6</child>
            </children>
            <propertyNode>property.node.empty2</propertyNode>
        </DictionaryProperty>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="SimpleDictionaryProperty" propertyType="SIMPLE_ROOT"
inherited="false" typeName="simple.property.empty1">
            <maxCardinality>2147483647</maxCardinality>
            <minCardinality>-2147483648</minCardinality>
        </DictionaryProperty>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="SimpleDictionaryProperty" propertyType="SIMPLE_ROOT"
inherited="false" typeName="simple.property.empty2">
            <maxCardinality>2147483647</maxCardinality>
            <minCardinality>-2147483648</minCardinality>
        </DictionaryProperty>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="SimpleDictionaryProperty" propertyType="SIMPLE_ROOT"
inherited="false" typeName="simple.property.empty3">
            <maxCardinality>2147483647</maxCardinality>
            <minCardinality>-2147483648</minCardinality>
        </DictionaryProperty>
        <DictionaryProperty
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
xsi:type="SimpleDictionaryProperty" propertyType="SIMPLE_CHILD"
inherited="true" typeName="simple.property.full7">
            <code>code</code>
            <maxCardinality>2</maxCardinality>
            <minCardinality>1</minCardinality>
            <parentObject>feature.empty16</parentObject>
            <parentProperty>composite.property.empty9</parentProperty>
            <rootProperty>composite.property.empty10</rootProperty>
            <defaultValue>default-value</defaultValue>
            <dictionaryFeatureRange>feature.range2</dictionaryFeatureRange>
            <referentFeature>feature.empty17</referentFeature>
            <dictionaryValueRange>value.range1</dictionaryValueRange>
            <valueTypeName>value-type-name</valueTypeName>
        </DictionaryProperty>
    </DictionaryProperties>
    <DictionaryFeatureRanges>
        <DictionaryFeatureRange typeName="feature.range1">
            <DictionaryFeatures>
                <DictionaryFeature>feature.empty11</DictionaryFeature>
            </DictionaryFeatures>
        </DictionaryFeatureRange>
    </DictionaryFeatureRanges>
    <DictionaryValueRanges>
        <DictionaryValueRange typeName="value.range2">
            <DictionaryRangeItems>
                <DictionaryRangeItem>range.item3</DictionaryRangeItem>
            </DictionaryRangeItems>
            <valueTypeName>value-type-name</valueTypeName>
        </DictionaryValueRange>
    </DictionaryValueRanges>
    <DictionaryRangeItems>
        <DictionaryRangeItem typeName="range.item2">
            <value>4</value>
        </DictionaryRangeItem>
    </DictionaryRangeItems>
    <DictionaryValueTypeNames>
        <DictionaryValueTypeName>a value type name</DictionaryValueTypeName>
        <DictionaryValueTypeName>value-type-name</DictionaryValueTypeName>
    </DictionaryValueTypeNames>
</DictionaryModel>

On Nov 28, 2007 5:46 PM, G. Ken Holman <gkholman@xxxxxxxxxxxxxxxxxxxx> wrote:
> At 2007-11-28 17:04 -0500, Davis Ford wrote:
> >Hi, consider the following example:
> >...
> >I want to sort it as such
> >...
> >I am trying to come up with a generic XSLT solution that does not use
> >explicit element names, but only uses the sort select="name()", and it
> >should be recursive such that if say, element <A1> contained further
> >elements, then they would also be sorted by element name.
> >
> >Finally, if the element names are the same, then it should sort them
> >by an attribute called "typeName".
> >
> >Can anyone provide some help?  Thank you in advance!
>
> Am I missing something?  This is a variant of a one-template identity
> transform.
>
> I hope the example below helps.
>
> . . . . . . . . . . Ken
>
> t:\ftemp>type davis.xml
> <Collection>
>    <CollectionB>
>       <B2></B2>
>       <A2></A2>
>       <A1></A1>
>       <B1 typeName="2"></B1>
>       <B1 typeName="1"></B1>
>    </CollectionB>
>    <CollectionA>
>       <B2></B2>
>       <A2></A2>
>       <A1></A1>
>       <B1></B1>
>    </CollectionA>
> </Collection>
>
> t:\ftemp>type davis.xsl
> <?xml version="1.0" encoding="US-ASCII"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>                  version="1.0">
>
> <xsl:output indent="yes"/>
> <xsl:strip-space elements="*"/>
>
> <xsl:template match="@*|node()">
>    <xsl:copy>
>      <xsl:apply-templates select="@*|node()">
>        <xsl:sort select="name(.)"/>
>        <xsl:sort select="@typeName"/>
>      </xsl:apply-templates>
>    </xsl:copy>
> </xsl:template>
>
> </xsl:stylesheet>
> t:\ftemp>xslt davis.xml davis.xsl con
> <?xml version="1.0" encoding="utf-8"?>
> <Collection>
>     <CollectionA>
>        <A1/>
>        <A2/>
>        <B1/>
>        <B2/>
>     </CollectionA>
>     <CollectionB>
>        <A1/>
>        <A2/>
>        <B1 typeName="1"/>
>        <B1 typeName="2"/>
>        <B2/>
>     </CollectionB>
> </Collection>
> t:\ftemp>
>
>
>
>
> --
> Comprehensive in-depth XSLT2/XSL-FO1.1 classes: Austin TX,Jan-2008
> World-wide corporate, govt. & user group XML, XSL and UBL training
> RSS feeds:     publicly-available developer resources and training
> G. Ken Holman                 mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
> Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/s/
> Box 266, Kars, Ontario CANADA K0A-2E0    +1(613)489-0999 (F:-0995)
> Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/s/bc
> Legal business disclaimers:  http://www.CraneSoftwrights.com/legal


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================

Current Thread