XSLT Tutorial - Basics: Difference between revisions

The educational technology and digital learning wiki
Jump to navigation Jump to search
Line 72: Line 72:
=== Root of an XSLT file stylesheet ===
=== Root of an XSLT file stylesheet ===


  <?xml version="1.0"?>
<source lang="xml">
  ''&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;''
  <?xml version="1.0"?>
  ''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">''
  ''....''
  ''....''
  ''&lt;/xsl:stylesheet&gt;''
  ''</xsl:stylesheet>''
</source>


; Mandatory elements
; Mandatory elements
Line 82: Line 84:
* A '' stylesheet'' root tag with the following version and namespace attributes:
* A '' stylesheet'' root tag with the following version and namespace attributes:


   &lt;xsl:stylesheet ''version="1.0"'' ''xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'' &gt;
<source lang="xml">
   <xsl:stylesheet ''version="1.0"'' ''xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'' >
</source>


* XSLT must be wellformed (and also obey the XSLT specification)
* XSLT must be wellformed (and also obey the XSLT specification)
Line 91: Line 95:
You can directly associate a XSLT stylesheet with an XML file by using a so-called processing instruction (similar principle as [[CSS]] stylesheets)
You can directly associate a XSLT stylesheet with an XML file by using a so-called processing instruction (similar principle as [[CSS]] stylesheets)


&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;
<source lang="xml">
  &lt;''?xml-stylesheet'' ''href="project.xsl" type="text/xsl"'' ?&gt;
<?xml version="1.0" encoding="ISO-8859-1"?>
  &lt;yourxml&gt;
  <''?xml-stylesheet'' ''href="project.xsl" type="text/xsl"'' ?>
  <yourxml>
     ....  
     ....  
  &lt;/yourxml&gt;
  </yourxml>
</source>


=== Basic XSLT ===
=== Basic XSLT ===
Line 112: Line 118:
XML Source we want to translate:
XML Source we want to translate:


&lt;title&gt;Hello friend&lt;/title&gt;
<source lang="xml">
<title>Hello friend</title>
</source>


The XSLT rule that does it:
The XSLT rule that does it:
Line 124: Line 132:


* hello.xml
* hello.xml
 
<source lang="xml">
&lt;?xml version="1.0"?&gt;
<?xml version="1.0"?>
  ''&lt;?xml-stylesheet href="hello.xsl" type="text/xsl"?&gt;''
  ''<?xml-stylesheet href="hello.xsl" type="text/xsl"?>''
  &lt;page&gt;
  <page>
   &lt;title&gt;Hello&lt;/title&gt;
   <title>Hello</title>
   &lt;content&gt;Here is some content&lt;/content&gt;
   <content>Here is some content</content>
   &lt;comment&gt;Written by DKS.&lt;/comment&gt;
   <comment>Written by DKS.</comment>
&lt;/page&gt;
</page>
</source>


;Wanted result document
;Wanted result document
 
<source lang="xml">
&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"&gt;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
  &lt;html&gt;
  <html>
   &lt;head&gt;
   <head>
     &lt;title&gt;Hello&lt;/title&gt;
     <title>Hello</title>
   &lt;/head&gt;
   </head>
   &lt;body bgcolor="#ffffff"&gt;
   <body bgcolor="#ffffff">
     &lt;h1 align="center"&gt;Hello&lt;/h1&gt;
     <h1 align="center">Hello</h1>
     &lt;p align="center"&gt; Here is some content&lt;/p&gt;
     <p align="center"> Here is some content</p>
     &lt;hr&gt;&lt;i&gt;Written by DKS&lt;/i&gt;
     <hr><i>Written by DKS</i>
   &lt;/body&gt;
   </body>
  &lt;/html&gt;
  </html>
</source>


;The XSLT Stylesheet
;The XSLT Stylesheet


* hello.xslt
* hello.xslt
<source lang="xml">
<?xml version="1.0"?>               
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
''<xsl:template match="page">''
    <html> <head> <title> ''<xsl:value-of select="title"/>''
  </title> </head>
    <body bgcolor="#ffffff">
    '' <xsl:apply-templates/>''
    </body>
    </html>
  '' </xsl:template>''


&lt;?xml version="1.0"?&gt;
  '' <xsl:template match="title">''
&lt;xsl:stylesheet version="1.0"
     <h1 align="center"> ''<xsl:apply-templates/> '' </h1>
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
   '' </xsl:template>''
''&lt;xsl:template match="page"&gt;''
     &lt;html&gt; &lt;head&gt; &lt;title&gt; ''&lt;xsl:value-of select="title"/&gt;''
  &lt;/title&gt; &lt;/head&gt;
    &lt;body bgcolor="#ffffff"&gt;
    '' &lt;xsl:apply-templates/&gt;''
    &lt;/body&gt;
    &lt;/html&gt;
   '' &lt;/xsl:template&gt;''


  '' &lt;xsl:template match="title"&gt;''
  ''<xsl:template match="content">''
     &lt;h1 align="center"&gt; ''&lt;xsl:apply-templates/&gt; '' &lt;/h1&gt;
     <p align="center"> ''<xsl:apply-templates/>'' </p>
   '' &lt;/xsl:template&gt;''
   '' </xsl:template>''


  ''&lt;xsl:template match="content"&gt;''
   '' <xsl:template match="comment">''
    &lt;p align="center"&gt; ''&lt;xsl:apply-templates/&gt;'' &lt;/p&gt;
     <hr/> <i>''<xsl:apply-templates/>'' </i>
   '' &lt;/xsl:template&gt;''
   </xsl:template>
 
  ''</xsl:stylesheet>''
  '' &lt;xsl:template match="comment"&gt;''
</source>
     &lt;hr/&gt; &lt;i&gt;''&lt;xsl:apply-templates/&gt;'' &lt;/i&gt;
   &lt;/xsl:template&gt;
  ''&lt;/xsl:stylesheet&gt;''


=== Anatomy of a simple stylesheet ===
=== Anatomy of a simple stylesheet ===
Line 213: Line 224:
(2) Copy/paste the XSLT header and root element below (decide encoding as you like)
(2) Copy/paste the XSLT header and root element below (decide encoding as you like)


''&lt;?xml version="1.0" encoding="ISO-8859-1" ?&gt; ''
<source lang="xml">
  ''&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;''
''<?xml version="1.0" encoding="ISO-8859-1" ?> ''
''&lt;/xsl:stylesheet&gt;''
  ''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">''
''</xsl:stylesheet>''
</source>


(3) Write a rule that deals with your XML root element
(3) Write a rule that deals with your XML root element
This rule must produce the root, head and body of the HTML (copy/paste this too, but replace "'' page'' ")
This rule must produce the root, head and body of the HTML (copy/paste this too, but replace "'' page'' ")


''&lt;xsl:template match="page"&gt;''
<source lang="xml">
   &lt;html&gt;
''<xsl:template match="page">''
     &lt;head&gt; &lt;title&gt; ''&lt;xsl:value-of select="title"/&gt; ''
   <html>
       &lt;/title&gt;
     <head> <title> ''<xsl:value-of select="title"/> ''
     &lt;/head&gt;
       </title>
     &lt;body bgcolor="#ffffff"&gt;
     </head>
     '' &lt;xsl:apply-templates/&gt;''
     <body bgcolor="#ffffff">
     &lt;/body&gt;
     '' <xsl:apply-templates/>''
   &lt;/html&gt;
     </body>
''&lt;/xsl:template&gt;''
   </html>
''</xsl:template>''
</source>


(4) Write rules for '' each'' (!!) of your XML elements,
(4) Write rules for '' each'' (!!) of your XML elements,
Line 236: Line 251:


(5) Associate this stylesheet with your XML file using:
(5) Associate this stylesheet with your XML file using:
  ''&lt;?xml-stylesheet href="xxx.xsl" type="text/xsl"?&gt;''
<source lang="xml">
  <xml-stylesheet href="xxx.xsl" type="text/xsl"?>
</source>
 
== Tuning output with xsl:output and CSS ==
== Tuning output with xsl:output and CSS ==


Line 246: Line 263:
''xsl:output'' is an instruction that allows you to fine-tune XSLT translation output. It's definition is the following:
''xsl:output'' is an instruction that allows you to fine-tune XSLT translation output. It's definition is the following:


&lt;xsl:output<br /> method = "xml" | "html" | "text"<br /> version = nmtoken<br /> encoding = string<br /> omit-xml-declaration = "yes" | "no"<br /> standalone = "yes" | "no"<br /> doctype-public = string<br /> doctype-system = string<br /> indent = "yes" | "no"<br /> media-type = string /&gt;
<pre>
<xsl:output
method = "xml" | "html" | "text"
version = nmtoken<br /> encoding = string
omit-xml-declaration = "yes" | "no"
standalone = "yes" | "no"
doctype-public = string
doctype-system = string
indent = "yes" | "no"
media-type = string
</pre>


* You should put this instruction in the beginning of the file (after xsl:stylesheet)
* You should put this instruction in the beginning of the file (after xsl:stylesheet)
Line 252: Line 279:
; Example - Output in HTML ISO-latin encoded
; Example - Output in HTML ISO-latin encoded


  &lt;xsl:output method="''html''"
<source lang="xml">
  <xsl:output method="''html''"
     encoding="ISO-8859-1"
     encoding="ISO-8859-1"
     doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/&gt;
     doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
</source>


; Example - Output in XHTML transitional with a namespace
; Example - Output in XHTML transitional with a namespace
Line 260: Line 289:
* This is quite more complicated than producing simple HTML
* This is quite more complicated than producing simple HTML


&lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
<source lang="xml">
                 ''xmlns="http://www.w3.org/1999/xhtml"'' &gt;
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  &lt;xsl:output
                 ''xmlns="http://www.w3.org/1999/xhtml"'' >
  <xsl:output
     method="''xml''"
     method="''xml''"
     doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
     doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
     doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
     doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
     indent="yes"
     indent="yes"
     encoding="iso-8859-1" /&gt;
     encoding="iso-8859-1" />


  &lt;xsl:template match="recipe"&gt;
  <xsl:template match="recipe">
     &lt;html ''xmlns="http://www.w3.org/1999/xhtml"'' &gt;
     <html ''xmlns="http://www.w3.org/1999/xhtml"'' >
     &lt;head&gt; ... &lt;/head&gt; ... &lt;body&gt; ... &lt;/body&gt;
     <head> ... </head> ... <body> ... </body>
  &lt;/xsl:template&gt;
  </xsl:template>
</source>


; Exemple - Your XML
; Exemple - Another XML language


&lt;xsl:output
<source lang="xml">
<xsl:output
   method="xml" indent="yes"
   method="xml" indent="yes"
   doctype-system="mydtd.dtd" /&gt;
   doctype-system="mydtd.dtd" />
</source>


; Exemple - Output in SVG
; Exemple - Output in SVG


&lt;xsl:output
<source lang="xml">
<xsl:output
   method="xml"
   method="xml"
   indent="yes"
   indent="yes"
Line 288: Line 322:
   doctype-public="-//W3C//DTD SVG 1.0//EN"
   doctype-public="-//W3C//DTD SVG 1.0//EN"
   doctype-system="http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd"
   doctype-system="http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd"
   media-type="image/svg" /&gt;
   media-type="image/svg" />
</source>


=== CSS styling of HTHML ===
=== CSS styling of HTHML ===
Line 296: Line 331:
* .... in the hello.css file you then have to define styles of HTML elements you generate
* .... in the hello.css file you then have to define styles of HTML elements you generate


   &lt;xsl:template match="hello"&gt;
<source lang="xml">
   &lt;html&gt;
   <xsl:template match="hello">
     &lt;head&gt;
   <html>
     ''&lt;link href="hello.css" type="text/css" rel="stylesheet"/&gt;''
     <head>
     &lt;/head&gt;
     ''<link href="hello.css" type="text/css" rel="stylesheet"/>''
     </head>
     ......
     ......
  &lt;/xsl:template match="hello"&gt;
  </xsl:template match="hello">
</source>


; Example 3-5: cooking
; Example 3-5: cooking
Line 308: Line 345:
* cooking.xsl, cooking.xml and cooking-html.css
* cooking.xsl, cooking.xml and cooking-html.css


   &lt;xsl:template match="recipe"&gt;
<source lang="xml">
     &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
   <xsl:template match="recipe">
     &lt;head&gt;
     <html xmlns="http://www.w3.org/1999/xhtml">
       &lt;title&gt; &lt;xsl:value-of select="title"/&gt; &lt;/title&gt;
     <head>
       &lt;link href="cooking-html.css" type="text/css" rel="stylesheet"/&gt;
       <title> <xsl:value-of select="title"/> </title>
     &lt;/head&gt;
       <link href="cooking-html.css" type="text/css" rel="stylesheet"/>
       &lt;body bgcolor="#ffffff"&gt;
     </head>
       &lt;xsl:apply-templates/&gt;
       <body bgcolor="#ffffff">
     &lt;/body&gt;
       <xsl:apply-templates/>
     &lt;/html&gt;
     </body>
   &lt;/xsl:template&gt;
     </html>
   </xsl:template>
</source>


== If things go wrong ==
== If things go wrong ==
Line 362: Line 401:


* simply cut/paste this to your XSLT (but remove it later on)
* simply cut/paste this to your XSLT (but remove it later on)
   &lt;xsl:template match="*"&gt;
<source lang="xml">
   &lt;dl&gt;&lt;dt&gt;Untranslated node:
   <xsl:template match="*">
       &lt;strong&gt;&lt;xsl:value-of select="name()"/&gt;&lt;/strong&gt;&lt;/dt&gt;
   <dl><dt>Untranslated node:
   &lt;dd&gt;
       <strong><xsl:value-of select="name()"/></strong></dt>
     &lt;xsl:copy&gt;
   <dd>
       &lt;xsl:apply-templates select="@*"/&gt;
     <xsl:copy>
       &lt;xsl:apply-templates select="node()"/&gt;
       <xsl:apply-templates select="@*"/>
     &lt;/xsl:copy&gt;
       <xsl:apply-templates select="node()"/>
   &lt;/dd&gt;
     </xsl:copy>
   &lt;/dl&gt;
   </dd>
   &lt;/xsl:template&gt;
   </dl>
  &lt;xsl:template match="text()|@*"&gt;
   </xsl:template>
   Contents: &lt;xsl:value-of select="."/&gt;
  <xsl:template match="text()|@*">
  &lt;/xsl:template&gt;
   Contents: <xsl:value-of select="."/>
  </xsl:template>
</source>


== Selective processing ==
== Selective processing ==
Line 601: Line 642:
;XML fragment
;XML fragment


&lt;page&gt;
<source lang="xml">
   &lt;title&gt;Hello&lt;/title&gt; &lt;content revision="''10'' "&gt;
<page>
       Here is some content&lt;/content&gt;
   <title>Hello</title> <content revision="''10'' ">
   &lt;comment&gt;Written by &lt;author&gt;''DKS''
       Here is some content</content>
  &lt;/author&gt;&lt;/comment&gt;
   <comment>Written by <author>''DKS''
&lt;/page&gt;
  </author></comment>
</page>
</source>


; XSLT rules
; XSLT rules


&lt;xsl:template match="page"&gt;
<source lang="xml">
     &lt;P&gt;&lt;''xsl:value-of select="comment/author"'' /&gt;&lt;/P&gt;
<xsl:template match="page">
  &lt;/xsl:template&gt;
     <P><''xsl:value-of select="comment/author"'' /></P>
  </xsl:template>


  &lt;xsl:template match="content"&gt;
  <xsl:template match="content">
     &lt;P&gt;Revision number: &lt;''xsl:value-of select="@revision"'' /&gt;&lt;/P&gt;
     <P>Revision number: <''xsl:value-of select="@revision"'' /></P>
&lt;/xsl:template&gt;
</xsl:template>
</source>


=== Inserting a value inside a string ===
=== Inserting a value inside a string ===
Line 624: Line 669:
;There is a special syntax
;There is a special syntax


'' {....}'' '' ''
'' {....}''


This is the equivalent of &lt;'' xsl:value-of select="..."/&gt; '' which can not be used here !!
This is the equivalent of &lt;'' xsl:value-of select="..."/&gt; '' which can not be used here !!
Line 634: Line 679:
;The XML information
;The XML information


  &lt;contact-info ''email''<nowiki> ="</nowiki>''test@test'' "&gt;
<source lang="xml">
  <contact-info email="test@test">
</source>


;The XSLT rule
;The XSLT rule


  &lt;xsl:template match="contact-info"&gt;
<source lang="xml">
  <xsl:template match="contact-info">
  ....
  ....
   &lt;a href="mailto:''{'' ''@email'' ''}'' "&gt;&lt;xsl:value-of select="''@email'' "/&gt;&lt;/a&gt;
   <a href="mailto:''{'' ''@email'' ''}'' "><xsl:value-of select="''@email'' "/></a>
  ...
  ...
</source>


; The result
; The result


  &lt;a href="''mailto:test@test'' "&gt;''test@test'' &lt;/a&gt;
<source lang="xml">
  <a href="''mailto:test@test'' ">''test@test'' </a>
</source>


=== Dealing with pictures ===
=== Dealing with pictures ===

Revision as of 14:58, 5 August 2009

<pageby nominor="false" comments="false"/>

Introduction

This is a beginners tutorial for XSLT made from slides

Objectives
  • Understand the purpose of XSLT
  • Do simple transformations from XML to HTML
  • Understand the most simple XPath expressions (tag names)
Prerequisites
  • Editing XML (being able to use a simple DTD)
  • XML namespaces (some, have a look at the XML namespace article)
  • HTML and CSS (some)
Next steps
Warning

XSLT is a rather complex transformation language. I believe that one could distinguish four levels of difficulty:

  • This tutorial is introductory (level 1)
  • Level 2 XSLT is more sophisticated template ordering, conditional expressions, loops, etc.
  • Level 3 is advanced XPath expressions
  • Level 4 is functional programming with templates

Introduction Extensible Stylesheet Language Transformations

Goals of XSLT
  • XSLT is a transformation language for XML
  • XSLT is a W3C XML language (the usual XML well-formedness criteria apply)
  • XSLT can translate XML into almost anything , e.g.:
    • wellfomed HTML (closed tags)
    • any XML, e.g. yours or other XML languages like SVG, X3D
    • non XML, e.g. RTF (a bit more complicated)

Xslt-basics-2.png

So keep in mind that XSLT doesn't understand HTML at all !. Frequently, beginners assume that XSLT sort of knows about HTML, about pictures. All it can do is translate XML elements into something else.

History and specifications

Specification
  • XSLT 1.0 was formalized as W3C Recommendation on 16/11/99: http://www.w3.org/TR/xslt
    • Most modern web browser support most of it (even Safari)
  • XSLT 2.0 is a W3C recommendation since 23 January 2007: http://www.w3.org/TR/xslt20/
    • not implemented in current browsers, but in most good XSLT processors (e.g. Saxon and Xalan)
History
  • Initially, XLS (XSL: eXtensible Stylesheet Language) was a project to replace CSS for both display and print media and to provide support for complex formatting and layout features (pagination, indexing, cross-referencing, recursive numbering, indexing, etc.
  • XSLT ( Extensible Stylesheet Language Transformations ) was originally intended as a small part of the larger specification for XSL
  • However, when the XSL specification draft became very large and complex it was decided to split the project into XSLT for transformations (that were urgently needed) and XSL for the rest (W3C recommendation of 2001)
Related languages

A first glance at XSLT

Simple use of XSLT means writing a file (called a stylesheet) and to associate it with an XML file and the to view the XML file in a web browser. Alternatively, you can use an XML editor or a XSLT processor to translate an XML file with an XSLT file, then save the result file.

Root of an XSLT file stylesheet

 <?xml version="1.0"?>
 ''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">''
 ''....''
 ''</xsl:stylesheet>''
Mandatory elements
  • XML declaration on top of the file
  • A stylesheet root tag with the following version and namespace attributes:
  <xsl:stylesheet ''version="1.0"'' ''xmlns:xsl="http://www.w3.org/1999/XSL/Transform"'' >
  • XSLT must be wellformed (and also obey the XSLT specification)
  • XSLT files usually have the *.xsl extension and should have the text/xsl or application/xml mimetype when served by http (a web server). So make sure that your webserver is configured correctly.

Association of XML and an XSLT file

You can directly associate a XSLT stylesheet with an XML file by using a so-called processing instruction (similar principle as CSS stylesheets)

<?xml version="1.0" encoding="ISO-8859-1"?>
 <''?xml-stylesheet'' ''href="project.xsl" type="text/xsl"'' ?>
 <yourxml> 
    .... 
 </yourxml>

Basic XSLT

Basic (!) use of XSLT means:

  • writing translation rules (aka templates) for each XML tag we want to translate
  • translating XML to HTML
A simple translation rule (called "template" in XSLT)

Xslt-basics-3.png

Example Translation of a title tag into HTML centered H1

XML Source we want to translate:

<title>Hello friend</title>

The XSLT rule that does it:

Xslt-basics-4.png

A complete XSLT example

(Hello XSLT)

XML file (source)
  • hello.xml
<?xml version="1.0"?>
 ''<?xml-stylesheet href="hello.xsl" type="text/xsl"?>''
 <page>
  <title>Hello</title>
  <content>Here is some content</content>
  <comment>Written by DKS.</comment>
</page>
Wanted result document
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
 <html>
   <head>
     <title>Hello</title>
   </head>
   <body bgcolor="#ffffff">
     <h1 align="center">Hello</h1>
     <p align="center"> Here is some content</p>
     <hr><i>Written by DKS</i>
   </body>
 </html>
The XSLT Stylesheet
  • hello.xslt
 <?xml version="1.0"?>                
 <xsl:stylesheet version="1.0"
                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 ''<xsl:template match="page">''
    <html> <head> <title> ''<xsl:value-of select="title"/>''
  </title> </head>
     <body bgcolor="#ffffff">
     '' <xsl:apply-templates/>''
     </body>
    </html>
  '' </xsl:template>''

  '' <xsl:template match="title">''
    <h1 align="center"> ''<xsl:apply-templates/> '' </h1>
  '' </xsl:template>''

   ''<xsl:template match="content">''
    <p align="center"> ''<xsl:apply-templates/>'' </p>
  '' </xsl:template>''

  '' <xsl:template match="comment">''
    <hr/> <i>''<xsl:apply-templates/>'' </i>
   </xsl:template>
 ''</xsl:stylesheet>''

Anatomy of a simple stylesheet

Xslt-basics-5.png

Rule execution order

(1) The XSLT engine first looks at the XML file and tries to find a XLT rule that will match the root element

  • E.g. in the above example it will find "page" and then the template for page

(2) The XSLT processor will then "move" inside the rule element and do further processing

  • HTML elements (or any other tags) will be copied to the output document
  • If an XSLT instruction is found, it will be executed
 <xsl:apply-templates/>  means: "go and look for other rules"

E.g. in the above example

  • the processor dealing with root element "page" will first find a rule for "title" and execute it according to the same principle.
  • once it is done with "title" and its children, it then will find the rule for "content" and execute it

(3) and so forth ....

More information

  • <xsl:value-of select="title"/> will retrieve contents of the "title" child element.
    • In our example, it would only work in the template for "page", since only "page" has a "title" child
  • You have to understand that XSLT works down "depth-first" the XML tree, i.e.
    • it first deals with the rule for the root element,
    • then with the first instruction within this rule.
    • If the first instruction says "find other rules" it will then apply the first rule found for the first child element and so forth...
    • The rule of the root element is also the last one be finished (since it must deal step-by-step with everything that is found inside) !!!

The procedure recapitulated

(1) Create a XSLT stylesheet file: xxx.xsl

(2) Copy/paste the XSLT header and root element below (decide encoding as you like)

''<?xml version="1.0" encoding="ISO-8859-1" ?> ''
 ''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">''
''</xsl:stylesheet>''

(3) Write a rule that deals with your XML root element This rule must produce the root, head and body of the HTML (copy/paste this too, but replace " page ")

''<xsl:template match="page">''
   <html>
    <head> <title> ''<xsl:value-of select="title"/> ''
      </title> 
    </head>
    <body bgcolor="#ffffff">
     '' <xsl:apply-templates/>''
    </body>
   </html>
''</xsl:template>''

(4) Write rules for each (!!) of your XML elements,

  • for each insert some HTML, sometimes some text, or sometimes nothing
  • make sure to place a <xsl:apply-templates> inside each rule (usually between some HTML) ... unless you wish to censor contents.

(5) Associate this stylesheet with your XML file using:

 <xml-stylesheet href="xxx.xsl" type="text/xsl"?>

Tuning output with xsl:output and CSS

Output declarations

  • So far, HTML output produced would display in a naviagor, but is not fully HTML compliant.

xsl:output is an instruction that allows you to fine-tune XSLT translation output. It's definition is the following:

<xsl:output
 method = "xml" | "html" | "text"
 version = nmtoken<br /> encoding = string
 omit-xml-declaration = "yes" | "no"
 standalone = "yes" | "no"
 doctype-public = string
 doctype-system = string
 indent = "yes" | "no"
 media-type = string
  • You should put this instruction in the beginning of the file (after xsl:stylesheet)
Example - Output in HTML ISO-latin encoded
 <xsl:output method="''html''"
     encoding="ISO-8859-1"
     doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
Example - Output in XHTML transitional with a namespace
  • This is quite more complicated than producing simple HTML
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 ''xmlns="http://www.w3.org/1999/xhtml"'' >
 <xsl:output
    method="''xml''"
    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
    doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
    indent="yes"
    encoding="iso-8859-1" />

 <xsl:template match="recipe">
    <html ''xmlns="http://www.w3.org/1999/xhtml"'' >
     <head> ... </head> ... <body> ... </body>
 </xsl:template>
Exemple - Another XML language
<xsl:output
  method="xml" indent="yes"
  doctype-system="mydtd.dtd" />
Exemple - Output in SVG
<xsl:output
  method="xml"
  indent="yes"
  standalone="no"
  doctype-public="-//W3C//DTD SVG 1.0//EN"
  doctype-system="http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd"
  media-type="image/svg" />

CSS styling of HTHML

Associating a CSS stylesheet with HTML output is trivial:

  • add a link tag in the "head" produced by the template for the root element
  • .... in the hello.css file you then have to define styles of HTML elements you generate
  <xsl:template match="hello">
   <html>
    <head>
     ''<link href="hello.css" type="text/css" rel="stylesheet"/>''
    </head>
    ......
 </xsl:template match="hello">
Example 3-5
cooking
  • cooking.xsl, cooking.xml and cooking-html.css
  <xsl:template match="recipe">
    <html xmlns="http://www.w3.org/1999/xhtml">
     <head>
       <title> <xsl:value-of select="title"/> </title>
       <link href="cooking-html.css" type="text/css" rel="stylesheet"/>
     </head>
      <body bgcolor="#ffffff">
      <xsl:apply-templates/>
     </body>
    </html>
   </xsl:template>

If things go wrong

Frequent problems and remediation

Style-sheet error !
  • Validate the style-sheet in your XML editor
  • If it provides XSLT support, it will help you find the error spots
XHTML doesn't display in Firefox !
  • Firefox wants a namespace declaration in the XHMTL produced, do it (see above).
HTML doesn't seem to be right !
  • Transform the XML document within your XML editor and look at the HTML

In "Exchanger Lite", use Transform in the menu bar with the following parameters:

Transform->Execute Advanced XSLT
Input = current document
XSLT = Use Processing instructions
  • You also may validate the output HTML !
There is various unformatted text in the output !
  • See the XSLT default rule (below)
HTML still doesn't seem to be right !!
  • Use a XSLT debugger/tracer to understand how your XSLT executes

The XSLT default rule

  • When you test your first style sheet, it is likely that some of your contents will appear non-formatted.
  • This is due to the fact that XSLT will apply a default rule to all XML elements for which it didn't find a rule.
    • If you forget to write a rule for a tag (or misspell tag names) this will happen .....
  • The XSLT default rule simply copies all contents to the output.

A modified default rule that will help you find missing pieces

  • simply cut/paste this to your XSLT (but remove it later on)
  <xsl:template match="*">
   <dl><dt>Untranslated node:
       <strong><xsl:value-of select="name()"/></strong></dt>
   <dd>
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates select="node()"/>
    </xsl:copy>
  </dd>
  </dl>
  </xsl:template>
 <xsl:template match="text()|@*">
   Contents: <xsl:value-of select="."/>
 </xsl:template>

Selective processing

Steering rule execution and information filtering

  • Instead of letting XSL apply rules in "natural order", you can tell which rules to apply when.
Example 5-1
Hello without content
  • The rule for the root element will only "call" the rules for the "title" and the "comment" element
  • Information within a content tag will not be displayed (since we don't let the processor find rules by itself, but only let it execute a rule for "title" and another for "comment").
Hello2.xml
 <?xml version="1.0"?> 
  <?xml-stylesheet href="hello2.xsl" type="text/xsl"?>
   <page>
    <title>Hello</title>
    <content>Here is some content</content>
    <comment>Written by DKS.</comment>
   </page>
Hello2.xsl
 <?xml version="1.0"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:template match="page">
   <html> <head> <title> <xsl:value-of select="title"/> </title> </head>
    <body bgcolor="#ffffff">
     <xsl:apply-templates select="title"/>
     <xsl:apply-templates select="comment"/>
    </body>
   </html>
  </xsl:template>

  <xsl:template match="title">
   <h1 align="center"> <xsl:apply-templates/> </h1>
  </xsl:template>

  <xsl:template match="comment">
   <hr/> <i><xsl:apply-templates/></i>
  </xsl:template>

 </xsl:stylesheet>
Hello2.html
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN""http://www.w3.org/TR/REC-html40/strict.dtd">
 <html>
  <head>
    <title>Hello</title>
  </head>
  <body bgcolor="#ffffff">
    <h1 align="center">Hello</h1>
    <p align="center"> Here is some content</p> 
    <hr><i>Written by DKS</i>
  </body>
 </html>

A short glance at Xpath

  • XPath is a very powerful language to extract information from XML
  • XPath was published at the same time as XSLT 1.0 (1999)
  • Values of XSLT match and select attributes are XPath expressions

Xslt-basics-6.png

  • XSLT beginners don't need to know a lot about XPath (so don't worry right now !).
    • Simply stick to the idea of writing a template for each XML tag, as explained before
  • XPath expressions can be more complicated:
<xsl:apply-templates select="course/module[position()=1]/section[position()=2]"/>

means: "find rule for 2nd section of the first module of course"

  • XPath also includes arithmetics and tests
"//Participant[string-length(Nom)>=8]"

means: "return all participant nodes with content of name longer than 7 characters"

Examples of a few simple XPath expressions (optional !)
  • These should remind you of CSS selectors

Syntax
elemen

(Type of path)

Example path

Example matches

tag

element name

project

<project> ...... </project>

/

separates children

project/title

<project> <title> ... </title>

/

(root element)

//

descendant

project//title

<project><problem> <title>....</title>

//title

<racine>... <title>..</title> (any place)

*

"wildcard"

*/title

<bla> <title>..</title> and <bli> <title>...</title>

|

"or operator

title|head

<title>...</title> or <head> ...</head>

*|/|@*

All elements: root, children and attributes

.

current element

.

../

parent element

../problem

<project>

@

attribute name

@id

<xyz id="test">...</xyz>

element/@attr

attribute of child

project/@id

<project id="test" ...> ... </project>

@attr='type'

type of attribute

list[@type='ol']

<list type="ol"> ...... </list>

Basic value extraction

The xsl:value-of instruction

  • inserts the value of an XPath expression and copies it to the output
  • e.g. you can take contents of an element or attribute values and insert them in HTML table cells.
Example - Value-of
  • Let's assume that we have an author element and that we would like to put this information on top of the page and that we should like to display the value of the revision attribute.
XML fragment
<page>
  <title>Hello</title> <content revision="''10'' ">
      Here is some content</content>
  <comment>Written by <author>''DKS''
 </author></comment>
</page>
XSLT rules
<xsl:template match="page">
     <P><''xsl:value-of select="comment/author"'' /></P>
 </xsl:template>

 <xsl:template match="content">
     <P>Revision number: <''xsl:value-of select="@revision"'' /></P>
</xsl:template>

Inserting a value inside a string

  • If you want to insert information inside an HTML attribute value, things get a little bit tricky, since this value must be within quotes.
There is a special syntax
 {....}

This is the equivalent of < xsl:value-of select="..."/> which can not be used here !!

Example 5-3
Building a href tag with an email
  • We will use both the {...} and the value-or select constructs.
The XML information
 <contact-info email="test@test">
The XSLT rule
 <xsl:template match="contact-info">
 ....
   <a href="mailto:''{'' ''@email'' ''}'' "><xsl:value-of select="''@email'' "/></a>
 ...
The result
 <a href="''mailto:test@test'' ">''test@test'' </a>

Dealing with pictures

There is no special "magic" for dealing with images, links, stylesheets etc. Simply:

  • look at your XML and figure out how to translate into equivalent HTML (or whatever else)
  • the following example demonstrates the use of value extraction
  • several other solutions than the one demonstrated exist ...
Example - Dealing with pictures
images.xml
 <?xml version="1.0"?>
 <?xml-stylesheet href="images.xsl" type="text/xsl"?>
 <page>
  <title>Hello Here are my images</title>
  <list>
    <!-- pictures are either contents or attribute values of elements -->
   <image>dolores_001.jpg</image>
   <image>dolores_002.jpg</image>

   <image3 source="dolores_002.jpg">Recipe image</image3>
  </list>
  <comment>Written by DKS.</comment>
 </page>
images.xsl
 <?xml version="1.0"?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:template match="page">
   <html> <head> <title> <xsl:value-of select="title"/> </title> </head>
    <body bgcolor="#ffffff">
     <xsl:apply-templates/>
    </body>
   </html>
  </xsl:template>

  <xsl:template match="title">
   <h1 align="center"> <xsl:apply-templates/> </h1>
  </xsl:template>

  <!-- pictures are either contents or attribute values of elements -->
  <xsl:template match="list">
   Images are element contents, apply a template to all image elements:
   <xsl:apply-templates select="image"/>
   Images are attribute values of an element, we do it differently:
   <xsl:apply-templates select="image3"/>
  </xsl:template>

  <xsl:template match="image">
    <p> <img src="{.}"/> </p>
  </xsl:template>

  <xsl:template match="image3">
    <p> <img src="{@source}"/><br/><xsl:value-of select="."/> </p>
  </xsl:template>


  <xsl:template match="comment">
   <hr/> <i><xsl:apply-templates/></i>
  </xsl:template>

 </xsl:stylesheet>

Sorting

Sometimes you wish to sort elements. This should encourage you to study what I call XSLT level 2 (programming constructs).

XML
 <?xml version="1.0"?>
 <?xml-stylesheet href="participants.xsl" type="text/xsl"?>
  <participants>
   <participant>
    <FirstName>Daniel</FirstName>
    <qualification>8</qualification>
    <description>Daniel will be the tutor</description>
    <FoodPref picture="dolores_001.jpg">Sea Food</FoodPref>
   </participant>
   <participant>
    <FirstName>Jonathan</FirstName>
    <qualification>5</qualification>
    <FoodPref picture="dolores_002.jpg">Asian</FoodPref>
   </participant>
   <participant>
    <FirstName>Bernadette</FirstName>
    <qualification>8</qualification>
    <description>Bernadette is an arts major</description>
   </participant>
    <participant>
    <FirstName>Nathalie</FirstName>
    <qualification>2</qualification>
   </participant>
  </participants>
XSL
 <?xml version="1.0" encoding="ISO-8859-1" ?>
 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html" 
    encoding="ISO-8859-1" 
    doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>

 <xsl:template match="/">
  <html>
    <head>
      <title>Participants List</title>
    </head>
    <body bgcolor="#ffffff">
      <h1>Participants list</h1>
      Shows how to build a simple sorted table with XSLT.
      <xsl:apply-templates/>
    </body>
  </html>
 </xsl:template>

 <xsl:template match="participants">
    <table border="2" cellspacing="1" cellpadding="6">
    <tr><th>Qualification</th>
        <th>First Name</th>
        <th>Description</th>
        <th>Food Picture</th>
     </tr>
     <xsl:for-each select="participant">
       <xsl:sort select="qualification"/>
      <tr>
      <td><xsl:value-of select="qualification"/></td>
      <td><xsl:value-of select="FirstName"/></td>
      <td><xsl:value-of select="description"/></td>
      <td><xsl:if test="FoodPref/@picture"><img src="{FoodPref/@picture}"/></xsl:if></td>
      </tr>
     </xsl:for-each>
    </table>	
 </xsl:template>

 </xsl:stylesheet>

Exercise

Here is a simple XML file and an unfinished XSLT Stylesheet. Try to complete it.

XML (copy/paste)
 <?xml version="1.0" encoding="iso-8859-1"?>
 <?xml-stylesheet href="cooking.xsl" type="text/xsl"?>

 <recipe>
     <recipe_head>
	<recipe_name>Cold Salmon in Creamy Spiced Sauce</recipe_name>
 	<recipe_author>Hilaire Walden</recipe_author>
	<meal_type>Fish and Shellfish</meal_type>
     </recipe_head>
  	
     <recipe_body>
	  	<ingredients>
	  	  <ingredient>1/2 teaspoon finely crushed cumin seeds</ingredient>
	  	  <ingredient>1 teaspoon chilli powder</ingredient>
	  	  <ingredient>salt and freshly ground black pepper</ingredient>
	  	  <ingredient>2 tablespoons olive oil</ingredient>
	  	  <ingredient>2 cloves garlic, crushed</ingredient>
	  	  <ingredient>1.25 cm (1/2 in) fresh ginger root, finely chopped</ingredient>
	  	  <ingredient>4 pieces salmon fillet, skinned</ingredient>
	  	  <ingredient>125 ml (4 fl oz / 1/2 cup) double (heavy) cream</ingredient>
	  	  <ingredient>250 ml (8 fl oz / 1 cup) thick plain yogurt</ingredient>
	  	  <ingredient>large pinch of saffron threads, toasted and crushed</ingredient>
  		  <ingredient>seeds from 6 cardamom pods, toasted and finely crushed</ingredient>
	  	  <ingredient>salt</ingredient>
  		  <ingredient>coriander (cilantro) to garnish</ingredient>
	  	</ingredients>
  	<directions>
	  <direction>Mix together the cumin seeds, chilli powder and pepper and rub into the fish.</direction>
	<direction>Heat the oil in a frying pan, add the garlic and ginger and heat until they sizzle.</direction>
	<direction>Add the salmon fillets and fry until they start to colour (about 15-20 seconds on each side).</direction>
	<direction>Stir in the cream, yogurt, saffron, cardamom and salt.</direction>
	<direction>Adjust the heat so that the sauce is just bubbling and cook, 
 turning the fish once, until the flesh just flakes when tested 
 with the point of a sharp knife (about 3-4 minutes each side).
        </direction>
	<direction>Transfer the fish to a shallow dish. 
 Boil the sauce until it has reduced and thickened, pour over the fish and leave to cool.</direction>
        <direction>Cover the dish and chill until 15-20 minutes before serving.</direction>
	<direction>Garnish with coriander (cilantro).</direction>
	</directions>
     </recipe_body>

     <recipe_footer>
     <serving>4</serving>
     <preparation_time>15 minutes</preparation_time>
     </recipe_footer>
     <document_info>
  		<document_author>Hilaire Walden</document_author>
  		<date_updated>21/01/07</date_updated>
  		<origin>Easy to Cook, Hot &amp; Spicy</origin>
  	</document_info>
  </recipe>
XSLT (complete)
 <?xml version="1.0"?>
 <xsl:stylesheet version="1.0"
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output
   method="xml"
   doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
   doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
   indent="yes"
   encoding="iso-8859-1" />

  <xsl:template match="recipe">
   <html xmlns="http://www.w3.org/1999/xhtml"> 
    <head> 
      <title> <xsl:value-of select="title"/> </title>
      <link href="cooking-html.css" type="text/css" rel="stylesheet"/>
    </head>
    <body bgcolor="#ffffff">
     <xsl:apply-templates/>
    </body>
   </html>
  </xsl:template>

  <xsl:template match="recipe_head">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="recipe_body">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="recipe_name">
   <h1 align="center"> <xsl:apply-templates/> </h1>
  </xsl:template>

  <xsl:template match="recipe_author">
   <p align="center"> <xsl:apply-templates/> </p>
  </xsl:template>

  <xsl:template match="meal_type">
   <p align="center"> Type: <xsl:apply-templates/> </p>
  </xsl:template>

  <xsl:template match="ingredients">
   <h2 align="center">Ingredients</h2>
   <ol>
     <xsl:apply-templates/> 
   </ol>
   </xsl:template>

  <xsl:template match="ingredient">
   <li> <xsl:apply-templates/> </li>
  </xsl:template>

  <xsl:template match="directions">
   <h2 align="center">Directions</h2>
   <ol>
     <xsl:apply-templates/> 
   </ol>
   </xsl:template>

  <xsl:template match="direction">
   <li> <xsl:apply-templates/> </li>
  </xsl:template>

  <xsl:template match="recipe_footer">
   <h2 align="center">More info</h2>
    <p>This stylesheet is unfinished ... some rules are missing.
      This is why you can't see properly formatted contents below .... 
    </p>
   <xsl:apply-templates/>
   </xsl:template>

 </xsl:stylesheet>

Last advice

  • Ignore textbooks that start by explaining how to use the for-each construct.
  • You can do a lot just with templates (rules) !
  • Try to complete the example problem above. In my experience, people absolutly don't get the mechanism of this kind of data-driven rule-based programming before they really tried understanding and completing an example. (This includes programmers that only have been trained in procedural languages. Btw, those programmers really freak out when the have to learn how to write functional programming code with XSLT and cope with the fact that there no variables as they understand them in XSLT).
  • Look up other tutorials, some are listed in the XSLT article.