Elected member of the W3C Technical Architecture Group; chair of the XML Processing Model Working Group; co-chair of the XML Core WG; member of the XSL WG. Joint editor of several XSL/XML Query Specs.
Chair of the OASIS DocBook Technical Committee, member of the Entity Resolution TC and the RELAX NG TC.
Specification Lead for JSR 206: Java API for XML Processing
Seven core specifications; most recent Working Drafts published in June, 2006. We've reached “Candidate Recommendation” stage.
XQuery 1.0 and XPath 2.0 Data Model
XQuery 1.0 and XPath 2.0 Functions and Operators
XQuery 1.0 and XPath 2.0 Formal Semantics
XML Path Language (XPath) 2.0
XSL Transformations (XSLT) Version 2.0
XSLT 2.0 and XQuery 1.0 Serialization
XQuery 1.0: An XML Query Language
Plus XQueryX, Updates, Full Text, …
The family of XSL and XML Query specifications are closely related. Many of the specifications depend on each other.
A subset of the specifications and some of their relationships.
XPath 2.0 has nodes and typed values. Colloquially, there are three kinds of things: nodes, simple or atomic values, and items. An item is either a node or an atomic value.
XPath 2.0 has sequences where XPath 1.0 had node sets:
Sequences can be in arbitrary order
Sequences can contain duplicates
Sequences can be heterogenous
Functions. Lots of functions.
String and numeric functions
Date, time and duration functions
QName and namespace functions
Regex functions
Sequence manipulation functions
Casting and type-related functions
XSLT 2.0 uses XPath 2.0
This tutorial doesn't really cover XPath 2.0
But naturally, we'll be using it all over the place.
Serialization is a separate specification.
XSLT users can influence serialization with xsl:output attributes.
XPath 2.0 has both static and dynamic semantics.
Support for static analysis is optional.
The Formal Semantics specification describes the static semantics of XPath.
The XPath 2.0 specification describes the dynamic semantics of XPath.
The XSLT 2.0 specification describes all of the semantics of XSLT.
Everyone’s third favorite toy example, the recipe collection. Our recipe list is defined by the schema described on the following slides.
Do you need to perform W3C XML Schema validation to use XPath 2.0/XSLT 2.0?
No.
Do some features require validation?
Yes.
Can I use some other validation technology?
Maybe. Yes, in principle, but not yet in practice.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://nwalsh.com/xmlns/extreme2006/recipes/" xmlns:r="http://nwalsh.com/xmlns/extreme2006/recipes/"> <xs:complexType name="RecipeList"> <xs:sequence> <xs:element ref="r:recipe" minOccurs="1" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:element name="recipeList" type="r:RecipeList"/>
<xs:simpleType name="Servings"> <xs:restriction base="xs:integer"> <xs:minInclusive value="1"/> <xs:maxInclusive value="12"/> </xs:restriction> </xs:simpleType>
<xs:complexType name="Recipe"> <xs:sequence> <xs:element ref="r:name"/> <xs:element ref="r:source" minOccurs="0" maxOccurs="1"/> <xs:element ref="r:description" minOccurs="0" maxOccurs="1"/> <xs:element ref="r:ingredientList" minOccurs="1" maxOccurs="unbounded"/> <xs:element ref="r:preparation"/> </xs:sequence> <xs:attribute name="servings" type="r:Servings"/> <xs:attribute name="time" type="xs:duration"/> <xs:attribute name="calories" type="xs:positiveInteger"/> </xs:complexType>
<xs:complexType name="FoodRecipe"> <xs:complexContent> <xs:extension base="r:Recipe"/> </xs:complexContent> </xs:complexType> <xs:complexType name="CandyRecipe"> <xs:complexContent> <xs:extension base="r:FoodRecipe"> <xs:attribute name="sugarfree" type="xs:boolean"/> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="DrinkRecipe"> <xs:complexContent> <xs:extension base="r:Recipe"> <xs:attribute name="virgin" type="xs:boolean"/> </xs:extension> </xs:complexContent> </xs:complexType>
<xs:element name="recipe" type="r:Recipe" abstract="true"/> <xs:element name="beverage" type="r:DrinkRecipe" substitutionGroup="r:recipe"/> <xs:element name="appetizer" type="r:FoodRecipe" substitutionGroup="r:recipe"/> <xs:element name="entrée" type="r:FoodRecipe" substitutionGroup="r:recipe"/> <xs:element name="sidedish" type="r:FoodRecipe" substitutionGroup="r:recipe"/> <xs:element name="dessert" type="r:FoodRecipe" substitutionGroup="r:recipe"/> <xs:element name="candy" type="r:CandyRecipe" substitutionGroup="r:recipe"/>
<xs:complexType name="Prose"> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element ref="r:p"/> <xs:element ref="r:list"/> </xs:choice> </xs:complexType> <xs:complexType name="Para" mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="em" type="xs:string"/> </xs:choice> </xs:complexType> <xs:complexType name="NumberedList"> <xs:sequence> <xs:element name="item" minOccurs="1" maxOccurs="unbounded" type="r:Prose"/> </xs:sequence> </xs:complexType>
<xs:element name="description" type="r:Prose"/> <xs:element name="preparation" type="r:Prose"/> <xs:element name="p" type="r:Para"/> <xs:element name="list" type="r:NumberedList"/> <xs:element name="title" type="r:Para"/> <xs:element name="name" type="r:Para"/> <xs:element name="source" type="r:Para" nillable="true"/>
<xs:complexType name="IngredientList"> <xs:sequence> <xs:element ref="r:title" minOccurs='0' maxOccurs='1'/> <xs:element ref="r:ingredient" minOccurs='1' maxOccurs='unbounded'/> </xs:sequence> </xs:complexType> <xs:element name="ingredientList" type="r:IngredientList"/>
<xs:complexType name="Ingredient"> <xs:sequence> <xs:element name="quantity" minOccurs="0" maxOccurs="1"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:double"> <xs:attribute name="units"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:element name="name" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:element name="ingredient" type="r:Ingredient"/>
Many of the W3C XML Schema simple types are always available.
In order to refer to additional types, you must import the schema that defines them:
<xsl:import-schema namespace="http://nwalsh.com/xmlns/extreme2006/recipes/" schema-location="recipes.xsd"/>
You must specify at least the namespace or the schema location, if not both.
The “as” attribute is used to declare types.
<xsl:variable name="i" select="1"/>
is the integer value 1.
<xsl:variable name="fp" select="1" as="xs:double"/>
is the double value 1.0.
<xsl:variable name="rtf"> <a/> <b/> </xsl:variable>
<xsl:variable name="elemlist" as="element()*"> <a/> <b/> </xsl:variable>
<xsl:variable name="elemlist" as="element(r:recipe)+"> ...select or contruct Recipes... </xsl:variable>
The constructor functions, xs:type(string), attempt to construct the typed value from the lexical form provided.
The as attribute asserts that the value must have the required type. It performs simple type promotions but doesn’t, for example, implicitly cast as the requested type.
If a type cannot be cast to another type, attmpting the cast will generate a type error. Some (perhaps many) of the things you’re used to doing in XPath 1.0 will generate type errors in XPath 2.0:
Math operations on strings (@attr + 1 if attr is validated as a string type).
Invalid lexical representations (“12/08/2003” is not a valid lexical form for dates, use “2003-12-08” instead).
Incompatible casts (100 cast as r:Servings).
From subtypes to supertypes (xs:NMTOKEN where xs:string is required).
Between numeric types (xs:decimal to xs:double, etc.)
Computing effective boolean values (“NaN” to false())
From “untyped” values
The <xsl:sequence> instruction is used to construct sequences of nodes or atomic values (or both).
<xsl:sequence select='(1,2,3,4)'/>
returns a sequence of integers.
<xsl:sequence select='(1,2,3,4)' as="xs:double"/>
returns a sequence of doubles.
Suppose we want to compute the prices of a list of products:
<xsl:variable name="products"> <product cost="90" price="100"/> <product cost="100"/> <product cost="100" price="90"/> </xsl:variable>
If a product has a price, then that's its price, otherwise, its price is 150% of its cost.
The following code defines $prices to contain a sequence of decimal values computed from the prices of each product.
<xsl:variable name="prices"> <xsl:for-each select="$products/product"> <xsl:choose> <xsl:when test="@price"> <xsl:sequence select="xs:decimal(@price)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="xs:decimal(@cost) * 1.5"/> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:variable>
So does this:
<xsl:value-of select="for $p in products return if ($p/@price) then xs:decimal($p/@price) else xs:decimal($p/@cost) * 1.5"/>
Why is the former better? Because if you run the latter stylesheet through a processor, you’ll get:
<xsl:value-of select="for $p in products return if ($p/@price) then xs:decimal($p/@price) else (xs:decimal($p/@cost) * 1.5)"/>
Which I find a little hard to read. My recommendation: use XSLT whenever you can.
What’s the difference between xsl:value-of, xsl:copy-of, and xsl:sequence?
xsl:value-of always creates a text node.
xsl:copy-of always creates a copy.
xsl:sequence returns the nodes selected, subject possibly to atomization. Sequences can be extended with xsl:sequence.
Grouping in XSLT 1.0 is hard. XSLT 2.0 provides a new, flexible grouping instruction for grouping…
on a specific key
by transitions at the start of each group
by transitions at the end of each group
by adjacent key values
Groups can also be sorted.
Group the following data by country:
<cities> <city name="Milano" country="Italia"/> <city name="Paris" country="France"/> <city name="München" country="Deutschland"/> <city name="Lyon" country="France"/> <city name="Venezia" country="Italia"/> </cities>
<xsl:for-each-group select="cities/city" group-by="@country"> <tr> <td><xsl:value-of select="position()"/></td> <td><xsl:value-of select="@country"/></td> <td> <xsl:value-of select="current-group()/@name" separator=", "/> </td> </tr> </xsl:for-each-group>
Group the following data so that the implicit divisions created by each h1 are explicit:
<body> <h1>Introduction</h1> <p>XSLT is used to write stylesheets.</p> <p>XQuery is used to query XML databases.</p> <h1>What is a stylesheet?</h1> <p>A stylesheet is an XML document used to define a transformation.</p> <p>Stylesheets may be written in XSLT.</p> <p>XSLT 2.0 introduces new grouping constructs.</p> </body>
<xsl:for-each-group select="*" group-starting-with="h1"> <div> <xsl:apply-templates select="current-group()"/> </div> </xsl:for-each-group>
<div> <h1>Introduction</h1> <p>XSLT is used to write stylesheets.</p> <p>XQuery is used to query XML databases.</p> </div> <div> <h1>What is a stylesheet?</h1> <p>A stylesheet is an XML document used to define a transformation.</p> <p>Stylesheets may be written in XSLT.</p> <p>XSLT 2.0 introduces new grouping constructs.</p> </div>
Group the following data so that continued pages are contained in a pageset:
<doc> <page continued="yes">Some text</page> <page continued="yes">More text</page> <page>Yet more text</page> <page continued="yes">Some words</page> <page continued="yes">More words</page> <page>Yet more words</page> </doc>
<xsl:for-each-group select="*" group-ending-with="page[not(@continued ='yes')]"> <pageset> <xsl:for-each select="current-group()"> <page><xsl:value-of select="."/></page> </xsl:for-each> </pageset> </xsl:for-each-group>
Group the following data so that lists do not occur inside paragraphs:
<p>Do <em>not</em>: <ul> <li>talk,</li> <li>eat, or</li> <li>use your mobile telephone</li> </ul> while you are in the cinema.</p>
<xsl:for-each-group select="node()" group-adjacent="self::ul or self::ol"> <xsl:choose> <xsl:when test="current-grouping-key()"> <xsl:copy-of select="current-group()"/> </xsl:when> <xsl:otherwise> <p> <xsl:copy-of select="current-group()"/> </p> </xsl:otherwise> </xsl:choose> </xsl:for-each-group>
There are three regular-expression functions that operate on strings:
matches() tests if a regular expression matches a string.
replace() uses regular expressions to replace portions of a string.
tokenize() returns a sequence of strings formed by breaking a supplied input string at any separator that matches a given regular expression.
The xsl:analyze-string instruction uses regular expressions to apply markup to a string.
<xsl:analyze-string select="…" regex="…"> <xsl:matching-substring>…</xsl:matching-substring>… <xsl:non-matching-substring>…</xsl:non-matching-substring>… </xsl:analyze-string>
The regex-group() function allows you to look back at matching substrings.
These instructions transform dates of the form “12/8/2003” into ISO 8601 standard form: “2003-12-08” using the regular expression instructions.
<xsl:analyze-string select="$date" regex="([0-9]+)/([0-9]+)/([0-9]{{4}})"> <xsl:matching-substring> <xsl:number value="regex-group(3)" format="0001"/> <xsl:text>-</xsl:text> ...
Note that the curly braces are doubled in the regular expression. The regex attribute is an attribute value template, so to get a single “{” in the attribute value, you must use “{{” in the stylesheet.
Let's combine what we've learned about regular expressions and grouping to solve a real (looking) problem.
2006-05-21 3.1,4.3,2.5,1.6,1.6,2.0 2.3,8.4,0.9,2.8,4.0,3.1 2.3,9.4,2.0,9.4,8.2,3.0 === 0.8,2.0,2.8,4.2,3.4,9.8 0.9,3.2,8.4,0.9,8.3,2.4 2006-05-22 6.2,4.3,5.3,4.5,5.4,3.5 8.7,3.5,6.9,1.5,2.9,2.3 2.7,7.5,7.5,0.9,7.5,0.9 2006-05-23 7.3,1.4,0.9,7.4,0.9,5.7 0.9,7.4,3.5,0.9,8.7,3.4 === 9.8,7.9,5.7,9.5,7.2,1.0 === 4.7,5.0,9.7,2.3,4.7,2.4 0.9,5.8,7.2,4.5,0.9,8.7 9.7,3.2,5.9,8.7,9.8,7.5 4.9,8.7,5.9,8.7,2.9,4.7 2006-06-04 9.8,7.5,9.8,7.5,9.7,1.2 0.9,7.5,0.9,7.1,0.9,8.7 2.3,5.0,9.7,2.0,9.8,7.2 4.6,5.0,9.7,1.4,5.0,9.7
<days> <day> <date>May 21, 2006</date> <group> <n>3.1</n><n>4.3</n><n>2.5</n>… <n>2.3</n><n>8.4</n><n>0.9</n>… <n>2.3</n><n>9.4</n><n>2.0</n>… <n>0.8</n><n>2.0</n><n>2.8</n>… <n>0.9</n><n>3.2</n><n>8.4</n>… </group> <group> <n>6.2</n><n>4.3</n><n>5.3</n>… …
At the instruction level, XSLT 1.0 and 2.0 provide mechanisms for calling named templates. They also provide mechanisms for calling user-defined extension functions. What’s new is the ability to declare user-defined functions in XSLT.
<xsl:function name="str:reverse" as="xs:string"> <xsl:param name="sentence" as="xs:string"/> <xsl:value-of separator=" "> <xsl:choose> <xsl:when test="contains($sentence, ' ')"> <xsl:sequence select="str:reverse(substring-after($sentence, ' '))"/> <xsl:sequence select="substring-before($sentence, ' ')"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="$sentence"/> </xsl:otherwise> </xsl:choose> </xsl:value-of> </xsl:function>
This can be called from XPath: select="str:reverse('DOG BITES MAN')".
Extend the function library.
Most XSLT 1.0 processors support extension functions.
Saxon 8.x supports extension functions.
The distance between two points on the earth is Δσ × Rl where:
Rl is the radius at the appropriate geocentric latitude:
where a is the equatorial radius and b is the polar radius.
And Δσ is the angular distance between the two points:
where ϕ1, λ1; ϕ2, λ2 are the latitude and longitude of the two points, respectively, and Δλ is the longitudinal difference between the points.
It is technically possible to compute this distance in XSLT, but that's perhaps not the easiest way.
Extend the instruction library.
Most XSLT 1.0 processors support extension elements.
Saxon 8.x supports extension elements.
Stylesheets can be included or imported:
<xsl:include> provides source code modularity.
<xsl:import> provides logical modularity.
<xsl:apply-imports> allows an importing stylesheet to apply templates from an imported stylesheet.
What’s new is <xsl:next-match>
Character maps give you greater control over serialization. They map a Unicode character to any string in the serialized document.
For XML and HTML output methods, the resulting character stream does not have to be well-formed.
The mapping occurs only at serialization: it is not present in result tree fragments.
This facility can be used instead of “disabled output escaping” in most cases.
Suppose you want to construct an XHTML document that uses for non-breaking spaces, é for “é”, etc.
<xsl:output method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" use-character-maps="example-map"/> <xsl:character-map name="example-map"> <xsl:output-character character="é" string="&eacute;"/> <xsl:output-character character=" " string="&nbsp;"/> </xsl:character-map>
Suppose you want to construct a JSP page that contains:
<jsp:setProperty name="user" property="id" value="'<%= "id" + idValue %>'"/>
Pick some otherwise unused Unicode characters to represent the character sequences that aren’t valid XML. For example, “«” for “<%=”, “»” for “%>”, and “·” for the explicit double quotes:
<jsp:setProperty name="user" property="id" value='« ·id· + idValue »'/>
Construct a character map that turns those characters back into the invalid strings:
<xsl:character-map name="jsp"> <xsl:output-character character="«" string="<%"/> <xsl:output-character character="»" string="%>"/> <xsl:output-character character="·" string='"'/> </xsl:character-map>
Break libraries into useful units.
Break along schema-dependent boundaries.
Document the functions.
Provide unit tests.
Staging in XSLT:
Modes
Explicit calls
Priority and next-match
Staging with a framework (like XProc :-)
<xsl:template match="/"> ... <xsl:apply-templates select="." mode="mode1"/> ... </xsl:template> <xsl:template match="/" mode="mode1"> ... <xsl:apply-templates select="." mode="mode2"/> ... </xsl:template> <xsl:template match="/" mode="mode2"> ... <xsl:apply-templates/> ... </xsl:template>
Appears “ordinary” to users
Can be easily extended
Requires more familiarity to write extensions
<xsl:template name="start-here"> <xsl:call-template name="stage1"/> </xsl:template> <xsl:template name="stage1"> <xsl:call-template name="stage2"/> </xsl:template> <xsl:template name="stage2"> <xsl:apply-templates/> </xsl:template>
Users must supply the starting template
Extension requires replacing existing templates
Requires more familiarity to write extensions
<xsl:template match="/" priority="10000"> <xsl:next-match/> </xsl:template> <xsl:template match="/" priority="9000"> <xsl:next-match/> </xsl:template> <xsl:template match="/" priority="8000"> <xsl:apply-templates/> </xsl:template>
Appears “ordinary” to users (but import precedence trumps priority)
Can be extended
Requires more familiarity to write extensions
Do you think in terms of push or pull?
Do you need to apply the stages to lots of different elements?
Do you care about user customization or extension?
Are you going to xsl:include the base, or xsl:import it?
An XSLT 1.0 processor handles 2.0 stylesheets in forwards compatibility mode
An XSLT 2.0 processor handles 1.0 stylesheets:
As a 1.0 processor, or
in backwards compatibility mode
A mixed-mode stylesheet uses the appropriate mode.
Although the goal is that a 2.0 processor running a 1.0 stylesheet in backwards compatibility mode should produce the same results as a 1.0 processor, this is not guaranteed to be the case for all stylesheets.
What does this stylesheet produce?
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="2.0"> <xsl:output method="text"/> <xsl:param name="doc"> <doc> <p>One</p> <p>Two</p> <p>Three</p> </doc> </xsl:param> <xsl:template match="/"> <xsl:text>There are </xsl:text> <xsl:value-of select="count($doc//p)"/> <xsl:text> paras. </xsl:text> </xsl:template> </xsl:stylesheet>
It produces:
There are 0 paras.
Why?
Because “doc” is in the default namespace and “//p” matches elements in no namespace.
This would work:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xpath-default-namespace="http://www.w3.org/1999/xhtml" version="2.0"> ...
So would this:
<xsl:value-of xmlns:x="http://www.w3.org/1999/xhtml" select="count($doc//x:p)"/>
Write an XSLT stylesheet function that returns true if two elements “match”:
f:element-matches($srcElem, $targetElem)
Two elements match if:
They have the same name (use the node-name function).
Every attribute on $srcElem that is not in a namespace is also on $targetElem and has the same value.
Namespace qualified attributes on $srcElem are ignored.
Extra attributes are allowed on $targetElem.
Here’s one approach:
<xsl:function name="f:element-matches" as="xs:boolean"> <xsl:param name="srcElement" as="element()"/> <xsl:param name="targetElem" as="element()"/> <xsl:choose> <xsl:when test="node-name($srcElement) = node-name($targetElem)"> <xsl:variable name="attrMatch"> <xsl:for-each select="$srcElement/@*[namespace-uri(.) = '']"> <xsl:variable name="aname" select="local-name(.)"/> <xsl:variable name="attr" select="$targetElem/@*[local-name(.) = $aname]"/> <xsl:choose> <xsl:when test="$attr = .">1</xsl:when> <xsl:otherwise>0</xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:variable> <xsl:value-of select="not(contains($attrMatch, '0'))"/> </xsl:when> <xsl:otherwise><xsl:value-of select="false()"/></xsl:otherwise> </xsl:choose> </xsl:function>
That function can be replaced by a single XPath 2.0 expression. What is it?
(node-name($srcElem) = node-name($targetElem)) and (every $i in $srcElem/@*[namespace-uri(.) = ''] satisfies for $j in $targetElem/@*[local-name(.) = local-name($i)] return $i = $j
XPath 2.0 and XSLT 2.0 are larger and more complex than their predecessors. Schema support and “strong” typing will catch errors, but they will also force more explicit casting.
Does it make sense to start developing for 2.0?
Yes, I think so. Grouping, regular expressions, user-defined functions, character maps, standardized access to result documents and multiple result documents are all going to make stylesheet writing easier.
Many of the examples in this tutorial are taken directly from the XSLT 2.0 Specification.
Michael Kay generously shared a number of examples that he uses in his own tutorials.
David Carlisle suggested the XPath replacement for matching elements.
XQuery 1.0 and XPath 2.0 Data Model, http://www.w3.org/TR/xpath-datamodel/. Mary Fernández, Ashok Malhotra, Jonathan Marsh, et. al., editors. World Wide Web Consortium. 2006.
XQuery 1.0 and XPath 2.0 Functions and Operators, http://www.w3.org/TR/xpath-functions/. Ashok Malhotra, Jim Melton, and Norman Walsh, editors. World Wide Web Consortium. 2006.
XQuery 1.0 and XPath 2.0 Formal Semantics, http://www.w3.org/TR/xquery-semantics/. Denise Draper, Peter Frankhauser, Mary Fernández, et. al., editors. World Wide Web Consortium. 2006.
XML Path Language (XPath) 2.0, http://www.w3.org/TR/xpath20/. Anders Berglund, Scott Boag, Don Chamberlin, et. al., editors. World Wide Web Consortium. 2006.
XQuery 1.0: An XML Query Language, http://www.w3.org/TR/xquery/. Scott Boag, Don Chamberlin, Mary Fernández, et. al., editors. World Wide Web Consortium. 2006.
XSL Transformations (XSLT) Version 2.0, http://www.w3.org/TR/xslt20/. Michael Kay, editor. World Wide Web Consortium. 2006.
XSLT 2.0 and XQuery 1.0 Serialization, http://www.w3.org/TR/xslt-xquery-serialization/. Michael Kay, Norman Walsh, and Henry Zongaro, editors. World Wide Web Consortium. 2006.
Typing in Transformations, http://www.idealliance.org/papers/extreme03/html/2003/Tennison01/EML2003Tennison01-toc.html. . Extreme Markup Languages. 2003.
These slides: http://nwalsh.com/docs/tutorials/extreme06/.
The matching elements example comes from a real-life problem: http://norman.walsh.name/2004/07/27/titlepages.