问题
I'm using
<xsl:sort />
to sort the rows in a table. The value of
@result
can be Failed, Ignored or Passed. As it is sorted alphabetically it will not come out in the order I want. Which is
Failed - Ignored - Passed
How do I achieve this I am using xslt 1.0
This is my code
<xsl:apply-templates select="results/test-case">
<xsl:sort select="@result" />
</xsl:apply-templates>
回答1:
In your question the ordering you've asked for is consistent with alphabetical order, so a plain <xsl:sort select="@result" />
should work correctly. But in cases where a non-alphabetic fixed ordering is required I tend to use the following trick.
First define the order in a variable, with entries delimited by some character that is not part of any of the options:
<xsl:variable name="sortOrder" select="'|Passed|Failed|Ignored|'" />
Then use
<xsl:sort data-type="number" select="string-length(
substring-before($sortOrder, concat('|', @result, '|')))" />
The trick here is that substring-before($sortOrder, concat('|', @result, '|'))
will be the empty string when @result
is Passed, the string "|Passed"
when @result
is Failed, and the string "|Passed|Failed"
when @result
is Ignored. Thus sorting numerically by the length of these strings will produce the ordering given by $sortOrder
.
In this particular case you don't even need the concat
, just
<xsl:sort data-type="number" select="string-length(
substring-before($sortOrder, @result))" />
will do the job. The concat
is there in the general case to handle situations where one item in the ordering is a substring of another. For example, for an ordering of '|Passed|Pass|Failed|Fail|'
the concat is required otherwise "Pass" would be treated the same as "Passed" rather than being consistently sorted after it.
回答2:
The following alternate XSLT is definitely not as cool as @IanRoberts's but it may be helpful in some setups when e.g. the sorting order is defined by another process and hence be available in another XML file.
The following file sort.xml
is a simple example defining a sort order:
<?xml version="1.0" encoding="ISO-8859-1"?>
<sort_indices>
<sort_index name="my_sort">
<entry key="Failed" index="2"/>
<entry key="Ignored" index="0"/>
<entry key="Passed" index="1"/>
</sort_index>
</sort_indices>
This file can be sourced into the XSLT using document
and then used as sorting index:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:variable name="sort_index" select="document('sort.xml')/sort_indices/sort_index[@name='my_sort']"/>
<xsl:template match="/">
<test-cases>
<xsl:apply-templates select="results/test-case">
<xsl:sort select="$sort_index/entry[@key = current()/@result]/@index"/>
</xsl:apply-templates>
</test-cases>
</xsl:template>
</xsl:stylesheet>
This way the sorting uses the numeric index values of the sort index directly without having to derive them from the length of an encoded string. It looks cleaner but as I said it's not as cool. :-)
来源:https://stackoverflow.com/questions/19787773/sort-given-order-with-xslt-sort