Reputation: 20862
I have an XML document like this:
<?xml version="1.0" ?>
<root>
<element id="1"><name>Red</name><rank value="1" /></element>
<element id="2"><name>Orange</name><rank value="4" /></element>
<element id="3"><name>Yellow</name><rank value="3" /></element>
<element id="4"><name>Green</name><rank value="2" /></element>
<element id="5"><name>Blue</name><rank value="5" /></element>
<element id="6"><name>Indigo</name></element>
<element id="6"><name>Violet</name></element>
</root>
I'd like to sort by numeric rank and have the un-ranked elements float to the bottom, like this:
The order of Indigo/Violet is not relevant to me.
I tried this:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">
<xsl:apply-templates select="element">
<xsl:sort select="rank/@value" data-type="number" order="ascending" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="element">
<xsl:text>* </xsl:text><xsl:apply-templates select="name" /><xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
But my output looks like this:
All of the ranked items are in fact in order, but they are at the bottom of the list.
Upvotes: 1
Views: 83
Reputation: 243479
<xsl:template match="/*">
<xsl:apply-templates select="element">
<xsl:sort select="not(rank/@value)"/>
<xsl:sort select="rank/@value" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
Upvotes: 0
Reputation: 116993
I would suggest a more general approach:
<xsl:template match="/root">
<xsl:apply-templates select="element">
<xsl:sort select="number(boolean(rank/@value))" data-type="number" order="descending" />
<xsl:sort select="rank/@value" data-type="number" order="ascending" />
</xsl:apply-templates>
</xsl:template>
See explanation: https://stackoverflow.com/a/34290573/3016153
Upvotes: 1
Reputation: 20862
Answering my own question after a bit of tinkering.
Since I'm using a numeric sort criteria, I can sort descending
instead of ascending
, and then flipping the sign of the numeric argument being sorted:
<xsl:apply-templates select="element">
<xsl:sort select="-(rank/@value)" data-type="number" order="descending" />
</xsl:apply-templates>
This gives the desired order:
Upvotes: 1