Tests for xslt2 and xpath 2.

Dave Pawson. 4 Feb 2007. Version 3.0, Built under Saxon 8.8 to Rec, at www.dpawson.co.uk

Meant to be run against itself: saxon document.xsl document.xsl
Note: All the current syntax could change. Be aware of that. Its not yet a recommendation. But it is getting very close!

The source XSLT is Here too

Table of Contents.

  1.   QName()
  2.   This heading is included to produce an error.
  3.   analyze-string - Analyse string, using regular expressions.
  4.   analyze-string() and regex Groups
  5.   as - Creating variables of a given type
  6.   as attribute, cast to another type
  7.   avg() max() min() sum() abs() - the Numeric functions.
  8.   base-uri(). Stylesheet and source document name+path
  9.   base-uri()
  10.   castable and cast
  11.   character-map
  12.   codepoint-equal()
  13.   codepoints-to-string()
  14.   collation
  15.   collation, default collation .
  16.   collection(). Seems to return a number of xml instance. See
  17.   comments in xpath expressions
  18.   compare() - String Comparison
  19.   comparison operators
  20.   copy-of with / without namespace
  21.   copy-of() - Copying - omitting namespaces
  22.   current-time() - Second check on time function.
  23.   data() function
  24.   date and time
  25.   deep-equal(),
  26.   distinct-values() function
  27.   doc-available().
  28.   document() and doc().
  29.   document-uri()
  30.   empty() - The empty function
  31.   encode-for-uri()
  32.   ends-with() function
  33.   error()
  34.   escape-html-uri() - Escaping Special characters in a URI
  35.   every , The Universal quantifier
  36.   exactly-one(),
  37.   except, Union and Intersection.
  38.   exists() function
  39.   for loop.
  40.   for-each-group - A New grouping method
  41.   format attribute, Number formatting
  42.   format-date[Time] and format-time.
  43.   function-available() - Function Availability. Does your process support this?
  44.   get-namespace-uri-for-prefix function
  45.   idiv, integer Division
  46.   idref() - Linking functions.
  47.   if then else - conditional value-of?
  48.   in-scope-prefixes()
  49.   index-of() - Find the index of one item in a sequence
  50.   insert() Insert-before function
  51.   instance of
  52.   item()* .. sort of nodeset?
  53.   lang()
  54.   list constructor; () as a list constructor?
  55.   lower-case()
  56.   matches() regular expression in xslt
  57.   modes, Select all modes
  58.   namespace - Adding a namespace with xsl:namespace
  59.   namespace-uri()
  60.   next-match
  61.   node-name()
  62.   normalize-space() Normalise text
  63.   number()
  64.   perform-sort - Sorting function
  65.   prefix-from-QName()
  66.   quotes - Changes in the use of quotes
  67.   quoting, "(") character nesting:
  68.   remove() Remove functions
  69.   remove(), remove an item from a sequence,
  70.   replace() - Text replace function
  71.   resolve-QName() - Builds a qname from the in-scope namespaces.
  72.   resolve-uri() - Uri resolution
  73.   result-document - Indirect use
  74.   result-document. Creating multiple output documents. Direct use
  75.   reverse() function
  76.   root() - find root node of context.
  77.   round()
  78.   round-half-to-even()
  79.   sequence - a literal sequence
  80.   some , The Universal quantifier.
  81.   some and every $x - Range variables.
  82.   sort - Sorting.
  83.   static-base-uri()
  84.   string-join() string functions:
  85.   string-to-codepoints()
  86.   subsequence function
  87.   system-property()
  88.   terminology.
  89.   test attribute changes. Reduction in verbosity / test on a sequence
  90.   tokenize()
  91.   treat as
  92.   tunnelling,
  93.   types ... a few examples.
  94.   union and intercept operators. Combining sequences of node-sets
  95.   unordered() function.
  96.   unparsed-entity-uri()
  97.   unparsed-text() - get the contents of a text file.
  98.   upper-case()
  99.   user defined functions
  100.   value Comparisons... eq, ne, is, isnot etc
  101.   wrong data types.
  102.   xpath-default-namespace()
  103.   xpath-default-path


You can access the base URI for a node using the base-uri() function in XPath 2.0. So if you want to know the filename for the input document, you can do: <xsl:variable name="input-uri" select="base-uri(/)" /> which gives
file:/sgml/site2/2src/exampler2.xsl and if you want to know the filename for the stylesheet, you can do: <xsl:variable name="stylesheet-uri" select="base-uri(doc(''))" /> which gives

error() w3c

Error raised, <xsl:value-of select="error('Error found')"/> -- function used at end of program. The string Error found is output on the error stream.. As you see I haven't used it, since it terminates the program :-)

system-property() w3c

Note: This using Saxon, SAXON 8.8 from Saxonica
Version, 2.0
Vendor, SAXON 8.8 from Saxonica
Vendor-url, http://www.saxonica.com/
product-name, SAXON
product-version, 8.8
Schema aware, no
Supports serialization, yes
Supports backwards compatibility,
supports-serialization supports-backwards-compatibility

date and time w3c

Declared variables are

 <xsl:variable name="date" select="current-date()"/>
<xsl:variable name="dateTime" select="current-dateTime() "/>

Obtain values using <xsl:value-of select="(function)" : Functions are:

current-dateTime() - 2007-02-04T11:25:18.93Z

current-date() - 2007-02-04Z

current-time() - 11:25:18.93Z

implicit-timezone() - PT0S - GMT here as of Feb 05

day-from-date() 4 - which is the day of the month.

year-from-date() 2007

date from dateTime, xs:date(xs:dateTime($dateTime)) = Date from dateTime: 2007-02-04Z

month-from-date() 2

day-from-date($date) gives - 4

Basic date formatting: 4 february, 2007 from <xsl:value-of select=" format-date($date,'[D] [Mn], [Y]')"/>

timezone-from-dateTime($datetime) gives - [PT0S ]

Current time is : 11:25:18.93Z - Using <xsl:value-of select="$time"/>

hours-from-time() gives 11

minutes-from-time() gives 25

seconds-from-time() gives 18.93

timezone-from-time() [time zone ]gives PT0S

Subtract dates or $xs:date() - xs:date():  
 In this case, subtract  2002-09-01Z from 2007-02-04Z

 1617 days  - The duration since I stopped smoking, in days.
Note that it is now a simple subtraction, rather than a special function.

Except it doesn't produce nice months/days format.. The failure comes down to irregular months. As Mike Kay pointed out, a March date - a Jan date will vary dependent on leap years etc. The logic goes, convert each date to the units you want, then do the maths.

   So its 
   4 years and  5 months

   Now using the function dp:subDates, (2007-02-04Z - 2002-09-01)
   4 years 5 months

Boy that's messy!
See the source to find out how messy - but it can be done!

External Java call to get date: <xsl:value-of select="Date:toString(Date:new())" xmlns:Date="/java.util.Date" /> Sun Feb 04 11:25:19 GMT 2007 is no longer needed.

format-date[Time] and format-time. W3C

Basic date and time formatting. Uses a picture string. As shown below in the more common forms.

Y  	year  	
M 	month in year 	
D 	day in month 	
d 	day in year 	
F 	day of week 	
W 	week in year 	
w 	week in month 	
H 	hour in day (24 hours) 	
h 	hour in half-day (12 hours) 	
P 	am/pm marker 	
m 	minute in hour 	
s 	second in minute 	
f 	fractional seconds

So, for example, to format the date and time a format might be

  <xsl:variable name="now" select="current-dateTime()"/>



Similarly, for a time

  <xsl:variable name="now" select="current-time()"/>
select="format-time($now,'[H]:[m] [P]','en',(),())"/>


  11:25 a.m.

collation, default collation . W3C

Default Collation is: http://www.w3.org/2005/xpath-functions/collation/codepoint, obtained by
<xsl:value-of select="default-collation()"/>. This seems to be the Unicode codepoint default.
If you don't know what the collation is all about, then it's of no interest to you.

user defined functions w3c

<xsl:function name="dp:add">
  <xsl:param name="val1" />
  <xsl:param name="val2" />
  <xsl:sequence select="$val1 + $val2" />

(Thanks Jeni)

  Used by  <xsl:value-of select="dp:add(3,4)"/>

Which gives, 7

And from the XSLT rec, a string reversal function

<xsl:function name="dp:reverse">
  <xsl:param name="sentence" as="xs:string"/>
     select="if (contains($sentence, ' '))
             then concat(str:reverse(substring-after($sentence, ' ')),
                         ' ',
                         substring-before($sentence, ' '))
             else $sentence"

which is called up as:
  <xsl:value-of select="dp:reverse('DOG BITES MAN')"/> 

A more constrained version of addition, using types:

<xsl:function name="dp:add2">
  <xsl:param name="val1" as="xs:integer" />
  <xsl:param name="val2" as="xs:integer" />
  <xsl:sequence select="$val1 + $val2" as="xs:integer" />

Provides, using <xsl:value-of select="dp:add(1, 189)" Result is : 190 [Note: It should fail with 189.3 as second param.]

And the string reversal function gives, MAN BITES DOG

instance of W3C

Tests if a node is of a particular data type. Testing the current node, the stylesheet element

    Looking at <xsl:value-of select="name()"/> 
         <xsl:if test=".  instance of node()">
           Its an node 
         <xsl:if test=".  instance of element()">
           Its an element 
         <xsl:if test=".  instance of attribute()">
           Its an attribute
         <xsl:if test=".  instance of item()">
           Its an item
        <xsl:if test=" empty(.)">
           Its empty 
         <xsl:if test=".  instance of text()">
           Its text 
         <xsl:if test=".  instance of processing-instruction()">
           Its a pi 
         <xsl:if test=".  instance of comment()">
           Its a comment
        <xsl:if test=".  instance of document-node()">
           Its a document-node 
       <xsl:if test="$decVar  instance of xs:decimal">
           $decVar is xs:decimal 

.... and don't ask me what the full list of types is:
Many wonder, and few seem to know.

Looking at element xsl:stylesheet
Its an node
Its an item
Its a document-node
$decVar is xs:decimal

<xsl:value-of select=" if ($intTest instance of xs:integer) then 'True' else 'False'"/>

and with intTest defined as 
<xsl:variable name="intTest" select="5" as="xs:integer"/>

gives a result of True
And <xsl:value-of select=" if ($decVar instance of xs:integer) then 'True' else 'False'"/> -
with $decVar defined as 
   <xsl:variable name="decVar" 
       select="3.14159" as="xs:decimal"/> 
gives False

treat as W3C

Almost a temporary cast? Again Mike Kay's book offers a useful example. A stock level element may contain either an integer count of the items or a string indicating that the item is 'out of stock'. The example decrements the stock, but only if it has a numeric value. A zero or negative value indicates this out of stock count.

<xsl:variable name="stock1" select="3" as="xs:integer"/>
<xsl:variable name="stock2" select="'Out of Stock'" as="xs:string"/>

<xsl:value-of select="
if (data($stock1) instance of xs:integer) then
     $stock1 -1


<xsl:value-of select="
if (data($stock2) instance of xs:integer) then
     $stock1 -1

Testing $stock1 gives

and testing $stock2 gives


item()* .. sort of nodeset? W3C

Yes, I agree it looks pretty meaningless doesn't it. However. As of CR, its pretty essential, especially if you want to use types. And want to generate, say, a nodeset.. sorry sequence, in a variable.

<xsl:variable name="a" select="(//h3)[position() < 3]" as="item()*"/>
This creates a variable you can hack into using xpath quite readily. I.e. remember item()*.

types ... a few examples. W3C

From an explanatory email from Mike Kay, thanks Mike.

<xsl:param name="x" as="item()"/>
the parameter value can be any item (i.e. a node or atomic value). But it must be a single item.
<xsl:param name="x" as="item()?"/>
the parameter can be a single item or an empty sequence
<xsl:param name="x" as="item()+"/>
the parameter must be a sequence of one or more items - an empty sequence is not allowed
<xsl:param name="x" as="item()*"/>
the parameter can be any sequence of zero or more items - this places no constraints on its value.
<xsl:param name="x" as="node()*"/>
the parameter can be any sequence of zero or more nodes
<xsl:param name="x" as="xs:atomicValue*"/>
the parameter can be any sequence of zero or more atomic values (e.g. integers, strings, or booleans).

item()* is the most general type possible, it matches everything, like "Object" in Java. For that reason, it can usually be omitted. But not always, for example the default type in xsl:variable is not item()* but document-node(), to ensure that

<xsl:variable name="rtf">
continues to behave like XSLT 1.0

Use these to specify parameters, variable types etc.

comments in xpath expressions W3C

The long xpath expressions that David Carlisle and Jeni T come up with can now be commented. For example:

       <xsl:value-of select="//h3[@id='cmnts'] (:The h3 element with xml:id comnts,  :)
                              /following-sibling::p[1]  (:The first p following-sibling :)
                              /xsl:value-of/@select (:the value-of child, its select attribute :)
This expression gives - //h3[@id='cmnts'] (:The h3 element with xml:id comnts, :) /following-sibling::p[1] (:The p element child (:Oh yes it is:):) /xsl:value-of/@select (:the value-of child, its select attribute :) which as you can see, includes the comments! Note they can be nested too!

castable and cast W3C

Tests whether a given value is castable into a given target type. Returns boolean.

<xsl:variable name="decVar" select="3.14159" as="xs:decimal"/>
<xsl:variable name="intVar" select="3" as="xs:integer"/>
         <xsl:if test="$intVar castable as xs:decimal">
           Yes, we can convert an int to a decimal
         <xsl:if test="$decVar castable as xs:float">
           and we can change decimals to floats.
 Then do it, using 
<xsl:value-of select="$decVar cast as xs:float"/>
Yes, we can convert an int to a decimal and we can change decimals to floats. Then do it, using 3.14159
See the source to see this working.

get-namespace-uri-for-prefix function w3c

<xsl:value-of select="namespace-uri-for-prefix('dp',document('')//dp:analyze-string)"/> 

This provides the reverse mapping from prefix (dp in this case) to a full namespace and gives - http://www.dpawson.co.uk/ns#

string-join() string functions: w3c

  <xsl:value-of select="string-join(('Now', 'is', 'the', 'time', ' '), ")/> 

The output is: Now is the time

Note the difference between this and

<xsl:value-of select="concat('Now', 'is', 'the', 'time')" />

Which gives:Nowisthetime

Michael Kay put a clever example on the list: The requirement was to reverse a string. This

<xsl:variable name="in" select="'Now is the time'"/>
  <xsl:value-of select=" string-join(
                        for $i in string-length($in) to 1 return substring($in, $i, 1),'')"/>

This gives:
emit eht si woN

reverse() function W3C

A function to reverse a sequence. Needed since the WG have removed the option to use 'for n to n-x', Hence, taking a sequence one to N, which we really want to process by decrement:

<xsl:variable name="in" select="'Now is the time'"/>
<xsl:sequence select="reverse((1 to string-length($in)))"/>

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

ends-with() functionw3c

A boolean returning true if param 1 ends with param 2. Both parameters are strings. Complements the existing 'starts-with' functionality.

<xsl:value-of select='ends-with("goldenrod","rod")'/> 

returns "true"


Case changing:

select="upper-case('The quick Brown fox Jumps over the lazy dog' 



Case changing:

select="lower-case('The Quick Brown Fox Jumps Over The Lazy Dog' 

Gives: "the quick brown fox jumps over the lazy dog "

matches() regular expression in xslt w3c

Matches on the entire input, returns true or false.

Testing the matches function, with a string variable having value 'abd124' and using the regexp "[a..d|0..9]*" Hence

 <xsl:value-of select="matches ($inputString,'[a..d|0..9]*')"/>

Returns true

replace() - Text replace function w3c

replace() function. E.g. turn spaces into *** in "the quick brown fox jumps over the lazy dog"

 <xsl:value-of select="replace($str, ' ', '***')" /> 

Gives - the***quick***brown***fox***jumps***over***the***lazy***dog
[So any occurrences of param2 in param1 are replaced with param3]

tokenize() w3c

Tokenise!!! (One of my favourites). Do a for-each over the output of tokenize("The cat sat on the mat", "\s+") to process each item as if it were a child of the input element. Enables easy processing of regularly split text content

  <xsl:for-each select='tokenize("The cat sat on the mat", "\s+")'>
      <xsl:value-of select="."/>

Note that

<quote>If a separator occurs at the start of the $input string, 
      the result sequence will start with a zero-length string. 

and that the \s+ caters for a tab, space and newline character in the input string.

normalize-space() Normalise text w3c

Normalisation: Input as

brown ....


Function used

<xsl:value-of select="normalize-space('The


Result: [The quick brown fox]

compare() - String Comparison w3c

String comparison; With and without a character entity.

<xsl:variable name="stSt" select="'The quick brown fox ....'"/>
<xsl:variable name="entStr" select="'Th&#101; quick brown fox ....'"/>

<xsl:value-of select="compare($stSt, $entStr)"/>

Result is : 0

  Interpret the results as below.
-1  => less than 
 0  => Equal 
+1  => Greater than

Which indicates equality when the XSLT processor makes the comparison.

resolve-uri() - Uri resolution w3c

URI rsolution - absolute, or against a base URI.

 <xsl:value-of select="resolve-uri('./test1.xsl')"/>
(Which is this file)

Gives: file:/sgml/site2/2src/test1.xsl Indicating the full path name of the file, in this case. The parameter is meant to be a relative uri.

The second form takes an absolute location as a second parameter, such as might be used for a server root.

  <xsl:value-of select="resolve-uri('test1.xsl','file://c:/')"/>

This gives file://c/sgml/test1.xsl which resolves the relative URI against the base.

I'm told that the Java docs explains it. Baffles me.

resolve-QName() - Builds a qname from the in-scope namespaces. w3c

E.g, using the dp:months element, create a QName dp:newdoc,

<xsl:value-of select="resolve-QName('dp:newdoc',//dp:months)"/> gives dp:newdoc
Then check if it is a qname... using
<xsl:if test="resolve-QName('dp:newdoc',//dp:months) instance of xs:QName">
Its a QName!! 

Its a QName!! 

root() - find root node of context. w3c

Used to find the root node of the current document, with respect to the current-node(),

 <xsl:value-of select="name(root(.)/*[1]) 
gives: xsl:stylesheet
Note: Presumes root() returns the document node, which is why the first child is used as shown above. Possibly removes the necessity of saving the root node when you are mid xsl:for-each, and wish to access the current document.

index-of() - Find the index of one item in a sequence w3c

Sequence based. Remember that we've lost the node-list idea, life's full of sequences now. Load variable with a number of items. E.g.

<xsl:variable name="seq" select="$root//h3"/> 
pick the 5th item.
<xsl:variable name="oneChild" select="$seq[5]"/> 
Test it using
<xsl:value-of select="index-of($seq,$oneChild)" /> 

The result is 5
or, using a simple text example,

<xsl:value-of select="index-of(('a','b','c','d','e','f' ),'c')"/> 

gives a result of  3

empty() - The empty function w3c

Empty tests: Input document reads

<dp:t2><el/> </dp:t2>
<dp:t3>xxx </dp:t3>

Tested with
t1 shows as: <xsl:value-of select="empty($root//dp:mttests/t1/*)"/>
t2 shows as: <xsl:value-of select="empty($root//dp:mttests/t2/*)"/>
t3 shows as: <xsl:value-of select="empty($root//dp:mttests/t3/*)"/> 

Each is tested using the empty() function.
t1 shows as: true
t2 shows as: false
t3 shows as: true
Note that empty here seems to be defined as containing no elements, i.e. text content is ignored.

exists() function w3c

<xsl:if test="exists($root//dp:mttests/t1)">
  mttests/t1 is a non-empty sequence

<xsl:if test="exists($root//dp:mttests/t2)">
  mttests/t2 is a non-empty sequence
  <xsl:if test="not(exists($root//dp:mttests/t3/el)">
  mttests/t3 is an empty sequence

dp:mttests/t1 is a non-empty sequence
dp:mttests/t2 is a non-empty sequence
dp:mttests/t3 is an empty sequence

Note the inversion on the last test.

distinct-values() function w3c

We can now test for distinct nodes and values. Note the difference!
1. Define a variable with one duplicate item - the 3.

<xsl:variable name="ns1" select="(1,2,3,4,5,3)"/> 
2. Count its contents
<xsl:value-of select="count($ns1)"/>  
Gives 6
3. Remove duplicates and count the resulting nodes,
<xsl:value-of select="count(distinct-values($ns1))"/>
gives: 5

Then picking out the two distinct values with

<xsl:for-each select="distinct-values(//dp:distinct/dp:val1)"> 
gives: Single value
Single value with a difference.

copy-of() - Copying - omitting namespaces w3c

New attribute to the copy function. Copy without copying namespace. Adds the attribute copy-namespaces="no".
View source should show a <para> element without namespaces, then the same with a normal copy-of
[ Test Harness for XSLT and xpath 2 constructs] (no ns)
[ Test Harness for XSLT and xpath 2 constructs] (has ns)

The two forms are:

1. <xsl:copy-of select="document('')//d:doc/revhistory/purpose/para"
  copy-namespaces = "no"/>
2. <Test Harness for XSLT and xpath 2 constructs

the output is shown below. Here's one I prepared earlier, I think is the phrase.

 <para>Test Harness for XSLT and xpath 2 constructs</para>
  <para xmlns:d="rnib.org.uk/tbs#" 
  xmlns:saxon="http://saxon.sf.net/">Test Harness for XSLT and xpath 2 constructs</para>] (has ns)

Now you can see why this functionality is helpful.

node-name() w3c

Obtain the qualified name for a node. E.g.

[<xsl:value-of select="node-name(//xsl:template[1])"/>]
whose namespace is <xsl:value-of select="namespace-uri(//xsl:template[1])"/>

whose namespace is http://www.w3.org/1999/XSL/Transform

namespace-uri() w3c

Returns the namespace URI of the node passed as a parameter, or the current node. Example immediately above.

sequence - a literal sequence w3c

Creates one of these new sequences!

<xsl:sequence select="(1,2,3,4)" />
This shows it using a simple sequence of numbers.
the result is 1 2 3 4
Note that
<xsl:value-of select="(1,2,3,4)" separator=", "/> 
works just the same, but with the separator,
to give 1, 2, 3, 4

Another oddity is the need to use double brackets (( when specifying a sequence, as in

1. <xsl:value-of select="min((1,2,3,4))"/>
2. <xsl:value-of select="min(1,2,3,4)"/>

If the second form is used an error is reported. See this for an explanation.

Another use of this is to create a sequence containing duplicates.

<xsl:sequence select="(//h3, //h3[5])"/>
Should you ever need it.

list constructor; () as a list constructor? W3C - I think, but I could be wrong. Its well hidden

Another rather subtle use of sequences. The min() function takes a single argument, which is a sequence. So to find the minumum of two values X and Y, write

min((X, Y))
Note the double parentheses: the outer ones say that this is a list of arguments, the inner ones say that (X, Y) is a sequence containing X and Y.

It's not technically a constructor, the "," is a list concatenation operator: A,B is the concatenation of two lists. The inner parens in min((A, B)) are needed because a function argument must be an ExprSingle rather than an Expr. An ExprSingle is effectively an expression that does not contain a top-level comma. A top-level comma is not allowed here for obvious reasons - it would be taken as the separator between arguments in the function call.

Note that string-length() first parameter needs to be a single expression, ExprSingle!

sort - Sorting. w3c

An additional attribute, case-order, can take values of upper-first or lower-first, which helps with sorting.

Sorting: descending order, upper case first.

<xsl:variable name="rString"
  select="('AB','aA','c', 'dEF', 'ghij','GHj' ,'KLmno','PqrSt','uvwxy','z',
  '123', '456789')"/>


<xsl:for-each select="$rString">
<xsl:sort select="."  case-order ="upper-first" order="descending"    />
  <xsl:value-of select="." /> <xsl:text> </xsl:text>
gives: z uvwxy PqrSt KLmno GHj ghij dEF c AB aA 456789 123

Note in the above that the sort order has placed upper case first and changed the order to descending. A very useful addition.

perform-sort - Sorting function w3c

Trying to figure out the difference between xsl:perform-sort and xsl:sort. It seems to wrap xsl:sort, so I've no idea of its functionality.

Mike Kay tells me: quote. xsl:sort specifies how for-each and apply-templates should do their work. xsl:perform-sort is an instruction that does sorting and nothing else; it's useful for example if you want to sort a sequence of elements before doing a grouping operation. It's really just a shorthand for

<xsl:for-each select="xxx">
  <xsl:sort select="yyy"/>
  <xsl:sequence select="."/>

analyze-string - Analyse string, using regular expressions. w3c

analyze-string function. With a string, whose original content was "

There is some need to view this differently.
I Want to change the word need into <par>. This is done using

 <xsl:value-of select="document('')//dp:analyze-string"/>." Change need into <par>
 <xsl:analyze-string select="document('')//dp:analyze-string" 

   (<xsl:value-of select="."/>)<xsl:text/>

     <span style="color:blue"><xsl:text><par> </xsl:text> </span>

Result is :
(There is some )<par> ( to view this differently.)

Note the two child elements, matching and non-matching. I've added brackets round the 'non-matching' parts of the input, so you can see the output.

With a more complex String, the regex-group(n) can be used to pick out individual sub-groups.

Jeni Tennison gave a slightly more educational example on the list which I changed to show all the matches. It brings out a few points.

<xsl:variable name="regex" select="'(([^_]*)_PARA)'"/>
  <xsl:variable name="input" select="'ABC_PARA__PARA'"/>

    <xsl:variable name="res" as="item()*">
   <xsl:analyze-string select="$input" regex="{$regex}">
        <xsl:for-each select="for $i in (1 to 10)  return $i">
          <xsl:if test="not(string-length(regex-group(.)) = 0)">
            <match><xsl:value-of select="regex-group(.)"/>   </match>
        <mismatch><xsl:value-of select="."/></mismatch>

  <xsl:copy-of select="$res"/>

The output is:


From this, its possible to see just what is filtered within each group.

There are a total of 3 matches, sequenced as two matches, a mismatch and the last match. Note the sequence? It is ordered, and will be different if you write it directly to the output. Note also that the regex attribute is an Attribute Value Template. I presume less than 11 matches, and test each for a zero string length of the regexp-group() function. This provides a simple structure which can then be accessed programmatically to obtain the nth match, or the nth mismatch, should that be what you want.

if then else - conditional value-of? w3c

With a defined function

<xsl:function name="dp:reverse">
  <xsl:param name="sentence" as="xs:string"/>
   select="if (contains($sentence, ' '))
           then concat(dp:reverse(substring-after($sentence, ' ')),
                         ' ',
                         substring-before($sentence, ' '))
           else $sentence"

An If then else conditional, within an attribute.
Called by

<xsl:value-of select="dp:reverse('DOG BITES MAN')"/>
which (from the rec) reverses the words in a sentence.

wrong data types. w3c

Getting it wrong, Wrong data type that is. (who needs that!). Firstly the correct use. Again from the rec, a function,

<xsl:value-of select="dp:roman(34)"/>
which should turn the 34 into XXXIV.
The result is XXXIV - works fine.
Now lets pass it a string such as:
<xsl:value-of select="dp:roman('34')"/>
Result is .... well it would be, the stylesheet crashes, or more exactly, the program terminates. Saxon 8.8 gives an error of
Required type is xs:integer; supplied value has type xs:string
Transformation failed: Failed to compile stylesheet. 1 error detected.

namespace - Adding a namespace with xsl:namespace w3c

The instruction

<xsl:namespace name='xx'>http://www.dpawson.co.uk/namespace#</xsl:namespace>
adds a namespace definition to the nearest ancestor element, so in the example, the head element would be in the xx namespace. I don't think stylesheet authors are that lazy? Do you?

quotes - Changes in the use of quotes W3C

Given a string such as

<xsl:variable name="qStr" select='"Some ""Content""  with quotes"'/>
                                           ^^       ^^
(Note the quote doubling)
using the translate function,
<xsl:value-of select="translate($qStr, '"', '''  ')"/>
which is a (single => double) gives
Some 'Content' with quotes
The rule becomes: Use one kind of quotes for XML attributes, the other kind for XPath string literals. Use XML escaping for the XML attribute quotes. Use XPath escaping (i.e. doubling) for the XPath quotes.

result-document. Creating multiple output documents. Direct use W3C

Formalising the various processor extensions, this provides the way to generate more than one output document.

No idea what the schema related ... attributes are all about. The basics are shown below.

  format = qname
  href = { uri-reference }>
  <!-- Content: sequence-constructor -->

The example here writes to res-doc.html all the titles from this document and links them back into this document. Just to see what happens, I've added an additional instruction into the output. After writing the <head> element, I've added the

<xsl:namespace name='xx'>http://www.dpawson.co.uk/namespace#</xsl:namespace>
instruction. If you look at the output file (res-doc.html), you'll see this adds the namespace declaration into the element! The code is:



  <xsl:namespace name='xx'>http://www.dpawson.co.uk/namespace#</xsl:namespace>
      <title>Test output.</title>
  <xsl:for-each select="$root//h3">
    <li> <a href="exampler.html#{@id}">   <xsl:value-of select="."/></a></li>

See also an indirect use of this

current-time() - Second check on time function. W3C

Just checking. The time now is 11:25:18.93Z according to <xsl:value-of select="current-time()"/>. This should be the same time as shown at -here, since xpath says If invoked multiple times during the execution of a query or transformation, these functions always returns a consistent result

terminology. W3C

See the W3C definitions.

escape-html-uri() - Escaping Special characters in a URI W3C

Addresses the need to replace 'special' characters in such as a URL. Escapes a URI in the manner html user agents handle attribute values that expect URIs.

Given a string such as




for-each-group - A New grouping method W3C

Since this requires input, I've created a separate file for this. See this separate xslt file and this xml file . Certainly answers most of the needs of xslt users. Run the stylesheet against the xml source file and have a look at the output.

every , The Universal quantifier W3C

This uses the predicate

'every $x in ....' 
to check that each h3 element has an id value which is not empty. The syntax is:

  test="not(every $id in (//h3) satisfies (not(empty($id/@id)) and $id/@id  )) "

Of course, to show it up, there is one without the requisite id value.

Warning, h3 element found with id attribute missing/empty Content is: This heading is included to produce an error.

This heading is included to produce an error.

value Comparisons... eq, ne, is, isnot etc W3C

Those nice simple days of = and != are over. The list now is quite long. The list is:

eq  equality
ne  not equal
lt  less than
le  less than or equal
gt  greater than
ge grater than or equal
Notable points are:


  <xsl:if test="p eq ../'The cat sat on the mat'"> 

Normal string equality... except that if there is more than one p element, its an error. Now you see what they mean about comparing single values.

Node comparisons occur in the same way, except they apparently need a separate verb,

<xsl:if test="a is b">
is and isnot are the two verbs in question. The two nodes must be the same for is to return true, different for isnot to return true. The rec gives an example of the same node accessed via two different means, e.g.
  <xsl:if test=" //*[@id = 'nodeA'] is title[1]">
Returns true if the only node with the id attribute equal to string value nodeA is also first child named title.

some , The Universal quantifier.W3C

General syntax is

some variable in //xpath  satisfies (boolean expression using $variable)
Returns true if at least one selection satisfies the criterion. E.g. to search this document to make sure that at least one h3 links out to the xpath Working Draft, http://www.w3.org/TR/xpath20. The expression is:

  <xsl:if test="$x in //h3/a/@href satisfies (contains($x,'http://www.w3.org/TR/xpath20'))">
Yes, at least one h3 satisfies the condition

This gives Yes, at least one h3 satisfies the condition

Range expressions could be useful here too. E.g.

<xsl:if test="some $x in (10, 1 to 4) satisfies ($x = 3)">
  Shows up as true, i.e. the range value contains 3.

The result is Shows up as true, i.e. the range value contains 3.
Can also be used in conjunction with the predicates to act as a filter

<xsl:value-of select="(1 to 30)[. mod 5 eq 0]" separator=", "/>

gives: 5, 10, 15, 20, 25, 30

union and intercept operators. Combining sequences of node-sets W3C

The Union, Intercept and except operators work to combine sets.

<xsl:variable name="a" select="(//h3)[position() < 3]"/>
<xsl:variable name="b" select="(//h3)[(position() > 2) and (position() < 5)]"/>
<xsl:variable name="c" select="(//h3)[(position() > 3)  and  (position() < 6)]"/>
<xsl:variable name="all" select="//h3"/>

Note the variable definition. I was corrected by Mike.

<xsl:variable name="a" select="(//h3)[position() < 3]"/>
provides the document position of the first two h3 elements. Note the (//h3). There can be lots of h3 elements in the document all satisfying //h3[1].
Using 'count()' on these variable gives:
a has 2 elements
b has 2 elements
c has 2 elements

exploring $c to find its position within the document using

<xsl:for-each select="$c">
 Value is:  <xsl:value-of select="index-of($all, .)"/>...  <xsl:value-of select="text()[1]"/>
Value is: 4 ... date and time
Value is: 5 ... format-date[Time] and format-time.

Using the union function, as in

There are <xsl:value-of select="count($a union $b)"/><br />
  <xsl:for-each select="($a union $a)">
Number     <xsl:value-of select="index-of($all, .)"/>is  <xsl:value-of select="text()[1]"/> in the Union.

There are 4 in the Union.
Number 1 is base-uri()
Number 2 is error()

Intersection of b and c using:

There are <xsl:value-of select="count($b intersect $c)"/> in the intersection<br />
  <xsl:for-each select="($b intersect $c)">
Number  <xsl:value-of select="index-of($all, .)"/> is  <xsl:value-of select="text()[1]"/> <br />
There are 1 in the intersection
Number 4 is date and time

$b except $c, as in

There are <xsl:value-of select="count($b except $c)"/><br />
  <xsl:for-each select="($b except $c)">
Number <xsl:value-of select="index-of($all, .)"/> is    <xsl:value-of select="text()[1]"/> <br />
There are 1
Number 3 is system-property()

insert() Insert-before function W3C

Given some sequence, insert (or remove )an item at a given position.
<xsl:value-of select="insert-before($target-seq, $position, $what-to-insert)"/>
E.g. given a sequence

<xsl:variable name="target-seq" select="(1,2,3,4,7)"/>
<xsl:variable name="what-to-insert" select="(5,6)"/>
<xsl:variable name="position" select="4"/>

Inserting at position 4,

<xsl:variable name="result"  
select="insert-before($target-seq, $position, $what-to-insert)"/> 
(1, 2, 3, 4, 5, 6, 7) - the (5,6 ) is inserted.

remove() Remove functions W3C

Similarly, removing the 5th element

<xsl:variable name="result1"  select="remove($target-seq, 5)"/> 
gives (1, 2, 3, 4)

subsequence function W3C

As with strings, there is also the subsequence function,
<xsl:variable name='ss' select = subsequence( $target-seq $position $length)"/>
which returns the sub-sequence starting at $position and extending to $position+$length.
E.g. if $length is 2 and $position is 3 then
<xsl:variable name="result2" select="subsequence($target-seq, 3, 2)"/> 
(<xsl:value-of select="$result2" separator=", "/>) 

gives (3, 4)

avg() max() min() sum() abs() - the Numeric functions.W3C

Given a numeric variable:

<xsl:variable name="n1" select="(3,4,6,8,-1)"/>

We can play with them just a little more:
E.g. The number of items in a sequence, count($n1) gives 5
The average, avg($n1) gives 4
The max($n1) gives gives 8
The min($n1) gives -1
The sum($n1) gives 20
The absolute value of the last item gives 1 There is some type information there, but it works well without it.

idref() - Linking functions. W3C

idref(String) provides a source node for the value passed in as a parameter. E.g. this heading is linked to from the end of the document. So, using this function, I can return the content of the element linking to it, i.e.

[<xsl:value-of select="idref('lnk')/../text()"/>]

The element having idref 'lnk' contains  [A link for testing the idref function]

for loop. W3C

The for loop is provided in xpath, with syntax as shown below:

for $x in (expression) return (expression)


<xsl:for-each select="for $i in ((//h3)[position() < 3]) return ($i/text()[1])">
Value: <xsl:value-of select="."/>
gives Value: base-uri()
Value: error()
This example iterates over the sequence, returning the text().

A better example might be to use the for statement to generate a sequence, then to operate on that sequence using a function which takes that as its input. For example; I wanted to find the max number of columns in a table, so in the template for the column, I had

max(for $i in ../../row return count($i/*))

this for statement returned a sequence, and the max function provides the maximum number in that sequence.

Note: Unlike pretty much every other xpath or xslt construct, for does not change the current node so ".", relative path expressions, etc all do not work as you might expect: they all stay relative to whatever was the context outside the for. DC Apr 03.

as - Creating variables of a given type W3C

Creating a variable of specific types, using the 'as' attribute.

<xsl:variable name="ls" as="item()*"
  <xsl:sequence select="(2,5,6,7,8)" />

gives 2, 5, 6, 7, 8
Similarly, using source document content:
 <xsl:variable name="ls1" 
  select="for $i in (//h3[position() < 6]) return string-length($i) "/>
returns 14, 13, 23, 19, 38
Note: MK: 17 3 03. With Saxon 7.4 and with the November XSLT 2.0 spec, the only way to create a variable whose value is a sequence is using the select attribute.
Dates may be formed using
<xsl:variable name='today' select='xs:date("2003-06-25")'/>
Then used,
<xsl:value-of select="$today" /> 
which gives Today is 2003-06-25
Difference is -P669D

quoting, "(&quot;) character nesting: W3C

String content can now contain an easier mix of double (") and single quote (’) characters. (Note they are spread out here for clarity.) the principle is to 'escape' a quote with another one.

<xsl:value-of select=' "He said, " " Go! " " " '/> 
gives: He said, "Go!"

some and every $x - Range variables. W3C

These are 'variables' which take the form of a sequence of items, and are created using the for, some and every syntax already mentioned above.
The general form is 'some $variable in Expression satisfies SingleExpression' E.g.

1 <xsl:variable name="rv1" select="(1,3,6,6 to 16)"/> 
2 <xsl:variable name='rv2' select="some $i in (//h3) satisfies (string-length($i) < 12)"/>
3 <xsl:variable name='rv3' select="every $i in (//h3) satisfies (string-length($i) > 5) "/>

and accessed using, perhaps, value-of with a separator attribute
rv1 gives: 2| 6| 12| 12| 14| 16| 18| 20| 22| 24| 26| 28| 30| 32
rv2 gives: true
rv3 gives: true
rv4 gives: true

The range variables can also be used as predicates.

<xsl:for-each  select="(//h3)[@id][some $x in position() satisfies ($x lt 3)]">
  <xsl:value-of select="@id"/>  | 

This gives: buri | err | which is the id value of the first two h3 elements.

And finally, a use to retrieve a fixed length string. This could replace the pad function often requested, if wrapped in a function call

<xsl:variable name="param" select="5"/>
<xsl:value-of select="string-join(for $i in 1 to $param return 'X','')"/>


I.e. It returns a $param length string.

copy-of with / without namespace W3C

View source for this xsl:copy, with namespace

1. Using
<xsl:for-each select="document('')//dp:distinct">
<xsl:copy >
  <xsl:copy-of select="*|@*"   copy-namespaces = "yes"  />  
<xsl:for-each select="document('')//dp:distinct">
<xsl:copy >
<xsl:copy-of select="*|@*"    copy-namespaces = "no" />  

This gives Resulting content - which won't show correctly in a browser.

Single value Single value Single value with a difference.
Single value Single value Single value with a difference.

<dp:distinct xmlns:dp="http://www.dpawson.co.uk/namespace" 
     <dp:val1>Single value</dp:val1>
     <dp:val1>Single value</dp:val1>
     <dp:val1>Single value with a difference.</dp:val1>

And for the second one

  <dp:val1>Single value</dp:val1>
  <dp:val1>Single value</dp:val1>
  <dp:val1>Single value with a difference.</dp:val1>

Which is quite a difference? The only ns in the second one I'd agree is required.

View source for actual output

The second is restricted to the dp namespace, the first has all ns included. Seems about right.

codepoints-to-string() W3C

Converts the input Unicode code points to a string. DC gave me the example of using it to reverse a string!

<xsl:variable name="in" select="'Now is the time'"/>
<xsl:value-of select="codepoints-to-string(reverse(string-to-codepoints($in)))"/>

emit eht si woN

A simpler case. Given the sequence (41,42,x5E,30), the function converts this to AB^0

string-to-codepoints() W3C

Provides the reciprocal conversion, converting a string to a sequence of codepoints

<xsl:value-of select="string-to-codepoints('Now is the time')"/>
78 111 119 32 105 115 32 116 104 101 32 116 105 109 101

encode-for-uri() W3C

This function applies the URI escaping rules defined in section 2 of RFC 3986 to the string supplied

E.g. encode-for-uri ("http://www.example.com/00/Weather/CA/Los%20Angeles#ocean") gives

See also W3C, which has the variant function 'iri-to-uri()'

codepoint-equal() W3C

Compares two strings according to the Unicode codepoint collation. Usage

<xsl:if test="codepoint-equal($s1,$s2)">

collection(). Seems to return a number of xml instance. See W3C for more. Leakage from XQuery perhaps?

unparsed-entity-uri() W3C

Using the definition

<!ENTITY thisFile SYSTEM "ndata.txt" NDATA txt>
and a use of
<xsl:value-of select="unparsed-entity-uri('thisFile')"/>

Returned value is [file:/sgml/site2/2src/ndata.txt ]... which is the value of the entity, not its content.

unparsed-text() - get the contents of a text file. W3C


<xsl:value-of select="unparsed-text($strng,$encoding)"/>
treats the first parameter as a sequence of uri's. The second is the encoding. Using it
with a minimal file which contains some content, returns the contents of that file:

This is a plain text file, no markup,
but containing & and < , which you should see escaped.

Hence this is the one to use when you want to include plain text or similar. NDATA implies that the parser informs the processing system that it has encountered an NDATA entity reference and gives it the relevant information. It is up to the processing system to decide what to do with it. It is not parsed as XML

result-document - Indirect use W3C

As above, this uses the xsl:result-document, but here its referenced from the xsl:output element, using the format attribute to reference the xsl:result-document.

As in <xsl:result-document 

(then, as a top level element)
  <xsl:output name="newFormat" method="xml" indent="yes"/> 

See file newfile.xml for output. Note that the format is specified in an output statement, which now has a name

function-available() - Function Availability. Does your process support this? W3C

A list of functions, tested for availability. Check by running the stylesheet. This run on 04 Feb 2007. (Note: There are 111 functions in total

character-map W3C

<-- Note that this is a top level element -->

<xsl:character-map name="html">
  <xsl:output-character character="&#160;"
                        string="&amp;nbsp;" />
  <!-- tabs as four spaces -->
  <xsl:output-character character="&#x9;" string="    " />



Another oft-requested feature. Translate character x into string Y, or even entity Z. In the example: Non breaking space to the entity &nbsp;
and a tab character into 4 spaces.
When the <xsl:output element is used, the attribute character-map="name" is used to reference the mappings.

   <xsl:output method="xhtml" use-character-map="html" indent="yes"/>

would invoke the above character map. We can now use this to get our beloved entities into the output file without using DOE. Implemented in Saxon 8.8, but read the comments.

base-uri(). Stylesheet and source document name+path W3C

Using base-uri to obtain the stylesheet name as in

<xsl:value-of select="base-uri(document(''))"/>
Gives file:/sgml/site2/2src/exampler2.xsl and for source document use
<xsl:value-of select="base-uri(.)"/>
gives file:/sgml/site2/2src/exampler2.xsl, which happens to be the same in this case. Without a context, the '.' in this case, the function appears to return the stylesheet value.

That's it... for version 3.0, Built under Saxon 8.8 to Rec.

WARNING: You'll screw this up if you set xml:base prior to using this stylsheet.

xpath-default-namespace() W3C

Ever used an expression like

value-of select="vis:Visiodocument/vis:Pages/vis:Page[0]/vis:shapes/vis:shape" 
Where it appears to get longer and longer the more you type? Help is at hand. Its now possible to abbreviate this, using
<xsl:template match="Visiodocument/Pages/Page[0]/shapes/shape" xpath-default-namespace="vis">

For example to access a stylesheet template, use
   <xsl:template match="template" 
     [<xsl:value-of select="value-of/@select" 

Note that the select attribute does not have to be reverse-engineered, since this default xpath namespace does not apply to attributes... even if its not clear in the specification.

as attribute, cast to another type W3C

Also see Constructor Functions for XML Schema Built-in Types , a page or so down from the link target, which is a list of types. Unsure if its complete.

It would appear almost impossible, despite the WG's assurances, to avoid using data types and still gain the benefit of the good features of XSLT 2.0. This section shows how to convert from one to another.

See also W3C Schema, part 2, for the data type list.

I've declared a number of variables, mostly as strings, which contain other types, for example "6.0" as a string, which ensures it can be converted to a decimal. The variable list is:

<xsl:variable name="elAS"  as="element()">


<xsl:variable name="decAS" select="'3.1519'" as="xs:string"/> <xsl:variable name="intAS" select="'2'" as="xs:string"/> <xsl:variable name="boolAS" select="'true'" as="xs:string"/> <xsl:variable name="bool2AS" select="'1'" as="xs:string"/> <xsl:variable name="dateAS" select="'2003-06-16'" as="xs:string"/> <xsl:variable name="ymdAS" select="'P1Y2M3'" as="xs:string"/> <xsl:variable name="dtdurAS" select="'P3DT10H30M'" as="xs:string"/> <xsl:variable name="datetimeAS" select="'2003-06-19T08:18:05.2810Z'" as="xs:string"/> <xsl:variable name="uriAS" select="'http://www.dpawson.co.uk/xsl'" as="xs:string"/> <xsl:variable name="timeAS" select="'13:29:26.109Z'" as="xs:string"/> <xsl:variable name="xAS" select="' '" as="xs:string"/> <xsl:variable name="durAS" select="'P1Y2M3DT10H30M'" as="xs:string"/> <xsl:variable name="qnameAS" select="'dp:element'" as="xs:string"/> <xsl:variable name="base64AS" select="'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCg=='" as="xs:string"/> <xsl:variable name="strAS" select="' A string with lots of white space in it '" as="xs:string"/> <xsl:variable name="langAS" select="'en-UK'" as="xs:string"/> <xsl:variable name="nameAS" select="'ident'" as="xs:string"/> <xsl:variable name="itemAS" select="('ident', 'item', 'list3')" as="item()*"/> <xsl:variable name="attset" as="attribute()+"> <xsl:attribute name="x">attval1</xsl:attribute> <xsl:attribute name="y">attval2</xsl:attribute> <xsl:attribute name="z">attval3</xsl:attribute> </xsl:variable>

Using the following value-of statements....

String => decimal - <xsl:value-of select="xs:decimal($decAS)"/> 
String => float -   <xsl:value-of select="xs:float($decAS)"/> 
String => double -   <xsl:value-of select="xs:double($decAS)"/> 
String => integer -   <xsl:value-of select="xs:integer($intAS)"/> 
String => duration -   <xsl:value-of select="xs:duration($durAS)"/> 
String => yearMonthDuration -   <xsl:value-of select="xs:yearMonthDuration($ymdAS)"/> (note xdt ns) 
String => dayTimeDuration -   <xsl:value-of select="xs:dayTimeDuration($dtdurAS)"/> (note xdt ns) 
String => dateTime -   <xsl:value-of select="xs:dateTime($datetimeAS)"/> 
String => date -   <xsl:value-of select="xs:date($dateAS)"/> 
String => time -   <xsl:value-of select="xs:time($timeAS)"/> 
String => anyURI -   <xsl:value-of select="xs:anyURI($uriAS)"/> 
String => qname -   <xsl:value-of select="xs:QName($qnameAS)"/> 
String => untyped () -   <xsl:value-of select="xs:untypedAtomic($qnameAS)"/> 
String => base64Binary -   <xsl:value-of select="xs:base64Binary($base64AS)"/> 

String => boolean -  <xsl:value-of select="xs:boolean($boolAS)"/>(input is true) 
String => boolean -  <xsl:value-of select="xs:boolean($bool2AS)"/> (input is string 1) 
attribute =>String  - [<xsl:value-of select="$attset[1]"/>]

item()*=> String - 
<xsl:for-each select="$itemAS">
 Item  <xsl:value-of select="position()"/> [<xsl:value-of select="."/>]
Noting that item()* is the new lowest common denominator.

This gives:
String => decimal - 3.1519
String => float - 3.1519
String => double - 3.1519
String => integer - 2
String => duration - P1Y2M3DT10H30M
String => yearMonthDuration - P1Y2M (note xdt ns)
String => dayTimeDuration - P3DT10H30M (note xdt ns)
String => dateTime - 2003-06-19T08:18:05.281Z
String => date - 2003-06-16
String => time - 13:29:26.109Z
String => anyURI - http://www.dpawson.co.uk/xsl
String => untyped () - dp:element
String => base64Binary - <xsl:value-of select="xs:base64Binary($base64AS)"/> Not in 8.8
String => boolean - true(input is true)
String => boolean - true (input is string 1)
attribute =>String - [attval1, attval2, attval3]
item()*=> String -
Item 1 [ident]
Item 2 [item]
Item 3 [list3]
Noting that item()* is the new lowest common denominator.

test attribute changes. Reduction in verbosity / test on a sequence

One of the additions that I find useful is the ability to test if some piece of source document content is one from a,b,c,d. For instance, in 1.0 to test if an attribute value is a or b or c or d its necessary to write

   <xsl:if test="@attVal = 'a' or @attval='b' ...... ">

With XSLT 2.0 its possible to write

    <xsl:if test="@attVal = ('a','b','c','d')">

Note that this is usable in any test scenario, e.g. xsl:if, xsl:when etc.

collation W3C

This is novel.. for me. If you need a specific sort sequence, then this is helpful. As an example, I'm using a suite of input data as follows:

<?xml version="1.0" encoding="utf-8" ?>

Of note is the Mword Nword pair. I want to sort these in reverse order, N before M. The xslt is shown below.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

Note the saxon namespace.

Note the name attribute, referred to later, and the class attribute... a java collator; see below. The specification states that N comes before M Then the actual sort:
  <xsl:template match="/">
        <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8" />

  <xsl:template match="doc">
      Before:  <br />

  <xsl:for-each select="word">
      <xsl:value-of select="."/> <br />
<hr />

    <b>After</b> <br />

  <xsl:for-each select="word">
   <xsl:sort select="."  
   <xsl:value-of select="."/> <br />


The sort element refers back to the named collation, mylang. Finally the java that does the sort.
import java.text.Collator;
import java.text.RuleBasedCollator;
import java.text.ParseException;
import java.lang.StringBuffer;
import java.io.FileReader;
import java.io.BufferedReader;

import java.io.Serializable;
import net.sf.saxon.xpath.XPathException;
import net.sf.saxon.om.Item;
import java.io.File;

 *Class mylang. Implements java.util.Comparator as a collator
public class mylang implements java.util.Comparator,Serializable {

    public String ruleFileName="collator.txt";
     * Constructor 
     * Inits the rules from the given rules file.
    public mylang (){
	String rules = getRules(ruleFileName);

     * Compare two objects.
     * o1 < o2  return -1
     * o1== o2  return 0
     * o1 > o2  return 1
     * @param o1 first object
     * @param o2 second object
     * @return int: -1 less than, 0 equal, +1 gt
    public int compare (Object o1, Object o2) {
	int res= 0;
	String s1 ="";
	String s2 = "";
        try {
            s1 = (o1 instanceof String ? (String)o1 : ((Item)o1).getStringValue());
        } catch (XPathException err) {
            throw new ClassCastException("Cannot convert sort key from " + o1.getClass() + " to a string");

   try {
            s2 = (o2 instanceof String ? (String)o2 : ((Item)o2).getStringValue());
        } catch (XPathException err) {
            throw new ClassCastException("Cannot convert sort key from " + o2.getClass() + " to a string");

	RuleBasedCollator collator =  null;
	String rule = getRules(ruleFileName);

	try {
	    collator =  new RuleBasedCollator(rule);}
	catch (ParseException err) {
	    System.out.println("collator error: " +err.getMessage() + "Quitting" );

	return collator.compare(s1,s2);
     * Compares another collator with this one.
     * @param o1, the collator to be compared with this one.
     * @return boolean, always false. Not implemented.
    public boolean equals (Object o1) {
	return false;


     *Read a set of rules into a String
     *@param filename  name of the file containing the rules
     *@return String, the rules
    private String getRules(String filename) {
	String res="";
	    BufferedReader reader = 
		new BufferedReader (new FileReader (filename));
	    StringBuffer buf=new StringBuffer();
	    String text;
	    try {
		while ((text=reader.readLine()) != null)
		    buf.append(text + "\n");
	    }catch (java.io.IOException e) {
		System.err.println("Unable to read from rules file "+ filename);

	}catch (java.io.FileNotFoundException e) {
	    System.out.println("Unable to read Rules file, quitting");
	return res;
    }// end of getRules()

     *sort an array of strings according to the collator .
     *@param collator collator to use
     *@param words - words to sort
     *@return null.
   public static void sortStrings(Collator collator, String[] words) {
       String tmp;
       for (int i = 0; i < words.length; i++) {
           for (int j = i + 1; j < words.length; j++) {
               // Compare elements of the words array
               if( collator.compare(words[i], words[j] ) > 0 ) {
                   // Swap words[i] and words[j] 
                   tmp = words[i];
                   words[i] = words[j];
                   words[j] = tmp;
     *print an array of strings.
     *src: http://java.sun.com/docs/books/tutorial/i18n/text/rule.html
   public static void printStrings(String [] words) {
       for (int i = 0; i < words.length; i++) {
     *Default entry point for command line testing.
    public static void main (String [] argv) {
	RuleBasedCollator collator =  null;
	mylang mc = new mylang();
	String rule = mc.getRules(mc.ruleFileName);
	try {
	    collator =  new RuleBasedCollator(rule);}
	catch (ParseException err) {
	    System.out.println("collator error: " +err.getMessage() );

	String [] words = {
	    " hello",
	    "Mother","Not", "4hello",
	// print before sorting
	System.out.println("Initial Strings\n\t\t");
	mc.sortStrings(collator, words);
	System.out.println("\t\tPost sort");

You either follow this or not I guess. The actual rules are read in from a file, collator.txt, at runtime. This file is as follows:
  ' ' ,  ':' ,  ';' ,  '<'  , '=' ,  '>'  , '?' ,  '@', '!',
 '[' ,  '\' ,  ']' ,  '^' ,  '_' ,  '`',
 '{' ,  '|' ,  '}' ,  '~'
 '!' ,  '"' ,  '#' ,  '$' ,  '%' ,  '&',  ''' ,  '(' ,  ')' ,  '*'  , '+'  , ','  , '-' , '.' ,  '/'

< A,a  < B,b  < C,c  < D,d  < E,e  < F,f  < G,g
< H,h  < I,i  < J,j  < K,k  < L,l < N,n   < M,m 
< O,o  < P,p  < Q,q  < R,r  < S,s  < T,t
< U,u < ü  < V,v  < W,w  < X,x  < Y,y  < Z,z

< 0  < 1  < 2  < 3  < 4  < 5  < 6  < 7  < 8  < 9
Note that N is specified to sort before M. On running this the following output is generated:



Which has sorted, N before M, as required.

Note: As of Aug 03, Saxon uses saxon:collation as follows.

idiv, integer Division W3C

Integer division. Produces an int from a pair of ints.

        <xsl:variable name="i1" select="5" as="xs:integer"/>
        <xsl:variable name="i2" select="2" as="xs:integer"/>
    a result of      <xsl:value-of  select="$i1 idiv $i2"/>
5 idiv 2 gives a result of 2

analyze-string() and regex Groups w3c

When using XSLT to mark up what is essentiall plain text, the grouping facility of the regexp facility may be used, as in this example provided by David Carlisle.

With an input file such as:


<r>Mateus 3.1-12; Lucas 3.1-20; </r>
<r>words 1.2-12; Name 1.2-30</r>
<r>LongString 1234.3-45; swd 1.2.1-2</r>

The following stylesheet fragment produces output as:
<?xml version="1.0" encoding="UTF-8"?>

   <canonRef Book="Mateus" chapter="3" verse="1" verseend="12" />
   <canonRef Book="Lucas" chapter="3" verse="1" verseend="20" />

   <canonRef Book="words" chapter="1" verse="2" verseend="12" />
   <canonRef Book="Name" chapter="1" verse="2" verseend="30" />

   <canonRef Book="LongString" chapter="1234" verse="3" verseend="45" />

  <xsl:template match="doc">
<xsl:template match="r">
  <xsl:analyze-string  regex="[^;]+" select=".">
      <xsl:analyze-string  regex="([A-Za-z]+) *([0-9]+)\.([0-9]+)-([0-9]+)(.*$)" select=".">
        </xsl:analyze-string >

Note that each pattern in the regular expression, as defined by the braces, results in a seperable attribute.

The final group (.*$) is there for debug purposes, catching the remainder of output until the correct regexp strings are in place.

unordered() function. W3C

Weird one this. From the rec, This function takes a sequence or more typically, an expression, that evaluates to a sequence, and indicates that the result sequence may be returned in any order.
For example.

    <xsl:variable name="ls" select="unordered(1 to 3)"/>
    <xsl:for-each select ="$ls">
      <xsl:value-of select="."/> <xsl:text> </xsl:text>

1 2 3

Which appears of little use to me

xpath-default-path W3C

Maybe due to confusion over namespaces, or just to save typing, when dealing with a namespaced document, whereas in 1.0, we had to write

      <xsl:template match="ns:elementName" xmlns:ns="somethingOrOther">
we can now write
and the processor assumes all xpath expressions are in that namespace. Neat!

data() function W3C

WD says, Summary: data() takes a sequence of items and returns a sequence of atomic values. It returns the typed value of the node passed as parameter. For how it gets from one to the other see the WD. MK offered a use case; testing to see if this node a boolean?

  <xsl:if test="data(.) instance of xs:boolean">
    This node holds some data of type boolean.

deep-equal(), W3C

Tests for equality. The spec defines this as (it is not straightforward)

they must either be atomic values that compare equal, or nodes of the same kind, with the same name, whose children are deep-equal.

With two simple variables it shows as follows:

<xsl:variable name="de1" select="(1,2,3,4,5)" as="item()*"/>
<xsl:variable name="de2" select="(1,2,3,4,5)" as="item()*"/>

<xsl:value-of select="if (deep-equal($de1,$de2)) then 'equal' else 'not equal'"/>

Gives:  equal

exactly-one(), W3C

An attempt to catch errors early. You judge if it succeeded.

Note that this seems a little pointless. It does not inform a user that a variable has more than one item or not. It raises an error if the parameter has more than one item! Hence I can write

<xsl:variable name="singular" select="(1)" as="item()*"/>
<xsl:variable name="multiple" select="(1,2,3)" as="item()*"/>

<xsl:if test="exactly-one($singular)">
Singular has exactly one item.

yet I get an error with 

<xsl:if test="exactly-one($multiple)">
Singular has exactly one item.

It seems to be a 'desperate measures' check on the typing system. Note also one-or-more and zero-or-one(), both similar in operation

tunnelling, W3C

The rule for named templates is exactly the same as for apply-templates: you only declare the parameter at the two ends of the tunnel: when the parameter is first created using xsl:with-param, and in a template that actually uses it with xsl:param.

A tunnel parameter is created by using an xsl:with-param element that specifies tunnel="yes". A template that requires access to the value of a tunnel parameter must declare it using an xsl:param element that also specifies tunnel="yes".

format attribute, Number formatting W3C>

The available forms of formatted numbers seems to have grown. Mike Kay posted an example to the list,

<xsl:variable name="val" select="1356" as="xs:integer"/>
<xsl:number value="$val" format="w"/>
Which produces, one thousand three hundred and fifty six
I.e. the number is converted to its word format!

Or, given a sequence,

<xsl:variable name="seq" select="(1, 3, 5)" />
The result of
<xsl:number value="$seq" format="A I w"/>
is A III five

remove(), remove an item from a sequence, W3C

remove($target, n ) as item()* is the description. From the target remove the nth item. This struck me as useful for recursive templates, where you want to process the cdr of the current node-set, i.e. everything except the first element. In which case the use would be

  <xsl:template name="recurse">
    <xsl:param name="ns"/>    
... test for exit condition
... if more
    <xsl:call-template name="recurse">
      <xsl:with-param name="ns" select="remove($ns,1"/>

Bit more elegant than 1.0?

modes, Select all modes W3C

Where you want to have something like <xsl:template match="X" mode="*"/>,XSLT 2.0 now allows mode="#all"

except, Union and Intersection.

Mike Kay offers this example of use. Given

 $a= 1,2,3   
 $b= 2,3,5
 $a minus $b = 1
 $a differences to $b = 1,5
except implements a mathematical set difference operation: $a except $b returns all nodes that are in $a excluding those that are also in $b. So it is asymmetric, as you observe. If you want all the nodes that are in one set and not both you could do
($a union $b) except ($a intersection $b)
($a except $b) union ($b except $a)

doc-available(). W3C

Returns true if a parsable entity is passed as a parameter

<xsl:value-of select="if (doc-available('newfile.xml')) then
'File newfile.xml exists, and is XML' else 'File not found'"/>


File not found

since the file exists.

document() and doc(). W3C and W3C

Document() is no different from the same function in XSLT 1.0

doc(), Retrieves a document using a URI supplied as an string. If the URI is not valid an error is raised. If it is a relative URI Reference, it is resolved relative to the value of the base URI property from the context. I.e. its simpler.

document-uri() W3C

Returns the URI of the node passed as a parameter, e.g. for this document it is:

<xsl:value-of select="document-uri(.)"/> gives file:/sgml/site2/2src/exampler2.xsl

prefix-from-QName() W3C

Provides the associated prefix given a namespace. E.g.

<xsl:value-of select="prefix-from-QName(node-name(/d:doc))"/> gives d
which is clearly correct!

QName() W3C

Provides the qualified name from the given parameter. E.g.

 <xsl:value-of select="QName('http://www.dpawson.co.uk/ns#','dp:doc')"/> gives dp:doc
As to a purpose for this... type conversion I guess.

in-scope-prefixes() W3C

Just as it says on the tin? E.g. for the stylesheet root this gives xml xsl saxon xs xdt d pref dp for

<xsl:value-of select="in-scope-prefixes(/xsl:stylesheet)"/>

lang() W3C

Boolean, checking if the language of the node specified matches that of the first param. E.g. I've set the language of this stylesheet to en-UK, of which en is a subset. Hence

<xsl:value-of select="if (lang('en',/xsl:stylesheet)) then 'English' else 'not English'"/> gives: 

number() W3C

Convert the argument to a number... if possible

E.g. xsl:value-of select="number('3.151492')"/> gives 3.151492

round-half-to-even() W3C

rounds a numerical value. Precision may be specified in second parameter.

3.5 rounds to 4
2.8 rounds to 3
1.567,2 rounds to 1.57
-1.4 rounds to -1
-1.5 rounds to -2
-1.567,2 rounds to -1.57

The second parameter is the required precision.

round() W3C

rounds a numerical value.

3.5 rounds to 4
2.8 rounds to 3
1.567 rounds to 2
-1.4 rounds to -1
-1.5 rounds to -1
-1.567 rounds to -2

The second parameter is the required precision.

static-base-uri() W3C

Returns the base URI of the context. E.g.

<xsl:value-of select="static-base-uri()"/> shows file:/sgml/site2/2src/exampler2.xsl
Note that this file is the source file (as well as the stylesheet).

comparison operators W3C

Note we have a number of ways of comparing nodes, items, atomic values etc. Just take care and use the right one.

 <xsl:variable name="s1" select="(1,2,3,4)"/>
 <xsl:variable name="s2" select="(1,2,3,4)"/>
 <xsl:variable name="s3" select="(1,2)"/>

  $s1 = $s2 gives true 
  //h3[@id='buri'] is (//h3)[1]  gives true 
  first h3 is before second h3, gives true 
  $s1[1] eq $s2[1] gives true
  $s1 = $s2 gives true

and the odd ones, from Mike Kays book.

<xsl:value-of select = "$s2 = $s3"/>
shows as 
since '2' is common to both sequences!

A slightly more useful case is testing for a value being one of a number of options. E.g.

  <xsl:variable name="color" select="'blue'"/>
  <xsl:if test="$color = ('red','blue','green')">
    color is in the set!
    color is in the set!

indicating that the value of the color variable has one of the stated values.

next-match W3C

The rec says The xsl:next-match instruction considers all other template rules of lower import precedence and/or priority. A practical use of this might be to perform two distinct sets of processing on the same node.

Rather than perform this in one template, two templates matching the same node, of differing priority, may be used. The higher priority template is run first and the xsl:next-match is used to invoke the lower priority template.

A link for testing the idref function

Basic references. operators, XSLT the data model, the XPATH 2 Functions and Operators and xpath 2. And in case you were wondering, the silly data types are borrowed from Schema jobbie, part 2 and Data model

And if you are as confused about namespaces, see the top of this xslt source file, or look at 2.0 Basics, in XPath, near the end of that section. . Of particular note is that xmlns:xs="http://www.w3.org/2001/XMLSchema" has changed. Don't be caught out.