Export (0) Print
Expand All

Node Fragments in Transformations

Node 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 are 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 Qname in several ways. You can assign a default value to the parameter by returning content from the 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 a 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 W3C spec at http://www.w3.org/XSLT, 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 children 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="http://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 an RTF, and hence, a type of node 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 which 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="http://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 which is RTF, and hence of type node 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 result of transforming XML with this style sheet:

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

See Also

XSLT Transformations with the XslTransform Class | XslTransform Class Implements the XSLT Processor | XPathNodeIterator Class | XPathNodeIterator Members

Show:
© 2014 Microsoft