web analytics

msxsl:node-set() Function

Options

codeling 1599 - 6654
@2016-12-17 19:49:29

The msxsl:node-set function enables you to convert a result tree fragment into a node set. The resulting node set always contains a single node and is the root node of the tree.

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 node tree as a node set.

nodeset.xsl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                version="1.0">
    <xsl:variable name="books">
        <book author="Michael Howard">Writing Secure Code</book>
        <book author="Michael Kay">XSLT Reference</book>
    </xsl:variable>

    <xsl:template match="/">
        <authors>
            <xsl:for-each select="msxsl:node-set($books)/book">
                <author><xsl:value-of select="@author"/)</author>
            </xsl:for-each>
        </authors>
    </xsl:template>
</xsl:stylesheet>

The output of the transformation is

<?xml version="1.0" encoding="utf-8"?>
<authors><author>Michael Howard</author><author>Michael Kay</author></authors>

 

@2016-12-17 21:13:39

A result tree fragment is a special type of node-set. It is created by the xsl:variable or xsl:param instruction, but only when the xsl:variable or xsl:param element has content. Thus,

  <xsl:variable name="a">foo</xsl:variable>
  <xsl:variable name="b">
    <asdf/>
  </xsl:variable>


both create RTFs, while

  <xsl:variable name="c" select="1"/>
  <xsl:variable name="d" select="'hello world'"/>
  <xsl:param name="e"/>


do not. ($c is a number, $d a string, $e an empty string)

A result tree fragment is actually not the set of all nodes created in the variable binding element's content. It's just one root node. For example:

  <xsl:variable name="myRtf">
    <elem/>
    <elem>hello</elem>
  </xsl:variable>


The code above creates a result tree fragment and binds it to the variable myRtf, so XPath expressions can now refer to $myRtf when they want to use the
fragment. The fragment consists of 1 root node. That node has 2 'elem' element nodes as children, and one of those has a 'hello' text node as its child.

 

@2016-12-17 21:25:18

When you use an XML fragment to initialize a variable or a parameter, then the variable or parameter is of the "result tree fragment" datatype. This is an XSLT 1.0 specific datatype [just like node-set, but slightly different].

A result tree fragment is equivalent to a node-set that contains just the root node. But you cannot apply operators like "/", "//" or predicate on a result tree fragments. They are only applicable for node-set datatypes.

Typically,when you perform a "select" in XSLT, what you get is a node-set. For instance, 

  <xsl:variable name="countryNames" select="/Countries/Country"/>

means that the variable countryNames contains a node-set of "Country" nodes. You can apply operators like "/" on this variable, for instance 

  <xsl:for-each select="$countryNames/@name">
    . . . 
  </xsl:for-each>

But you cannot perform this kind of an operation on a result tree fragment.

There are two ways to solve this issue.

a) In XSLT 1.0

The resolution of this is to convert the result tree fragment into a node-set. I am not aware of any oracle specific xpath extension functions that can do this trick for you. You could use MSXSL to achieve this.

MSXSL provides some very useful extensions to XSLT.They have defined an extension function node-set() that converts result tree fragments into node-sets.

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p1="http://example.org"
xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:param name="param1">
  <FileList>
    <File Name='a' valid='true' automated='false'/>
    <File Name='b' valid='true' automated='false'/>
    <File Name='c' valid='true' automated='false'/>
    <File Name='d' valid='true' automated='false'/>
    <File Name='e' valid='true' automated='false'/>
    <File Name='f' valid='true' automated='false'/>
  </FileList>
</xsl:param>
<xsl:template match="/">
  <ExternalAccess>
    <Query>
        <Parameters>
            <xsl:for-each select="msxsl:node-set($param1)/FileList/File">
                <xsl:variable name="secondary" select="."/>
                <RetrievedFile>
                    <xsl:attribute name="Name">
                        <xsl:value-of select='@Name'/>
                    </xsl:attribute>
                    <xsl:attribute name="valid">
                        <xsl:value-of select='@valid'/>
                    </xsl:attribute>
                    <xsl:attribute name="automated">
                        <xsl:value-of select='@automated'/>
                    </xsl:attribute>
                </RetrievedFile>
            </xsl:for-each>
        </Parameters>
    </Query>
  </ExternalAccess>
</xsl:template>

</xsl:stylesheet>

b) Use XSLT 2.0

You can code your transformations in XSLT 2.0.  XSLT 2.0 deprecates ResultTreeFragments i.e. if you are modeling an XSLT 2.0 transformation, and you create a variable or a parameter that holds a tree fragment, it is implicitly a node sequence. You could then use path expressions against these variables and parameters. To make your transformations executed by an XSLT 2.0 processor, simply change the "version" attribute on the &lt;xsl:stylesheet> to "2.0".

With this approach, you can use the select expression "$param1/FileList/File" to iterate over the File elements witihn the XSLT parameter.

Here is the XSLT 2.0 code for this approach.

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p1="www.example.org">
<xsl:param name="param1">
<FileList>
<File Name='a' valid='true' automated='false'/>
<File Name='b' valid='true' automated='false'/>
<File Name='c' valid='true' automated='false'/>
<File Name='d' valid='true' automated='false'/>
<File Name='e' valid='true' automated='false'/>
<File Name='f' valid='true' automated='false'/>
</FileList>
</xsl:param>
<xsl:template match="/">
<ExternalAccess>
      <Query>
            <Parameters>
                <xsl:for-each select="$param1/FileList/File">
                       <xsl:variable name="secondary" select="."/>
                               <RetrievedFile>
                                       <xsl:attribute name="Name">
                                           <xsl:value-of select='@Name'/>
                                       </xsl:attribute>
                                       <xsl:attribute name="valid">
                                           <xsl:value-of select='@valid'/>
                                       </xsl:attribute>
                                       <xsl:attribute name="automated">
                                           <xsl:value-of select='@automated'/>
                                       </xsl:attribute>
                                 </RetrievedFile>
                </xsl:for-each>
      </Parameters>
  </Query>
</ExternalAccess>
</xsl:template>
</xsl:stylesheet>

Comments

You must Sign In to comment on this topic.


© 2024 Digcode.com