An XSL file should start with:
<xsl:stylesheet version:"1.0" xmlns:xsl="http://www.w3.org/1999/xsl/Transform">
...
</xsl:stylesheet>
XPath is am XML navigation and selection language.
Path syntax: /step/step | step/step
Step syntax: axis::test[predicate]
XML document used in examples:
1 <?xml version="1.0" encoding="UTF-8" ?>
2 <store>
3 <book>
4 <title lang="en">Catch-22</title>
5 <price>29.95</price>
6 </book>
7 <book>
8 <title lang="en">Walden</title>
9 <price>15.95</price>
10 </book>
11 <book>
12 <title>Nightwatch</title>
13 <price>25.50</price>
14 </book>
15 <store lang="ge">
16 <book>
17 <title lang="ge">Die Verwandlung</title>
18 <price>8.99</price>
19 </book>
20 </store>
21 <overstock>
22 <book>
23 <title lang="en">Ubuntu Kung-Fu</title>
24 <price>34.99</price>
25 </book>
26 </ovestock>
27 </store>
28 <book>
29 <title lang="fr">La Petite Prince</title>
30 <price>18.00</price>
31 </book>
nodename = selects all nodes with that name
/ = starts at the root node, absolute path to nodes
// = selects nodes from anywhere that match the selection
. = selects the current node
.. = selects the parent of the current node
@ = selects attributes
XPath: "store"
Selects elements "store" at 2 and 15
XPath: "/store"
Selects element "store" at 2
XPath: "store/book"
Selects elements "book" at 3, 7, 11, and 16
XPath: "//book"
Selects elements "book" at 3, 7, 11, 16, 22, and 28
XPath: "store//book"
Selects elements "book" at 3, 7, 11, 16, and 22
XPath: "//@lang"
Selects elements "title" at 4, 8, 17, 23, 29
Selects element "store" at 15
Predicates are conditions added to the end of selectors. They are always inside [].
[1] = a specific index (indexes start at 1)
[last()] = the last element
[last()-1] = the second to last element
[position()<3] = the first and second elements
[@lang] = elements with a lang attribute defined
[@lang='en'] = elements with a lang='en' attribute defined
[price > 35] = element has a direct child called price, and its value is greater than 35
[starts-with(.,'Ubuntu')] = element has inner text that starts with this string
[text()='exact text'] = element has inner text that exactly matches this string
Operators: + - * div = != < <= > >= or and mod
XPath: "/store/book[2]"
Selects element "book" at 7
XPath: "/store/book[last()]"
Selects element "book" at 11
XPath: "//title[@lang]"
Selects elements "title" at 4, 8, 17, 23, and 29
XPath: "store/book[price > 25]/title"
Selects elements "title" at 4 and 12
XPath: "//title[starts-with(.,'Ubuntu')]"
Selects elements "title" at 23
* = any element node
@* = any attribute node
node() = any node of any kind
text() = the text contents of the current node
You can union multiple paths with |.
store/book | overstock/book
Selects a node set relative to the current node.
self = select current node
attribute = selects all attributes of current node
namespace = select all namespace nodes of the current node
ancestor = selects every ancestor
ancestor-or-self = selects every ancestor plus the current node
descendent = select all descendents
descendent-or-self = select all descendents plus the current node
child = select all direct children
parent = select the direct parent
following = select everything in the xml document after the closing tag of the current node
following-sibling = select all siblings of the current node that occur after it
preceding = select everything in the xml document before the current node tag EXCEPT for ancestors of the current node
preceding-sibling = select all siblings of the current node that occurred before it
XPath: "book[3]/ancestor::store"
Selects elements "store" at 2
You can test an XPath selector in your browser.
- F12 to open developer tools
- go the Inspector (aka Elements) tab
- Ctrl-F to open Search
- test your XPath in the Inspector search bar
XSLT stands for Extensible Stylesheet Language Transformation.
XSLT transforms XML documents into XML, TXT, HTMl, etc documents. It can add, remove, rearrange, sort, and change elements and attributes. It can perform tests and make decisions.
An XSLT document can use extension .xslt or .xsl.
The official W3C XSLT namespace is available at "http://www.w3.org/1999/xsl/Transform".
XML document used in examples:
<?xml version="1.0" encoding="UTF-8" ?>
<catalog>
<cd>
<artist>The Beatles</artist>
<title>Best of the Beatles</title>
<price>12.99</price>
</cd>
</catalog>
Templates are reusable XSLT blocks.
The match attribute is an XPath defining what elements to apply this template to. All the XSLT within the template is relative to the element the template is applied to.
You can have multiple templates per XSLT file.
Template applied to root node:
<xsl:template match="/">
...
</xsl:template>
Named templates:
<xsl:template name="footer">
...
</xsl:template>
Apply-templates finds the appropriate template for each node and applies it.
For each node in current set:
<xsl:apply-templates/>
For each node in current set selected by this XPath:
<xsl:apply-templates select="artist"/>
Example:
<xsl:template match="/">
<html>
<body>
My CDs:
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="cd">
<p>
<xsl:apply-templates select="title"/> -
<xsl:apply-templates select="artist"/>
</p>
</xsl:template>
<xsl:template match="title">
Title: <xsl:value-of select="."/>
</xsl:template>
<xsl:template match="artist">
Artist: <xsl:value-of select="."/>
</xsl:template>
1. Templates in primary (current) stylesheet are used before imported templates.
2. Templates with a higher "priority" attribute are used first.
3. Templates with any "priority" attribute are used before templates without the attribute.
4. Templates with more specific XPath patterns are used first.
If more than one template is still possible after all that, you'll either get an error or the last template will be selected.
You can explicitly used a named template.
<xsl:call-template name="footer"/>
You can pass parameters into templates, whether you use apply-templates or call-template.
<xsl:apply-templates>
<xsl:with-param name="paramA" select="artist"/>
<xsl:with-param name="paramB" select="title"/>
<xsl:with-param name="paramC">constant</xsl:with-param>
<xsl:with-param name="paramD" select="'constant'"/>
</xsl:apply-templates>
<xsl:template match="cd">
<xsl:param name="paramA"/>
<xsl:param name="paramB"/>
<xsl:param name="paramC">Default Value</xsl:param>
...
<!-- reference with $paramA -->
</xsl:template>
XSLT variables are all constants, you cannot change their value.
Place them at the top of the file as global variables, or within a template as local variables.
Declaring variables:
<xsl:variable name="varA">constant</xsl:variable>
<xsl:variable name="varB" select="cd[2]"/>
<xsl:variable name="varC" select="'constant'"/>
Referencing variables:
<xsl:with-param name="paramA" select="$varA"/>
Loops through a node set.
The default sort order is "ascending".
The default sort-data-type is "text".
The options for case-order are "upper-first" and "lower-first".
<xsl:for-each select="catalog/cd">
<xsl:sort select="artist"/>
...
</xsl:for-each>
<xsl:sort select="price" data-type="number" order="descending"/>
<xsl:sort select="artist" case-order="upper-first"/>
The contents of an If block are only used if the XPath predicate is true.
<xsl:if test="price > 10">
...
</xsl:if>
String operations:
test="string-length($paramA) > 0"
test="contains($text, $substring)"
test="substring-before($text, $substring)"
test="substring-after($text, $substring)"
Boolean operations:
test="not($paramB)"
Choose works like a if,else if,else statement. The first "when" whose XPath predicate returns "true" is used.
<xsl:choose>
<xsl:when test="price > 10">
...
</xsl:when>
<xsl:when test="price > 5">
...
</xsl:when>
<xsl:otherwise>
...
</xsl:otherwise>
</xsl:choose>
<xsl:text>plain text</xsl:text>
Adding an attribute to an element node.
<img>
<xsl:attribute name="src">
<xsl:value-of select="image/name"/>
</xsl:attribute>
</img>
Outputs a copy of the current node as-is, with no descendents.
<xsl:copy>...</xsl:copy>
Outputs a copy of the selected node as-is, with all descendents.
<xsl:copy-of select="header"/>
<xsl:comment>Comments</xsl:comment>
Outputs an error message and (optionally) terminates transformation.
<xsl:message terminate="yes">Message</xsl:message>
An XSLT document can only have one "output" element, and it must be directly under the "xsl:stylesheet" or "xsl:transform" element.
It defines the format of the output document. There are a lot of optional attributes.
<xsl:output indent="yes"/>
XML input document:
<?xml version="1.0" encoding="UTF-8"?>
<menu>
<food>
<name>Eggs Over Easy</name>
<price>5.95</price>
<calories>120</calories>
</food>
<food>
<name>Waffles</name>
<price>8.95</price>
<calories>420</calories>
</food>
<food>
<name>Oatmeal</name>
<price>3.50</price>
<calories>230</calories>
</food>
</menu>
XSLT document:
<?xml version="1.0" encoding="UTF-8"?>
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/Transform">
<body>
<xsl:for-each select="menu/food">
<div>
<p>
<xsl:value-of select="name"/> - $<xsl:value-of select="price"/>
</p>
<span>
(<xsl:value-of select="calories"/> calories)
</span>
</div>
</xsl:for-each>
</body>
</html>
HTML output document:
<html>
<body>
<div>
<p>
Eggs Over Easy - $5.95
</p>
<span>
(120 calories)
</span>
</div>
<div>
<p>
Waffles - $8.95
</p>
<span>
(420 calories)
</span>
</div>
<div>
<p>
Oatmeal - $3.50
</p>
<span>
(230 calories)
</span>
</div>
</body>
</html>