Oliver Becker, System Architecture, Department of Computer Science, Humboldt University Berlin .


XSLT Stylesheets

Useful things and other jokes

On this page:

All the XML documents provided are rendered additionally with xmlverbatimwrapper.xsl for viewing with a pure HTML browser - the link is named "(pretty HTML)".

The stylesheets were tested under Linux with the following XSLT processors:

XT  XT 19991105 (using Xerces 1.0.3)
Saxon  Saxon 5.4.1 (using built-in Ælfred)
Xalan  Xalan-Java 1.1 (using Xerces 1.1.2)
Oracle  Oracle XML

Comments, feedback, praise and criticism welcome!

XML to HTML Verbatim Formatter with Syntax Highlighting

Version 1.1 / 2002-08-22 (change log)
Runs with:  Saxon  Xalan

This stylesheet renders an XML source in HTML. Via a CSS stylesheet you may define your custom style of display. The package consists of three files:

Known problems:
Output of attributes isn't optimal. Because of the XML information set there's no information how attributes are ordered and indented in the source document. Therefore all attributes appear in one line. They are separated by normal spaces, so the browser wraps long lines if necessary. The same applies to namespace declarations.

XT and Oracle don't implement the namespace axis, so these processors won't work with my stylesheet.

The Sieve of Eratosthenes

No version number - this is just a fooling / 2000-06-13
Runs with:  XT  Saxon  Xalan  Oracle

This stylesheet computes prime numbers according to the known algorithm "Sieve of Eratosthenes" - see related information on the prime pages.

This isn't really a stylesheet - in the literally meaning. It does nothing with the input. Use it on a source document of your choice, e.g. on itself. Therefore the extension and namespace prefix I chose are xslt, the root element is xslt:transform - but that's just a matter of style and layout.

Possibly you need to downsize the global parameter bound (default 1000). Oracle's XSLT processor doesn't like it and produces a StackOverflowError.

Example (using saxon) gives:

saxon eratosthenes.xslt eratosthenes.xslt

2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,

An XSLT Loop Compiler

Version 1.0 / 2000-07-06
Runs with:  XT  Saxon  Xalan  Oracle
Error reporting functions with:  Saxon  Oracle

This is an XSLT transformation sheet which expands special iteration elements (<loop:for> and <loop:while>) into recursive template calls. Since the explanation of how these iteration elements must be used is somewhat detailed I've put this on a separate page.
Note: all my iteration stylesheets carry the extension ".lxsl" (loop XSL).


Usage example for total-sales.lxsl (using saxon):

saxon total-sales.lxsl loop-compiler.xslt > total-sales.xsl
saxon booklist.xml total-sales.xsl

Total sales value is: $1798.53

Around 50% of the stylesheet code performs validation. This could be separated.
Validation works not as expected with XT and Xalan. Though these processors report the number of errors and stop, they conceal which errors occurred. However, translation of correct code works.

Merging two XML Documents

Version 1.6 / 2002-07-05 (change log)
Runs with:  XT  Saxon  Xalan*
(*) more or less correctly ... particularly if the input documents contain elements with prefixed attributes

This transformation sheet merges two XML documents.

What does "merging" mean?
Consider the following documents:

   <!-- file1.xml -->
<theme id="appl">
<title xml:lang="nl">Toepassingen</title>
   <!-- file2.xml -->
<theme id="doc" />
<theme id="appl">
<title xml:lang="en">Applications</title>

After merging these two, the result document will be

   <!-- file1.xml -->
   <!-- file2.xml -->
<theme id="doc" />
<theme id="appl">
<title xml:lang="nl">Toepassingen</title>
<title xml:lang="en">Applications</title>

That means equivalent nodes appear only once in the output. Two element nodes are treated equivalent, their local names are equal, their namespace-uris are equal, and all their attributes are equal. Two text nodes are treated equal if their normalized content is equal. The same rule applies for comments and processing instructions. Normalization can be switched off via the stylesheet parameter "normalize" (set to any other value different from "yes").

The replace mode may be activated via the stylesheet parameter "replace" (set to any arbitrary value). In this mode text nodes in the first document will be replaced by corresponding nodes from the second document. The replace mode only affects text nodes for which in non-replace mode the algorithm must look for an equivalent node.

The order of all nodes will be preserved. That means merging won't work, if the relative position of equivalent nodes in the given files is different (e.g. it's not possible to merge <a/><b/> with <b/><a/>).

You may specifiy an element name with the dontmerge parameter, so that all elements with this name won't be merged. For example, if you want all the theme elements above to appear then the result would be

   <!-- file1.xml -->
   <!-- file2.xml -->
<theme id="appl">
<title xml:lang="nl">Toepassingen</title>
<theme id="doc" />
<theme id="appl">
<title xml:lang="en">Applications</title>

Note: The indentation may look a little bit weird, but that's the output the stylesheet produces.


Variant 1:
Provide a document with the following contents and use it as XML source for the transformation:

   <merge xmlns="http://informatik.hu-berlin.de/merge">

Variant 2:
Use file1.xml as source document and specify file2.xml as value for the parameter "with". For example:
saxon file1.xml merge.xslt with=file2.xml > result.xml

Specifying a name for elements which shouldn't be merged:
Use the parameter "dontmerge". For example:
saxon file1.xml merge.xslt with=file2.xml dontmerge=theme > result.xml

Quine: The Self-Reproducing Stylesheet

No version number - just another fooling / 2000-08-12
Runs with:  XT  Saxon  Xalan  Oracle

The following stylesheets are self-reproducing programs, i.e. they transform any input to a copy of the stylesheets itself.

Such programs are called quines: A quine is a program which reproduces itself on an output device without inputting its source (see The Quine Page by Gary P. Thompson).

While this seems to be challenging in languages which don't handle program logic as data, it's fairly simple in XSLT. Don't you think ...?

The following stylesheet quine.xslt is a true quine, while self.xslt is a cheat ...

Since there are some things in the output of an XSLT processor that can't be controlled by the stylesheet (e.g. outputting < as &lt;, &#60;, or &#x3C;), you should create the "real" self-reproducing stylesheet by running quine.xslt resp. self.xslt once with your preferred XSLT engine. The resulting stylesheet then outputs - on this chosen engine - exactly its source code. So these stylesheets are in fact quine-producing or self-reproducing-producing programs ;-)

A trace utility for XSLT stylesheets

Version 0.2 / 2002-02-13 (change log)
Runs with:  Saxon  (haven't checked other processors ...)

This is a transformation stylesheet which transforms any given XSLT stylesheet into a version with additional trace functionality. In this way all the processed nodes of the XML input document and all used templates of the stylesheet can be tracked.

The modified stylesheet outputs trace messages via the xsl:message mechanism. The format for every processed node is as follows:

node: [XPath to this node]
   stack: [call stack of the templates invoked]
   param: name="[parameter name]" value="[parameter value]"
   more parameters ...
   variable: name="[variable name]" value="[variable value]"
   more variables ...

The call stack takes the form of a path (with '/' as separator) and includes all passed templates. If a template has a name attribute then this name is used. Otherwise the number (position) of the template appears within the stack. If the current template doesn't have a name, the match attribute will additionally be displayed. If a mode attribute was specified it's value will also be displayed.

Using the Eratosthenes stylesheet on itself and a bound parameter of 4, the trace output starts with

node: /xslt:transform[1]
   stack: /1 (match="/")
node: /xslt:transform[1]
   stack: /1/init-array
   param: name="length" value="4" 
node: /xslt:transform[1]
   stack: /1/init-array/init-array
   param: name="length" value="3" 

Ok, in this example the context node never changes, but you get the idea.

Known problems:
The output for parameters or variables is their string value (produced with xsl:value-of). That's not reasonable for node-sets and result-tree-fragments. On the other hand: using xsl:copy-of results in an error if the variable contains attribute or namespace nodes. But how to detect the type of a variable value?

This is version 0.2, I think there are a lot of extension possibilities.

Want more "stupid XSLT tricks"?

Have a look at the Gallery of Stupid XSLT Tricks by Charlie Halpern-Hamu.

Related information and reading:

XSL Transformations (XSLT) Version 1.0, W3C Recommendation 16 November 1999
XML Path Language (XPath) Version 1.0, W3C Recommendation 16 November 1999
Michael Kay: "XSLT Programmer's Reference, 2nd Edition", Wrox Press, 2001
Miloslav Nic: XSLT and XPath tutorials, ZVON
G. Ken Holman: "Practical Transformation using XSLT and XPath", Crane Softwrights Ltd
Dave Pawson's XSL Frequently Asked Questions

© ob Monday, 04-Nov-2002 11:48:34 CET .