tags:

views:

277

answers:

1

Basically, I want an exact copy of the XML, except I'd like to sort certain nodes by their ID attribute. Not all elements with the ID attribute should be sorted.

I've kludged together a working stylesheet, but it requires me to hard-code the <xsl:apply-template>'s in for all sibling nodes to the nodes I'm sorting on. I've no formal schema, and I can't be certain that it won't change. I'd like to be able to create a more generic stylesheet which will output the non-sorted nodes without these explicit calls.

Is this possible?

My Java code to transform the XML:

String input = "C:\\presort.xml";
String output = "C:\\postsort.xml";
String xsl = "C:\\sort.xsl"
Document dom;

try
{
 dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(input);
 Element e = dom.getDocumentElement();

 Transformer transform = TransformerFactory.newInstance().newTransformer(
   new StreamSource( new File(xsl) ));
 StreamResult result = new StreamResult(new File(output));
 transform.transform(new DOMSource(dom), result);
} 
catch (Exception e)
{
 e.printStackTrace();
}

My XML:

<?xml version="1.0" encoding="utf-8"?>
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;

  <Person id="1">
    <Base>true</Base>
    <Description>something</Description>
    <Name>Vin Vinigar</Name>
    <Privileges>
      <Privilige id="340">
        <Permission>2</Permission>
        <Job id="dontsort" />
      </Privilige>
      <Privilige id="11">
        <Permission>3</Permission>
        <Job id="dontsort" />
      </Privilige>
      <Privilige id="1011">
        <Permission>1</Permission>
        <Job id="2342" />
      </Privilige>
    </Privileges>
  </Person>

  <Person id="f32">
    <Base>true</Base>
    <Description>Here be dragons</Description>
    <Name>John Doe</Name>
    <Privileges>
      <Privilige id="23a">
        <Permission>2</Permission>
        <Job id="a2a" />
      </Privilige>
    </Privileges>
  </Person>

  <Person id="22">
    <PossibleUnknownTagHere>something</PossibleUnknownTagHere>
    <Name>Han Solo</Name>
    <Privileges>
      <Privilige id="23a">
        <Permission>3</Permission>
        <Job id="a2a" />
      </Privilige>
    </Privileges>
  </Person>

</root>

My stylesheet:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

    <xsl:template match="root|@*">
        <xsl:copy >
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="Person">
                <xsl:sort select="@id" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Person">
        <xsl:copy >
            <xsl:apply-templates select="@*" />

            <!-- Works but requies a template for each sibling element -->
            <xsl:apply-templates select="Base" />
            <xsl:apply-templates select="Description" />
            <xsl:apply-templates select="Name" />

            <!-- I'd like to do something like this -->
            <!--
            <xsl:choose>
                <xsl:when test="not(Privileges)">
                    <xsl:apply-templates select="." />
                </xsl:when>
            </xsl:choose>
            -->

            <xsl:apply-templates select="Privileges" />
        </xsl:copy>
    </xsl:template>

    <!-- I'd like to remove the need for these 3 explicity copies -->
    <xsl:template match="Base">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="Description">
        <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="Name">
        <xsl:copy-of select="."/>
    </xsl:template>

    <xsl:template match="Privileges">
        <xsl:copy >
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates select="Privilege">
                <xsl:sort select="@id" order="ascending" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Privilege">
        <xsl:copy-of select="."/>
    </xsl:template>

</xsl:stylesheet>
+1  A: 
<xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates />
    </xsl:copy>
<xsl:template>

<xsl:template match="root">
    <xsl:copy>
        <xsl:apply-templates select="@*" />
        <xsl:apply-templates select="Person">
            <xsl:sort select="@id" order="ascending" />
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<xsl:template match="Privileges">
    <xsl:copy>
        <xsl:apply-templates select="@*" />
        <xsl:apply-templates select="Privilege">
            <xsl:sort select="@id" order="ascending" />
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>
Pavel Minaev
Unfortunately, this doesn't copy over the attributes on the nodes which have been sorted.
jhsheets
Hmm, I must have incorrectly copied the XSL as it's working now. Thanks :)
jhsheets