1. Introduction
2. Examples
3. Transformation Class

1. Introduction

Here you can follow the different XSL-T examples to learn more about the XSL-T basics. We introduce different concepts about XSL-T, one step at a time.

When you want to try these examples for yourself, you can use this little program to do the transformations.

2. Examples

2.1. Examples - Source Document

Here is the source XML document we will use to transform into something else, using XSL-T documents. The document represents the contents of a (extremely) simple book.

In this case it is a file named 'book.xml'.


<?xml version="1.0" encoding="UTF-8"?>
<book>
	<author>
		<first-name>Mark</first-name>
		<last-name>Meyers</last-name>
	</author>
	<content>
		<chapter>
			<title>About XML</title>
			<p>aaa</p>
			<p type='quote'>bbb</p>
			<p>ccc</p>
		</chapter>
		<chapter>
			<title>About XSL-T</title>
			<p>ddd</p>
			<p type='quote'>eee</p>
		</chapter>
		<chapter>
			<title>About XSL-FO</title>
			<p type='important'>fff</p>
			<p>ggg</p>
			<p>hhh</p>
		</chapter>
	</content>
</book>

2.2. Example 1

Let's have our very first XSL-T example.


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="chapter">
    <xsl:value-of select="title" />
  </xsl:template>
</xsl:stylesheet>

What happens here is that we copy the text content of each <title> that is a direct child of a <chapter> element to the output document. Remark that the result of our transformation is just a plain text file, not XML. Also, some whitespace that was present in our book.xml is copied to the output.

This is the output:

	
		Mark
		Meyers
	
	
		About XML
		About XSL-T
		About XSL-FO

2.3. Example 2 - Add Index

Now, what would happen when we copy the template twice?


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:template match="chapter">
		1. <xsl:value-of select="title" />
	</xsl:template>
	<xsl:template match="chapter">
		2. <xsl:value-of select="title" />
	</xsl:template>
</xsl:stylesheet>

It might not be completely what you would expect, but this might be the result:


	
		Mark
		Meyers
	
	
		
		2. About XML
		
		2. About XSL-T
		
		2. About XSL-FO
	

The reason is that there is an implicit, built-in template rule, that selects the root node ( <book> in our case) and all of the other elements and then applies the appropriate templates for the children recursively.

If more than one template matches an element, like <chapter> , the most specific one is used. When two templates have equal priority, a parser may select one or stop processing (it is an error when that happens).

Now we will replace the built-in rule with another one, it matches "/" which is the root element; we could also write <xsl:template match="book"> in this case, it would mean the same thing.

Similarly, we could replace '*' with 'book' in either of the apply-templates like this: <xsl:apply-templates select="book" /> . '*' means 'any node' in this context. But since the


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:template match="/">
		<xsl:apply-templates select="*" mode="xx" />
		<xsl:apply-templates select="*" />
	</xsl:template>
	<xsl:template match="chapter" mode="xx">
		1. <xsl:value-of select="title" />
	</xsl:template>
	<xsl:template match="chapter">
		2. <xsl:value-of select="title" />
	</xsl:template>
</xsl:stylesheet>


	
		Mark
		Meyers
	
	
		
		1. About XML
		
		1. About XSL-T
		
		1. About XSL-FO
	

	
		Mark
		Meyers
	
	
		
		2. About XML
		
		2. About XSL-T
		
		2. About XSL-FO
	

2.4. Example 3 - Generating The Book

We will take a few steps small steps in this example.

First we will change our output to generate an almost well formed xhtml document. Almost, since we omit the 'head' and 'title' elements just to make it more readable. To make this happen, we add the xhtml namespace to our xsl template:

<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns='http://www.w3.org/1999/xhtml'>
	...

The xmlns='http://www.w3.org/1999/xhtml' attribute of the root element makes the default namespace of our document 'xhtml', therefore <html> , <h1> etc. are known to belong to the xhtml namespace. We could have declared xmlns:xhtml='http://www.w3.org/1999/xhtml' in combination with <xhtml:h1> and so on, but <h1> would then be illegal.

This is also the reason the root element in the output has the same namespace declaration, you don't have to do that separately.

Then we change the first template to include some xhtml tags, surrounding te index with unordered list ('ul') tags. Then we surround the titles with list item ('li') tags.

The second step is to remove the author's name from the index, it still is appearing twice in the document. The built-in template rule generates this output, defining a template that will 'consume' the node will suffice to suppress unwanted output:

	
	<xsl:template match="author" mode="index">
		<!-- Do nothing -->
	</xsl:template>

Our index is now finished.

The third step is to generate the body of our book.

Instead of selecting the title for each chapter, we select all children with the '*'. Then we create a dedicated template for each specific child.

For title and p we use a different select ('text()' and '.') with the same result: the text content of the element is returned.

We have two templates for the 'p' child, but the second is more specific, it matches element 'p' having an attribute 'type' with the value 'important'. Note that each 'p' element is still matched only once (disregarding the index mode templates).

	<xsl:template match="p[@type='important']">
		 <p>Important: <span style="color: red;"><xsl:value-of select="text()" /></span></p>
	</xsl:template>	

Here is the complete stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns='http://www.w3.org/1999/xhtml'>
	
	<xsl:template match="/">
		<html>
		<body>
		<ul><xsl:apply-templates select="*" mode="index" /></ul>
		<xsl:apply-templates select="book" />
		</body>
		</html>
	</xsl:template>
	
	<xsl:template match="author" mode="index">
		<!-- Do nothing -->
	</xsl:template>
	<xsl:template match="chapter" mode="index">
		<li><xsl:value-of select="title" /></li>
	</xsl:template>
	
	<xsl:template match="chapter">	 
		<xsl:apply-templates select="*" />
	</xsl:template>
	<xsl:template match="author">
		<h1>A Book by <xsl:value-of select="first-name" /> <xsl:value-of select="last-name" />.</h1>
	</xsl:template>
	<xsl:template match="title">
		 <h2><xsl:value-of select="text()" /></h2>		 
	</xsl:template>
	<xsl:template match="p">
		 <p><xsl:value-of select="." /></p>		 
	</xsl:template>
	<xsl:template match="p[@type='important']">
		 <p>Important: <span style="color: red;"><xsl:value-of select="text()" /></span></p>
	</xsl:template>	
</xsl:stylesheet>

And here is the output, after a bit of reformatting:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
	<ul>
		<li>About XML</li>
		<li>About XSL-T</li>
		<li>About XSL-FO</li>
	</ul>
	<h1>A Book by MarkMeyers.</h1>
		<h2>About XML</h2><p>aaaHAHA</p><p>bbb</p><p>ccc</p>
		<h2>About XSL-T</h2><p>ddd</p><p>eee</p>
		<h2>About XSL-FO</h2><p>Important: <span style="color: red;">fff</span></p><p>ggg</p><p>hhh</p>
</body></html>

3. Transformation Class

When you are using Java, here is a small program that will work on the command line. In Eclipse choose Run > Open Run Dialog... > Arguments (tab) > Program arguments (editor) and type the arguments.

If the last of the tree file paths ends with "txt" the xml declaration is ommited.


package be.ooxs.example.xml;

import java.io.File;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class Transformation {
	public static void main(String[] args) throws TransformerException {
		if (args.length != 3) {
			printUsage();
		} else {
			File inputFile = new File(args[0]);
			File outputFile = new File(args[1]);
			File xslFile = new File(args[2]);

			Source source = new StreamSource(inputFile);
			Result target = new StreamResult(outputFile);
			Source xsl = new StreamSource(xslFile);

			boolean plainTextOutput = args[1].endsWith("txt");
			transform(source, target, xsl, plainTextOutput);
		}
	}

	private static void printUsage() {
		System.out.println("Need 3 parameters xml:");
		System.out.println("\txml source file");
		System.out.println("\tfilename where to write the result");
		System.out.println("\txsl-t file");
		System.out.println();
		System.out.println("example: java be.ooxs.example.xml.Transformation /tmp/book.xml /tmp/tofo.xsl /tmp/book-fo.xml");
	}

	public static void transform(Source source, Result target, Source template, boolean plainTextOutput) throws TransformerException {
		TransformerFactory factory = TransformerFactory.newInstance();
		Transformer t = factory.newTransformer(template);
		t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, plainTextOutput ? "yes" : "no");
		t.transform(source, target);
	}
}