Sort given order with xslt sort

一笑奈何 提交于 2019-12-04 04:53:47

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!