Introduction to XSLT
Jean-François Perrot
- General idea &
History
- Markup Languages,
from text to structure
- The transform
way : XSL eXtensible
Stylesheet Language
- A programming
language in its own right
- Example : The Menu
- Basic theory
- A rule-based
language
- Rule =
condition - action
- Recursive
call of
the rule base
- Default rules
- Two uses of XPath
expressions
- Traditional
control structures
- A useful feature
: sorting
- Advanced theory
- XML namespaces
- Generating XML
-
-
- Separation of concerns :
- structure vs. display (both are mixed in HTML)
- the idea of a stylesheet, a
separate entity to specify display.
- The other language way : HTML -> XHTML + CSS
CSS is a different language, so that
- structure is specified in XHTML
- display is specified using a different formalism,
namely CSS
- the final document, ready to be displayed by the
browser, is made up of the 2 specs, XHTML + CSS
-
Structure is seen as the only starting point (arbitrary XML, not
necessarily XHTML).
The XML document (structure) is transformed into a different
document,
ready for display.
This document is written in a specific dialect, display results from
the interpretation of that dialect.
XSL is the name of the overall project.
XSLT (eXtensible Stylesheet Language Transform)
is the name of the formalism for defining the transformations.
The original scope of XSL was
Hence, if was generalized to
- XML --> any sort of XML dialect
- XML --> any sort of text
Accordingly, XSLT evolved into...
-
- XML is its concrete syntax : the program as document
(not only as
a text !)
To understand the logic of the language, keep in mind that this is only
syntax...
- Web-distributed operation
- implicit operation via a Processing Instruction
(Browser,
xsltproc
)
<?xml-stylesheet type="text/xsl" href="path/URL
of the stylesheet"?>
- explicit operation, by applying a stylesheet (
xsltproc
,
php, Java)
The Java Transform
API
-
- The XML file (with Processing Instruction) :
Menu.xml
- a variant (with prices, without Processing
Instruction) :
MenuP.xml
- XML to HTML : XSLT transform
Menu2HTML.xsl
- observe the implicit operation by the browser : open
Menu.xml
and inspect
the source code
- generate the HTML file with
xsltproc
.
- XML to XSL-FO : XSLT transform
Menu2FO.xsl
- the pdf file
that we want to generate
- the XSL-FO
file that represents that pdf file (from which the pdf is produced)
- Generating pdf directly from XML with Apache-Fop (see
here)
-
(illustrated with HTML generation for the name/mark example)
An XSLT program ( = stylesheet) is
- an XML document
- with root element
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'>
Note the xsl
namespace prefix !
- containing a "flat", unordered collection of rules (
<xsl:template>
)
-
Provisionally, consider that at most one rule can be applied to
any XML object in the document.
The matter of rule priority in XSLT is treated in a
counter-intuitive way, and should be left aside at an introductive
level.
-
<xsl:template match="condition">
action
</xsl:template>
condition
is an expression in
the XPath
language.
Such an expression describes a set of paths in the XML tree, with a
Unix-like syntax.
The condition
is true for a given node N
if N belongs to the set of nodes that are reachable by one of
those paths.
Examples :
- "
/
" is the Document
node,
a rule starting with <xsl:template match="/">
is
applicable to this node only.
"student"
denotes any Element
node with name (tag) "student"
which is a child of the
current node.
action
is a text in which
- fragments tagged
<xsl:... >
are XSLT instructions and are evaluated
- all other fragments make up a tree-like structure
(XML, HTML or text), which may be
- either directly processed (e.g. in a browser)
- or sent to the output medium
where it will be serialized according to the option that is fixed in
the <xsl:output>
tag.
- Example :
list.xsl
to be applied to an name/mark file with DTD #2
(e.g. Nom_note2_list.xml
)
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version='1.0'>
<xsl:output method="html" />
<xsl:template match="/">
<html><head><title>Visualisation</title></head>
<body>
<h2>Here is a list of names and marks</h2>
<ol>
<xsl:apply-templates/>
</ol>
</body>
</html>
</xsl:template>
<xsl:template match="student">
<li>
<xsl:value-of
select="name"/> : <xsl:value-of select="mark"/>
</li>
</xsl:template>
</xsl:stylesheet>
Execution :
- The first rule is applied to the
Document
node.
This application first generates the tree fragment
<html><head><title>Visualisation</title></head>
<body>
<h2>Here is a list of names and marks</h2>
<ol>
- then
<xsl:apply-templates/>
is
executed (see below)
- on the return of
<xsl:apply-templates/>
,
the following tree fragment is generated
</ol>
</body>
</html>
<xsl:apply-templates/>
will
ultimately cause the 2nd rule to be applied to each <eleve>
node in turn.
Each application will
- first generate
<li>
- then evaluate
<xsl:value-of
select="name"/>
- generate "
:
"
- then evaluate
<xsl:value-of
select="mark"/>
- finally generate
</li>
- Evaluating
<xsl:value-of select="tagName"/>
yields the complete subtree contained in the first child node
of the current node that bears the tagName
.
<xsl:value-of
select="name"/>
will yield Toto
or the first <student>
,
then Tata
, etc.
The total output will be
<html><head><title>Visualisation</title></head>
<body>
<h2>Here is a list of names and marks</h2>
<ol>
<li> Toto : 12 </li>
<li> Tata : 13 </li>
<li> Tutu : 17 </li>
<li> Titi : 11 </li>
</ol>
</body>
</html>
-
The most fundamental instruction is
<xsl:apply-templates />
which launches the whole rule base on the children of the current
node.
A variant is <xsl:apply-templates select="an-XPath-expression"
/>
which restricts the application domain to the set of nodes that is the
value of the expression at the present node.
The short form <xsl:apply-templates />
is
equivalent to <xsl:apply-templates select="*" />
.
Execution starts by applying the rule base to the Document
node
(hence the utility of a rule with <xsl:template match="/">
)
and proceeds by recursive calls in a descending way on the tree
structure.
On our example, there is a rule for the Document
node,
but none for its only child <liste>
.
Does computation stop there ?
-
To facilitate the writing of rule bases in an intuitive way, the default
rules will
for any node to which no explicit rule is applicable
- Output the complete text contained in it.
- Execute
<xsl:apply-templates />
,
i.e.
launch the rule base on its children.
In our case, this will launch the rule base on the children of <liste>
,
i.e. the <eleve>
,
for which there is an applicable rule !
-
XPath expressions play in XSLT a dual role :
- Producing sets of nodes, as in
<xsl:template
match="expression">
or in <xsl:apply-templates
select="expression"
/>
:
/list/student
= all <student>
from the root "/
"
student/mark
= all <mark>
from the <student>
where evaluation occurs
list/student[position() = last()]
= the
last <student >
in <list>
see listSep.xsl
list/student[@name = 'Toto']
= all <student>
children of <list>
whose
attribute name
is Toto
(Names & Marks #1)
Beware ! This expression will be written as a
string value of an attribute (match
or select
),
i.e. between double quotes,
hence 'Toto'
between simple quotes !
- Yielding a (terminal) string value in
<xsl:value-of
select="expression" />
to be combined with other (constant) strings to build the final value
of an <xsl:apply-templates />
call.
- Evaluation of
<xsl:value-of select="@attributeName"/>
yields the value of the attribute of the current
node
with name attributeName
.
See tableAt.xsl
<xsl:value-of select="
sum(/list/student/@mark)
div count(/list/student)" />
computes the average, from the root.
See moy.xsl
-
To deal with cases where the subtle play of templates seems
impractical,
programmers may fall back on the usual control structures :
- One-way conditional construct
<xsl:if test="boolean-valued XPath expr.">
action
</xsl:if>
Example.
- Multiple choice
<xsl:choose>
<xsl:when test="boolean-valued XPath expr.">
action
</xsl:when>
<xsl:when test="boolean-valued XPath expr.">
action
</xsl:when>
............
<xsl:otherwise>
action
</xsl:otherwise>
</xsl:choose>
Example.
- for-each loop
<xsl:for-each select="nodeSet-valued
XPath expr.">
action
</xsl:for-each>
Example.
-
<xsl:sort select="criterium" />
inside an <xsl:apply-templates>
or an <xsl:for-each>
will induce a sorted treatment according to the criterium
feature, if it is available !
By default alphabetical sorting is applied
e.g.
<xsl:apply-templates>
<xsl:sort select="@name" />
</xsl:apply-templates>
will deal with (presumably, eleves) following the alphabetical order of
their names.
Example
- Additional information about the sorting method :
ex. <xsl:sort select="mark" order="descending"
data-type="number"/>
default values : ascending
and text
.
Example.
read
more...
-
-
- Declared in the root tag, together with the xslt ns.
- All other namespaces apply to the source document and to
the target document alike.
- A default namespace may be used only for the target
document.
Example : To generate an XHTML page from Names & Marks in RDF
format, the root tag will be :
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version='1.0'
xmlns="http://www.w3.org/1999/xhtml"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:epita="http://epita/masters/international/">
-
- Tags and attributes of the target document are written in
the same way as HTML in our previous examples
if they are constant.
- Quite often, attributes values must be computed.
Then, use an
explicit construction :
<myTag>
<xsl:attribute name=
"name-of-attribute">
... computation of value, typically ....
<xsl:value-of select="some-XPath-expression"/>
...........
</xsl:attribute>
</myTag>
see examples here.
- When the computation of the attribute value is easy, use
a shorthand
(note the curly brackets inside the double quotes of the value
string
)
<myTag myAttribute="{some-XPath-expression}">
....
</myTag>
see an example here.
- Very rarely, attribute names or even tag names
must be
computed.
Then use the heavy DOM-like artillery :
<xsl:element
name="{some-XPath-expression}">
<xsl:attribute
name="{another-XPath-expression}">
...
computation of attribute value ...
</xsl:attribute>
.... computation of element contents ...
</xsl:element>
see an example here.