Result Tree Fragment in Transformations

Note

The XslTransform class is obsolete in the .NET Framework 2.0. You can perform Extensible Stylesheet Language for Transformations (XSLT) transformations using the XslCompiledTransform class. See Using the XslCompiledTransform Class and Migrating From the XslTransform Class for more information.

Result tree fragments, also known as result tree fragments, are nothing more than a special type of node set. You can perform any function on them that can be performed on a node set. Or, you can also convert a result tree fragment to a node set using the node-set() function and subsequently use it any place that a node set can be used.

A result tree fragment is created as a result of using an <xsl:variable> or <xsl:param> element in a specific manner in a style sheet. The syntax for the variable and parameter elements is as follows:

<xsl:param name=Qname select= XPath Expression >
    template body
</xsl:param>

<xsl:variable name=Qname select=XPath Expression >
    template body
</xsl:variable>

For the parameter element, the value is assigned to the qualified name (Qname) in several ways. You can assign a default value to the parameter by returning content from the XML Path Language (XPath) expression in the select attribute, or by assigning it the contents of the template body.

For the variable element, the value is also assigned in several ways. You can assign it by returning content from the XPath expression in the select attribute, or by assigning it the contents of the template body.

For both the parameter and variable elements, if a value is assigned by the XPath expression, then one of the four basic XPath types will be returned: Boolean, string, number, or node set. When the value is given by using a non-empty template body, then a non-XPath data type is returned, and that will be a result tree fragment.

When a variable is bound to a result tree fragment instead of one of the four basic XPath data types, this is the only time that an XPath query returns a type that is not one of the four XPath object types. Result tree fragments and their behavior are discussed in the World Wide Web Consortium (W3C) specification, section 11.1 Result Tree Fragments through section 11.6 Passing Parameters to Templates. Also, section 1 Introduction discusses how templates can contain elements from the XSLT namespace that return or create result tree fragments.

A result tree fragment, in concept, behaves like a node set with nothing more than a single root node. However, the rest of the nodes returned are child nodes. To programmatically see the child nodes, copy the result tree fragment to the result tree using the <xsl:copy-of> element. When the copy-of is performed, all the child nodes are also copied to the result tree in sequence. Until a copy or copy-of is used, a result tree fragment is not part of the result tree or the output from the transformation.

To iterate over the returned nodes of a result tree fragment, an XPathNavigator is used. The following code sample shows how to create a result tree fragment within a style sheet by calling the function with a parameter fragment, which contains XML.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:user="https://www.adventure-works.com"
                version="1.0">
    <xsl:var name="fragment">
        <node1>
            <node2/>
        </node1>
    <xsl:var>

  <msxsl:script language="C#" implements-prefix="user">
    function NodeFragment(XPathNavigator nav)
    {
      if (nav.HasSelection == false)
        XPathNavigator.MoveToNext();
      return;
    }
  </msxsl:script>

    <xsl:template match="/">
            <xsl:value-of select="user:NodeFragment(msxml:node-set($fragment))"/>
    </xsl:template>
</xsl:stylesheet>

Here is another sample showing a variable, which is in Rich Text Format (RTF), and hence, a type of result tree fragment, that is not converted to a node set. Instead, it is passed to a script function, and the XPathNavigator is used to navigate over the nodes.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
        xmlns:user="urn:books"
        exclude-result-prefixes="msxsl">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

<xsl:variable name="node-fragment">
    <book>Book1</book>
    <book>Book2</book>
    <book>Book3</book>
    <book>Book4</book>
</xsl:variable>

<msxsl:script implements-prefix="user" language="c#">

<![CDATA[
    string func(XPathNavigator nav)
    {
        bool b = nav.MoveToFirstChild();
        if (b)
            return nav.Value;
        else
            return "Does not exist";
    }

]]>

</msxsl:script>

<xsl:template match="/">
    <first_book>
        <xsl:value-of select="user:func($node-fragment)"/>
    </first_book>
</xsl:template>

</xsl:stylesheet>

The result of transforming any XML with this style sheet is shown in the following output.

Output

<first_book xmlns:user="urn:books">Book1</first_book>

As stated above, the node-set function enables you to convert a result tree fragment into a node set. The resulting node always contains a single node that is the root node of the tree. If you convert a result tree fragment to a node set, then you can use it anywhere a regular node set is used, such as in a for-each statement or in the value of a select attribute. The following lines of code show the fragment being converted to a node set and used as a node set:

<xsl:for-each select="msxsl:node-set($node-fragment)">

<xsl:value-of select="user:func(msxsl:node-set($node-fragment))"/>

When a fragment is converted to a node set, you no longer use the XPathNavigator to navigate over it. For a node set, you use the XPathNodeIterator instead.

In the following example, $var is a variable that is a node tree in the style sheet. The for-each statement, combined with the node-set function, allows the user to iterate over this tree as a node set.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:user="https://www.adventure-works.com"
                version="1.0">
    <xsl:variable name="states">
        <node1>AL</node1>
        <node1>CA</node1>
        <node1>CO</node1>
        <node1>WA</node1>
    </xsl:variable>

    <xsl:template match="/">
            <xsl:for-each select="msxsl:node-set($states)"/>
    </xsl:template>
</xsl:stylesheet>

Here is another example of a variable that is in RTF, and hence of type result tree fragment, that is converted to a node set before being passed to a script function as XPathNodeIterator.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
        xmlns:user="urn:books"
        exclude-result-prefixes="msxsl">

<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

<xsl:variable name="node-fragment">
    <book>Book1</book>
    <book>Book2</book>
    <book>Book3</book>
    <book>Book4</book>
</xsl:variable>

<msxsl:script implements-prefix="user" language="c#">

<![CDATA[
    string func(XPathNodeIterator it)
    {
        it.MoveNext();
        return it.Current.Value;
        //it.Current returns XPathNavigator positioned on the current node
    }

]]>

</msxsl:script>
<xsl:template match="/">
    <books>
        <xsl:value-of select="user:func(msxsl:node-set($node-fragment))"/>
    </books>
</xsl:template>

</xsl:stylesheet>

The following is the result of transforming XML with this style sheet:

<books xmlns:user="urn:books">Book1Book2Book3Book4</books>

See also