MENU
Basic Flow Control
<xsl:stylesheet>, <xsl:output>, <xsl:template>, <xsl:variable>, <xsl:for-each>, <xsl:value-of>, <xsl:copy-of>, <xsl:copy>
The example below defines a template matching the root element <a>, builds a <head> fragment in a variable, and iterates over the <b> children whose position is greater than another variable's value.<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="a.xslt"?>
<a>
<b>1<c>Cat</c></b>
<b>2<c>Cow</c></b>
<b>3<c>Dog</c></b>
<b>4<c>Fish</c></b>
</a><?xml version="1.0" encoding="UTF-8"?>
<!--a.xslt -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0"
encoding="UTF-8" indent="yes"/>
<xsl:template match="a">
<xsl:variable name="v" as="xs:integer" select="2"/>
<xsl:variable name="header" as="node()*">
<head>
<title>A B C</title>
</head>
</xsl:variable>
<html>
<xsl:copy-of select="$header"/>
<body>
<table><xsl:for-each select="b[position() > $v]">
<tr><td><xsl:value-of select="text()"/></td>
<td><xsl:value-of select="c"/></td>
</tr>
</xsl:for-each></table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>| 3 | Dog |
| 4 | Fish |
- id = id
- version = decimal
- default-mode = eqname | "#unnamed" — the default value for the mode attribute of every <xsl:template> and <xsl:apply-templates> element within its scope.
- default-validation = "preserve" | "strip" — "strip" gives new and contained nodes the type annotation xs:untyped (elements) or xs:untypedAtomic (attributes), replacing any previous annotation, and sets the typed value to the string value; "preserve" keeps existing type annotations on copied nodes, while newly constructed content is annotated as xs:anyType (elements) or xs:untypedAtomic (attributes).
- input-type-annotations = "preserve" | "strip" | "unspecified" — when stripping, every element's type annotation becomes xs:untyped, every attribute's becomes xs:untypedAtomic, every typed value becomes its string value as xs:untypedAtomic, and every element's is-nilled property becomes false.
- default-collation = URIs
- extension-element-prefixes = prefixes
- exclude-result-prefixes = prefixes
- expand-text = "yes" | "no"
- use-when = expression
- xpath-default-namespace = URI
<xsl:template>, <xsl:variable>, <xsl:param>, <xsl:function> and similar declarations can carry a visibility attribute:
- public: a using package may use <xsl:apply-templates> to invoke templates in this mode, and may also declare additional template rules in this mode, which take preference over the used package's rules. These may appear only as children of <xsl:override> inside <xsl:use-package>.
- private: a using package may neither reference the mode nor provide additional templates in it; the mode name is not even visible to the using package, so it may reuse the same name for its own modes without conflict.
- final: a using package may invoke templates in this mode with <xsl:apply-templates>, but must not provide additional template rules in it.
- abstract: the sequence constructor forming the template body must be empty (only <xsl:context-item> and <xsl:param> are permitted as children), and there must be no 'match' attribute.
<xsl:output> can have the following attributes: name (eqname), method ("xml" | "html" | "xhtml" | "text" | eqname), byte-order-mark, cdata-section-elements, doctype-public, doctype-system, encoding, escape-uri-attributes, html-version, include-content-type, indent, item-separator, media-type, normalization-form ("NFC" | "NFD" | "NFKC" | "NFKD" | "fully-normalized" | "none" | nmtoken), omit-xml-declaration, parameter-document, standalone ("yes" | "no" | "omit"), suppress-indentation, undeclare-prefixes, use-character-maps, version.
| <xsl:output method="xml" indent="yes"/> |
Use this setting to have XML or HTML output properly indented.
<xsl:template> can also carry mode and priority attributes. When a selected item matches more than one template rule under a given mode, only one rule is evaluated for that item; a rule with a higher priority is preferred.
<xsl:value-of> can carry a separator attribute, defining the string placed between adjacent items when the selected value is a sequence.
<xsl:copy-of> performs a deep copy, while <xsl:copy> performs a shallow copy. The function deep-copy($nodes) can also be used to perform a deep copy of nodes.
<xsl:copy-of> attributes: copy-namespaces ("yes" | "no"), type (eqname), validation ("strict" | "lax" | "preserve" | "strip").
<xsl:copy> attributes: copy-namespaces, inherit-namespaces, use-attribute-sets, type, validation, on-empty.
<xsl:variable> and <xsl:param> can carry a static attribute; when true, the variable or parameter becomes global and can also be used in <xsl:use-when> expressions.
Whenever the select attribute is absent from an instruction, the value is instead given as the instruction's child content.
<xsl:where-populated>, <xsl:on-non-empty>, <xsl:on-empty>
These instructions conditionally suppress output that would otherwise be empty. <xsl:where-populated> looks at content generated by its children, while <xsl:on-non-empty> looks at content generated by its siblings.……
<div id="students">
<xsl:where-populated>
<table>
<xsl:on-non-empty>
<thead>
<tr><th>Name</th><th>Age</th></tr>
</thead>
</xsl:on-non-empty>
<xsl:where-populated>
<tbody>
<xsl:for-each select="student/copy-of()">
<tr>
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="age"/></td>
</tr>
</xsl:for-each>
</tbody>
</xsl:where-populated>
</table>
</xsl:where-populated>
<xsl:on-empty>
<p>There are no students</p>
</xsl:on-empty>
</div>
……- The <xsl:where-populated> around the <table> element ensures that if neither a <thead> nor a <tbody> is produced, no <table> is output.
- The <xsl:on-non-empty> surrounding <thead> ensures that <thead> is not output unless the <tbody> element is output.
- The <xsl:where-populated> around <tbody> ensures that it is not output unless there is at least one row (<tr>).
- The <xsl:on-empty> around the <p> element ensures that if no <table> is output, the paragraph "There are no students" is output instead.
<xsl:for-each-group>
The example below groups test scores by subject and outputs the average score per subject.<?xml version="1.0" encoding="UTF-8"?>
<testScores>
<test>
<subject>Math</subject>
<score>78</score>
</test>
<test>
<subject>English</subject>
<score>90</score>
</test>
<test>
<subject>Malay</subject>
<score>59</score>
</test>
<test>
<subject>Math</subject>
<score>95</score>
</test>
<test>
<subject>English</subject>
<score>85</score>
</test>
</testScores><?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:template match="testScores">
<xsl:for-each-group
select="test"
group-by="subject">
<xsl:value-of select="current-grouping-key()"/>
<xsl:value-of select="avg(current-group()/score)"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
Math86.5English87.5Malay59
<xsl:iterate>, <xsl:next-iteration>, <xsl:break>, <xsl:on-completion>, <xsl:param>, <xsl:choose>, <xsl:when>, <xsl:otherwise>
Unlike <xsl:for-each>, processing with <xsl:iterate> is explicitly sequential, which lets each iteration see values computed by the previous one through a tunnel-style parameter. The example below walks a list of primes, printing each prime together with the gap ("leap") since the previous one.<?xml version="1.0" encoding="UTF-8"?>
<primes>
<i>2</i>
<i>3</i>
<i>5</i>
<i>7</i>
<i>11</i>
<i>13</i>
</primes><?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0"
encoding="UTF-8" indent="yes"/>
<xsl:template match="/primes">
<xsl:iterate select="i">
<xsl:param name="cnt" select="1"/>
<xsl:on-completion>
Primes are fun.
</xsl:on-completion>
<xsl:choose>
<xsl:when test="position()=1">
Prime: 2
<xsl:next-iteration>
<xsl:with-param name="cnt" select="$cnt+1"
as="xs:integer"/>
</xsl:next-iteration>
</xsl:when>
<xsl:when test="position() le 5">
Prime <xsl:value-of select="."/>
Leap: <xsl:value-of select=". - /*//i[$cnt - 1]"/>
<xsl:next-iteration>
<xsl:with-param name="cnt" select="$cnt+1"
as="xs:integer"/>
</xsl:next-iteration>
</xsl:when>
<xsl:otherwise>
<xsl:break/>
</xsl:otherwise>
</xsl:choose>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
Prime: 2
Prime 3 Leap: 1
Prime 5 Leap: 2
Prime 7 Leap: 2
Prime 11 Leap: 4
- as = sequence-type
- required = "yes" | "no"
- tunnel = "yes" | "no" — tunnel parameters are automatically passed on by the called template to any further templates it calls, and so on recursively, making a value accessible throughout an entire phase of stylesheet processing without every intermediate template needing to be aware of it. <xsl:with-param> can carry this attribute too.
- static = "yes" | "no"
- visibility = "public" | "private" | "final" | "abstract"
<xsl:if>, <xsl:try>, <xsl:catch>, <xsl:function>, <xsl:message>
<xsl:try> evaluates an expression and lets <xsl:catch> handle any dynamic error raised, exposing details through the $err:code, $err:description, $err:value, $err:module, $err:line-number and $err:column-number variables. The example below deliberately triggers a division-by-zero error by calling an undefined function (ns:plus) inside the expression, which XSLT reports through the same error-handling mechanism.<?xml version="1.0" encoding="UTF-8"?>
<division>
<num1>9999</num1>
<num2>9</num2>
</division><?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:err="http://www.w3.org/2005/xqt-errors"
xmlns:ns ="http://example.com">
<xsl:function name="ns:divide" as="xs:decimal">
<xsl:param name="x" as="xs:double"/>
<xsl:param name="y" as="xs:double"/>
<xsl:value-of select="$x div $y"/>
</xsl:function>
<xsl:template match="division">
<xsl:try select=
"xs:integer(ns:plus(num1,num2)) div xs:integer(num2)">
<xsl:catch errors="*">
<!--<xsl:catch errors="err:FOAR0001"> -->
<xsl:message>
Code: <xsl:value-of select="$err:code"/>
Description: <xsl:value-of select="$err:description"/>
Value: <xsl:value-of select="$err:value"/>
Module: <xsl:value-of select="$err:module"/>
Line-number: <xsl:value-of select="$err:line-number"/>
Column-number:
<xsl:value-of select="$err:column-number"/>
</xsl:message>
</xsl:catch>
</xsl:try>
</xsl:template>
</xsl:transform>Code: err:FOAR0001
Description: Division by zero
Value:
Module: x.xslt
Line-number: 17
Column-number: -1
A custom function, defined with <xsl:function>, must use a namespace.
<xsl:message> can carry the terminate ("yes" | "no") and error-code attributes.
<xsl:function> can have the following attributes: visibility ("public" | "private" | "final" | "abstract"), override-extension-function ("yes" | "no"), identity-sensitive ("yes" | "no"), cache ("full" | "partial" | "no").
Run examples that use <xsl:message> from the command line, or with an IDE such as oXygen, to see the message output.