My first response is that I don't think I would do this: XSLT and XQuery are much better languages than Java for transforming nodes.
 
There are many implementations of NodeInfo, and it rather depends whether you want your code to work with all implementations, or only with certain specific implementations.
 
In general you can't modify a NodeInfo in-situ. (You can with some implementations, but not all. And it's not recommended even when you can - extension functions with side-effects can cause all manner of problems.) So I assume you're talking about producing a modified copy.
 
If so, you get a free choice what NodeInfo implementation to use for the new copy. You could choose, for example, to use a Saxon NodeWrapper around a XOM node. (Or DOM or JDOM or DOM4J, choose your poison.) You can then construct the new node using the XOM (etc) APIs, and wrap it in the appropriate kind of NodeWrapper before returning it to Saxon.
 
If you want to use the Saxon TinyTree implementation to construct the new node, the way to do it is to instantiate a TinyBuilder() and then feed it with SAX-like events such as startElement, namespace, attribute, characters, endElement; you can then get the constructed node from the builder and pass it back to Saxon. TinyBuilder implements the SAX-like Receiver interface on which these events are defined. NodeInfo has a copy() method that allows you to send the events representing the node to a Receiver, so you can construct a mini-pipeline in which you call copy() on the NodeInfo to send events first to your own implementation of Receiver. This can be written as a subclass of ProxyReceiver in which the only method you override is charaters() to modify the text node; your ProxyReceiver then passes on the events to the TinyBuilder to construct the new, modified, tree.
 
An alternative approach is to write your own implemention of NodeInfo as a wrapper around the original supplied node. All requests on the new (wrapper) node are then simply delegated to the original node, except a request for the string value, which is intercepted.
 
But all of this is a lot of work, and I really wonder why you want to do it in Java. There are much better languages for the job!
 
Michael Kay
http://www.saxonica.com/


From: saxon-help-admin@lists.sourceforge.net [mailto:saxon-help-admin@lists.sourceforge.net] On Behalf Of Feremans Len
Sent: 20 April 2006 13:42
To: saxon-help@lists.sourceforge.net
Subject: [saxon] extention functions: how do I return a modified node?

hi,

I want to write a saxon8 extension function that returns modified nodes.

The method must look something like:

public static NodeInfo setText(NodeInfo node) {

        //make copy of node and all its children, but set text value to something else

        return copy;

}

A NodeInfo node has not got any setters, so it's not possible to change a node.

I unsuccessfully tried finding a way to convert a converting the NodeInfo node to a DOM node, then modifying using DOM, then trying to convert to DOM node back again. Any help would be really appreciated!

For information: I successfully can return a text node using the following class:

public class MyTextNode extends net.sf.saxon.tree.NodeImpl

        {

                private String txt;

       

                public MyTextNode(String txt)

                {

                        this.txt =3D txt;=20

                }

       

                public void copy(Receiver arg0, int arg1, boolean arg2, int arg3) throws XPathException {

                        throw new RuntimeException("unsupported operation!");

                }

       

                public int getNodeKind() {

                        return Node.TEXT_NODE;

                }

       

                public String getStringValue() {

                        return txt;

                }

        }

returning from the above function new MyTextNode("blabla") return a text node, but I want to return a copy of the modified node returned so this code can not help me in achieving my current goal.

With friendly greetings,

Len Feremans