Introduction to Result Tree Fragments
The XPath specification defines four basic data types that are accessible in XPath location steps, function references, and so on:
- strings
- numbers
- Booleans
- node-sets
To these basic XPath data types, the XSLT specification adds a fifth: result tree fragments.
A result tree fragment is a part of the result tree of an XSLT transformation. That is, it is a template to be instantiated in the result tree—specifically, a template instantiated by a non-empty <xsl:variable>
or <xsl:param>
element. The result tree fragment can be well-formed, but does not have to be. It only has to be well-balanced—that is, each start tag must include an end tag, the tags must be nested properly, and so on.
A data set differs from a result tree fragment in that the data set has a root element containing other elements. This root element can the document's own root element, or a child of the document's root element.
The following code fragment from an XSLT style sheet is an example of how an <xsl:variable>
element can create a non-well-formed, but well-balanced, result tree fragment.
<xsl:variable name="tree"> <em>Emphasized and <b>bold</b></em> words </xsl:variable>
The result tree instantiated by this variable will be the following:
<em>Emphasized and <b>bold</b></em> words
That is, it consists of:
- A complete
<em>
element, containing some text and a<b>
element, which itself includes some text. - Some trailing text: the string
" words"
.
If you define a variable or parameter which is not empty, you will often want to then attempt some operation on the value of the variable or parameter. If you try to do so using built-in XPath and XSLT functions, it will probably not produce the desired result. This is because those functions are intended to be used with one of the four basic data types, not with result tree fragments.
XSLT File (rtf.xsl)
Suppose you want to walk the tree established by the $tree
variable in the fragment above. The following XSLT file attempts to do this. The file contains a template rule to be applied to the XML result tree fragment, <em>Emphasized and <b>bold</b></em> words
.
<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="rtf.xsl" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="tree">
<em>Emphasized and <b>bold</b></em> words
</xsl:variable>
<xsl:template match="/">
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<th>Node name</th>
<th>Node type</th>
</tr>
<!-- Show document root and each element in $tree variable. -->
<xsl:for-each select="$tree/descendant-or-self::*|$tree"
>
<tr>
<td>
<xsl:choose>
<xsl:when test="name()=''">
(DOC ROOT)
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="name()"/>
</xsl:otherwise>
</xsl:choose>
</td>
<td><xsl:value-of select="."/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
Result
You might apply this style sheet to itself, as follows:
Try { xslt.transformNode(xslt); } catch (e) alert(e.description); }
This results in the following runtime error:
Expression must evaluate to a node-set. -->$tree<--/...
Here xslt
refers to a DOM instance of the XSLT style sheet. This example might seem artificial, but you will almost certainly encounter similar problems in real-world situations, such as sorting and grouping.
To get around this common problem, you can use msxsl:node-set()
to convert the result tree fragment into a node set.