The sort key value for each item in the initial sequence is established by evaluating the expression given in the
select
attribute, or by evaluating the contained sequence constructor. This is evaluated for each item, with this item as the context item, with its position in the initial sequence as the context position, and with the number of items in the initial sequence as the context size.
This means that if you want to process a sequence in reverse order, you can specify a sort key as:
You can also achieve other crafty effects: try, for example, sorting by
position() mod 3
. This can be useful if you need to arrange data vertically in a table.
This just leaves the question of how the system decides whether one sort key value is equal to or less than another. The basic rule is that the result is decided using the XPath
eq
and
lt
operators. These are essentially the same as the
=
and
<
operators, except that they only compare a single atomic value to another single atomic value, and perform no type conversions other than numeric promotion (which means, for example, that if one operand is an integer and the other is a double, the integer will be converted to a double in order to perform the comparison).
There are several caveats to this general rule:
- The
lt
operator may raise an error when comparing values of different types (such as a number and a date) or when comparing two values of the same type for which no ordering relation is defined (for example, instances of the type
xs:QName
). This is treated as a fatal error.
- The
element has an attribute
data-type
. This is only there for backward compatibility with XSLT 1.0, but you can still use it. If the value of the attribute is
text
, then the sort key values are converted to strings (using the
string()
function) before being compared. If the value is
number
, then they are converted to numbers using the
number()
function. The attribute also allows the value to be a prefixed QName, but the meaning of this depends entirely on the implementation. The feature was probably added to XSLT 1.0 to anticipate the use of schema-defined type names such as
xs:date
, and the implementation may allow this usage, but it's not defined in the standard. Instead, if you want to convert the sort key values to a particular type to do the comparison, you can achieve this using a cast or constructor function within the
select
attribute; for example,
select=“xs:date(@date-of-birth)”
.
- Another option that has been retained for backward compatibility with XSLT 1.0 is the ability to supply a sequence of values as the result of the
select
attribute, rather than a single value. If the
element is in backward-compatibility mode (that is, if it's in the scope of an
[xsl:]version
attribute whose value is
1.0
), then all items in the sort key value after the first are ignored. Otherise, supplying a sequence of more than one item as the sort key value will cause an error.
- It is possible that evaluating a sort key value will return the empty sequence. XSLT specifies that for sorting purposes, the empty sequence is considered to be equal to itself and less than any other value.
- Another possibility is that when evaluating a numeric sort key value, the value will be the special value NaN (not a number). This would happen, for example, if you specify
select=“number(@price)”
and the element has no
price
attribute, or a
price
attribute whose value is
$10.00
(the
$
sign will cause the conversion to a number to fail). For sorting purposes, NaN is considered equal to itself, and less than any other numeric value (but greater than an empty sequence). This is different from the results of using the XPath comparison operators, where
eq
returns false if both operands are NaN.