3
votes

I am trying to sort the following XML using XSLT

<Name>name3</Name>
<Job>x</Job> 
<Name>name1</Name>
<Job>y</Job> 
<Name>name2</Name>

The expected output is

<Name>name1</Name>
<Job>x</Job> 
<Name>name2</Name>
<Job>y</Job> 
<Name>name3</Name>

The Name elements have to be sorted while keeping the Job elements intact. I am using XSLT 2.0

Although I am able to sort the Name elements properly using xsl:sort as given in the tutorial, the output I get is as follows:

<Name>name1</Name>
<Name>name2</Name>
<Name>name3</Name>
<Name>name3</Name>
<Job>x</Job> 
<Name>name1</Name>
<Job>y</Job> 
<Name>name2</Name>

I am new to XSLT. Sorry, if this is a very simple question. Thanks in advance.

1
This part is not clear: "while keeping the Job elements intact". Please change your example and assign a different value (or a unique id) to each Job, so that we can tell which one is which. - michael.hor257k
I have updated the example. - Abhinav
We can't tell you what you did wrong if you don't tell us what you did. - Michael Kay

1 Answers

4
votes

Sorry, if this is a very simple question.

No, this is not simple at all. Try it this way:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="sorted-names">
    <xsl:perform-sort select="/root/Name">
        <xsl:sort select="."/>
    </xsl:perform-sort>
</xsl:variable>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Name">
    <xsl:copy-of select="$sorted-names/Name[count(current()/preceding-sibling::Name) + 1]"/>
</xsl:template>

</xsl:stylesheet>

Note that this assumes a well-formed XML input, with a single root element.

Demo: http://xsltransform.net/94hvTzG/1