Re: Xalan: result tree fragments / node-set

Subject: Re: Xalan: result tree fragments / node-set
From: Gary L Peskin <garyp@xxxxxxxxxxxx>
Date: Thu, 13 Jul 2000 02:02:35 -0700
The following code seems to work, although I believe it's partially due
to a bug in Xalan.  I'll look into in more carefully tomorrow and come
up with a solution that will also work when Xalan is fixed.

------------------------------ start of code
------------------------------
package org.apache.xalan.xslt.extensions;

import org.w3c.dom.*;
import org.apache.xalan.xslt.ResultTreeFrag;
import org.apache.xalan.xpath.MutableNodeListImpl;

public class Nodeset
{
  /**
   */

  public NodeList nodeset(Node rtf) {

    DocumentFragment cloneFrag;
    DocumentFragment retFrag;
    NodeList fragElementList;
    int i;

    if (rtf instanceof DocumentFragment) {
      cloneFrag = (DocumentFragment) rtf.cloneNode(true);
      fragElementList = cloneFrag.getChildNodes();
      retFrag = cloneFrag.getOwnerDocument().createDocumentFragment();
      for (i = 0; i < fragElementList.getLength(); i++)
        retFrag.appendChild(fragElementList.item(i));
    }
    else {
      retFrag = rtf.getOwnerDocument().createDocumentFragment();
      retFrag.appendChild(rtf.cloneNode(true));
    }

    return new org.apache.xalan.xpath.XNodeSet(retFrag).nodeset();
  }                    
}
------------------------------ end of code
------------------------------

To use the code, make your xsl:stylesheet element look like this:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
               
xmlns:mynodeset="org.apache.xalan.xslt.extensions.Nodeset"
                extension-element-prefixes="mynodeset"
                version="1.0">

To invoke the nodeset function, see the following example provided by
Juergen Hermann in early posts:

XML:
<?xml version="1.0"?>
<root/>

XSL:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
               
xmlns:mynodeset="org.apache.xalan.xslt.extensions.Nodeset"
                extension-element-prefixes="mynodeset"
                version="1.0">
  <xsl:output method="xml"/>

  <xsl:variable name="greeting">abc<h1>Hello,
World!</h1>def<xsl:variable>

  <xsl:template match="root">
    Hello, World!
    <xsl:for-each select="mynodeset:nodeset($greeting)">*<xsl:copy-of
select="."/>*
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Expected Output:
    Hello, World!
    *abc<h1>Hello, World!</h1>def*

This conforms with the definition of nodeset (note the absence of a
hyphen between node and set) given by Mike Kay in his excellent book. 
The function takes a result tree fragment (RTF) as an argument and
returns a node-set consisting of a single node that operates as if it
was a root node.  The children of the RTF are children of the node
returned by this function.  As Mike points out, this is not, in general,
a well-formed document since the children of the resulting node need not
follow the rules for children of a document node.

Along the way, I've stumbled across the following observations:
1.  I can't write the function in java and call the function "node-set"
like xt and saxon because the function has to be the name of a java
method and a hyphen is not allowed as the name of a java method.  This
should be fixed to delete the hyphen if required by the language, I
think.
2.  Xalan improperly fails to reject the <xsl:copy-of select="."/> when
the "node" is an RTF.  I don't think you could get this problem working
purely in XSLT but an earlier version of my extension function returned
a purported nodeset consisting of a single RTF node (actually of type
ResultTreeFrag) and the copy-of statement did not complain as it should
have.  I think this is why my function actually works when it shouldn't.
3.  Perhaps the extension mechanism needs to be refined.  If I'm writing
my extensions in java, it is truly a pain to come up with a new
namespace for each java class (ie each extension) unless I just put
everything in one class.  Perhaps the Xalan extensions (which might
someday include node[-]set) should just be in one class.  Of course,
looking at Redirect, we have instance variables there and it seems silly
to have to instantiate them for every extension.  Obviously, I haven't
thought this out and I haven't looked at BSF but I also don't like
having ten different namespaces for ten different extensions.

Paul, although I'm new to XSLT and Xalan, I've been programming for
quite some time.  I'd like to participate in the development effort in
any way that would be helpful.  I've read the xml.apache.org Get
Involved! page and pages linked to that.  What do I do next?

Gary


Paul_Dick@xxxxxxxxx wrote:
> 
> Sukuma asks:
>   could anyone of the Xalan users drop a few lines of code or give me a
>   hint how to further process result tree fragments with Xalan?
>   I'm looking for an equivalent method to xt:node-set()?
> 
> This function is begging to be written.  Currently Xalan implements section
> 11.1 of the spec and that's all.  If you're interested, please contribute.
> I
> know several people have been asking about it.
> 
> Paul


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread