KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > dom > DOMObjectModel


1 package net.sf.saxon.dom;
2
3 import net.sf.saxon.Configuration;
4 import net.sf.saxon.event.Receiver;
5 import net.sf.saxon.event.PipelineConfiguration;
6 import net.sf.saxon.expr.XPathContext;
7 import net.sf.saxon.om.*;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.trans.DynamicError;
10 import net.sf.saxon.value.SequenceExtent;
11 import net.sf.saxon.value.Value;
12 import org.w3c.dom.Document JavaDoc;
13 import org.w3c.dom.Node JavaDoc;
14 import org.w3c.dom.NodeList JavaDoc;
15
16 import javax.xml.transform.Result JavaDoc;
17 import javax.xml.transform.Source JavaDoc;
18 import javax.xml.transform.dom.DOMResult JavaDoc;
19 import javax.xml.transform.dom.DOMSource JavaDoc;
20 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
21 import javax.xml.parsers.DocumentBuilder JavaDoc;
22 import javax.xml.parsers.ParserConfigurationException JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.io.Serializable JavaDoc;
27
28 /**
29  * This interface must be implemented by any third-party object model that can
30  * be wrapped with a wrapper that implements the Saxon Object Model (the NodeInfo interface).
31  * This implementation of the interface supports wrapping of DOM Documents.
32  */

33
34 public class DOMObjectModel implements ExternalObjectModel, Serializable JavaDoc {
35
36     public DOMObjectModel() {}
37
38      /**
39      * Test whether this object model recognizes a given node as one of its own
40      */

41
42     public boolean isRecognizedNode(Object JavaDoc object) {
43          return object instanceof Node JavaDoc;
44     }
45
46     /**
47      * Test whether this object model recognizes a given class as representing a
48      * node in that object model. This method will generally be called at compile time.
49      *
50      * @param nodeClass A class that possibly represents nodes
51      * @return true if the class is used to represent nodes in this object model
52      */

53
54     public boolean isRecognizedNodeClass(Class JavaDoc nodeClass) {
55         return Node JavaDoc.class.isAssignableFrom(nodeClass);
56     }
57
58     /**
59      * Test whether this object model recognizes a given class as representing a
60      * list of nodes in that object model. This method will generally be called at compile time.
61      *
62      * @param nodeClass A class that possibly represents nodes
63      * @return true if the class is used to represent nodes in this object model
64      */

65
66     public boolean isRecognizedNodeListClass(Class JavaDoc nodeClass) {
67         return NodeList JavaDoc.class.isAssignableFrom(nodeClass);
68     }
69
70     /**
71      * Test whether this object model recognizes a particular kind of JAXP Result object,
72      * and if it does, return a Receiver that builds an instance of this data model from
73      * a sequence of events. If the Result is not recognised, return null.
74      */

75
76     public Receiver getDocumentBuilder(Result JavaDoc result) throws XPathException {
77         if (result instanceof DOMResult JavaDoc) {
78             DOMEmitter emitter = new DOMEmitter();
79             Node JavaDoc root = ((DOMResult JavaDoc)result).getNode();
80             if (root == null) {
81                 try {
82                     DocumentBuilderFactory JavaDoc dfactory = DocumentBuilderFactory.newInstance();
83                     DocumentBuilder JavaDoc docBuilder = dfactory.newDocumentBuilder();
84                     Document JavaDoc out = docBuilder.newDocument();
85                     ((DOMResult JavaDoc)result).setNode(out);
86                     emitter.setNode(out);
87                 } catch (ParserConfigurationException JavaDoc e) {
88                     throw new DynamicError(e);
89                 }
90             } else {
91                 emitter.setNode(root);
92             }
93             return emitter;
94         }
95         return null;
96     }
97
98     /**
99      * Test whether this object model recognizes a particular kind of JAXP Source object,
100      * and if it does, send the contents of the document to a supplied Receiver, and return true.
101      * Otherwise, return false
102      */

103
104     public boolean sendSource(Source JavaDoc source, Receiver receiver, PipelineConfiguration pipe) throws XPathException {
105         if (source instanceof DOMSource JavaDoc) {
106             Node JavaDoc startNode = ((DOMSource JavaDoc)source).getNode();
107             DOMSender driver = new DOMSender();
108             driver.setStartNode(startNode);
109             driver.setReceiver(receiver);
110             driver.setPipelineConfiguration(pipe);
111             driver.setSystemId(source.getSystemId());
112             driver.send();
113             return true;
114         }
115         return false;
116     }
117
118     /**
119      * Wrap or unwrap a node using this object model to return the corresponding Saxon node. If the supplied
120      * source does not belong to this object model, return null
121      */

122
123     public NodeInfo unravel(Source JavaDoc source, Configuration config) {
124
125         if (source instanceof DOMSource JavaDoc) {
126             NodeInfo start;
127             Node JavaDoc dsnode = ((DOMSource JavaDoc)source).getNode();
128             if (dsnode instanceof NodeOverNodeInfo) {
129                 // Supplied source is a DOM Node wrapping a Saxon node: unwrap it
130
start = ((NodeOverNodeInfo)dsnode).getUnderlyingNodeInfo();
131             } else {
132                 // Supplied source is an ordinary DOM Node: wrap it
133
Document JavaDoc dom;
134                 if (dsnode.getNodeType() == Node.DOCUMENT_NODE) {
135                     dom = (Document JavaDoc)dsnode;
136                 } else {
137                     dom = dsnode.getOwnerDocument();
138                 }
139                 DocumentWrapper docWrapper = new DocumentWrapper(dom, source.getSystemId(), config);
140                 start = docWrapper.wrap(dsnode);
141             }
142             return start;
143         }
144         return null;
145     }
146
147     /**
148      * Convert a Java object to an XPath value. If the supplied object is recognized as a representation
149      * of a value using this object model, the object model should convert the value to an XPath value
150      * and return this as the result. If not, it should return null. If the object is recognized but cannot
151      * be converted, an exception should be thrown
152      */

153
154     public Value convertObjectToXPathValue(Object JavaDoc object, Configuration config) throws XPathException {
155         if (object instanceof org.w3c.dom.NodeList JavaDoc) {
156             NodeList JavaDoc list = ((NodeList JavaDoc)object);
157             NodeInfo[] nodes = new NodeInfo[list.getLength()];
158             for (int i=0; i<list.getLength(); i++) {
159                 if (list.item(i) instanceof NodeOverNodeInfo) {
160                     nodes[i] = ((NodeOverNodeInfo)list.item(i)).getUnderlyingNodeInfo();
161                 } else {
162                     DocumentInfo doc = wrapDocument(list.item(i), "", config);
163                     NodeInfo node = wrapNode(doc, list.item(i));
164                     nodes[i] = node;
165                 }
166             }
167             return new SequenceExtent(nodes);
168
169             // Note, we accept the nodes in the order returned by the function; there
170
// is no requirement that this should be document order.
171
} else if (object instanceof NodeOverNodeInfo) {
172             return Value.asValue(((NodeOverNodeInfo)object).getUnderlyingNodeInfo());
173         } else {
174             return null;
175         }
176     }
177
178     /**
179      * Convert an XPath value to an object in this object model. If the supplied value can be converted
180      * to an object in this model, of the specified class, then the conversion should be done and the
181      * resulting object returned. If the value cannot be converted, the method should return null. Note
182      * that the supplied class might be a List, in which case the method should inspect the contents of the
183      * Value to see whether they belong to this object model.
184      * @throws XPathException if the target class is explicitly associated with this object model, but the
185      * supplied value cannot be converted to the appropriate class
186      */

187
188     public Object JavaDoc convertXPathValueToObject(Value value, Class JavaDoc target, XPathContext context) throws XPathException {
189         // We accept the object if (a) the target class is Node, Node[], or NodeList,
190
// or (b) the supplied object is a node, or sequence of nodes, that wrap DOM nodes,
191
// provided that the target class is Object or a collection class
192
boolean requireDOM =
193                 (Node JavaDoc.class.isAssignableFrom(target) || (target == NodeList JavaDoc.class) ||
194                 (target.isArray() && Node JavaDoc.class.isAssignableFrom(target.getComponentType())));
195
196         // Note: we allow the declared type of the method argument to be a subclass of Node. If the actual
197
// node supplied is the wrong kind of node, this will result in a Java exception.
198

199         boolean allowDOM =
200                 (target == Object JavaDoc.class || target.isAssignableFrom(ArrayList JavaDoc.class) ||
201                 target.isAssignableFrom(HashSet JavaDoc.class) ||
202                 (target.isArray() && target.getComponentType() == Object JavaDoc.class));
203         if (!(requireDOM || allowDOM)) {
204             return null;
205         }
206         List JavaDoc nodes = new ArrayList JavaDoc(20);
207
208         SequenceIterator iter = value.iterate(context);
209         while (true) {
210             Item item = iter.next();
211             if (item == null) {
212                 break;
213             }
214             if (item instanceof VirtualNode) {
215                 Object JavaDoc o = ((VirtualNode)item).getUnderlyingNode();
216                 if (o instanceof Node JavaDoc) {
217                     nodes.add(o);
218                 } else {
219                     if (requireDOM) {
220                         DynamicError err = new DynamicError("Extension function required class " + target.getName() +
221                                 "; supplied value of class " + item.getClass().getName() +
222                                 " could not be converted");
223                         throw err;
224                     };
225                 }
226             } else if (requireDOM) {
227                 if (item instanceof NodeInfo) {
228                     nodes.add(NodeOverNodeInfo.wrap((NodeInfo)item));
229                 } else {
230                     DynamicError err = new DynamicError("Extension function required class " + target.getName() +
231                                 "; supplied value of class " + item.getClass().getName() +
232                                 " could not be converted");
233                     throw err;
234                 }
235             } else {
236                 return null; // DOM Nodes are not actually required; let someone else try the conversion
237
}
238         }
239
240         if (nodes.size() == 0 && !requireDOM) {
241             return null; // empty sequence supplied - try a different mapping
242
}
243         if (Node JavaDoc.class.isAssignableFrom(target)) {
244             if (nodes.size() != 1) {
245                 DynamicError err = new DynamicError("Extension function requires a single DOM Node" +
246                                 "; supplied value contains " + nodes.size() + " nodes");
247                 throw err;
248             }
249             return nodes.get(0);
250             // could fail if the node is of the wrong kind
251
} else if (target == NodeList JavaDoc.class) {
252             return new DOMNodeList(nodes);
253         } else if (target.isArray() && target.getComponentType() == Node JavaDoc.class) {
254             Node JavaDoc[] array = new Node JavaDoc[nodes.size()];
255             nodes.toArray(array);
256             return array;
257         } else if (target.isAssignableFrom(ArrayList JavaDoc.class)) {
258             return nodes;
259         } else if (target.isAssignableFrom(HashSet JavaDoc.class)) {
260             return new HashSet JavaDoc(nodes);
261         } else {
262             // after all this work, give up
263
return null;
264         }
265     }
266
267     /**
268      * Wrap a document node in the external object model in a document wrapper that implements
269      * the Saxon DocumentInfo interface. (However, if the supplied object is a wrapper for a Saxon
270      * NodeInfo object, then we <i>unwrap</i> it.
271      * @param node a node (any node) in the third party document
272      * @param baseURI the base URI of the node (supply "" if unknown)
273      * @param config the Saxon configuration (which among other things provides access to the NamePool)
274      * @return the wrapper, which must implement DocumentInfo
275      */

276
277     public DocumentInfo wrapDocument(Object JavaDoc node, String JavaDoc baseURI, Configuration config) {
278         if (node instanceof DocumentOverNodeInfo) {
279             return (DocumentInfo)((DocumentOverNodeInfo)node).getUnderlyingNodeInfo();
280         }
281         if (node instanceof NodeOverNodeInfo) {
282             return ((NodeOverNodeInfo)node).getUnderlyingNodeInfo().getDocumentRoot();
283         }
284         if (node instanceof org.w3c.dom.Node JavaDoc) {
285             if (((Node JavaDoc)node).getNodeType() == Node.DOCUMENT_NODE) {
286                 Document JavaDoc doc = (org.w3c.dom.Document JavaDoc)node;
287                 return new DocumentWrapper(doc, baseURI, config);
288             } else {
289                 Document JavaDoc doc = ((org.w3c.dom.Node JavaDoc)node).getOwnerDocument();
290                 return new DocumentWrapper(doc, baseURI, config);
291             }
292         }
293         throw new IllegalArgumentException JavaDoc("Unknown node class " + node.getClass());
294     }
295
296     /**
297      * Wrap a node within the external object model in a node wrapper that implements the Saxon
298      * VirtualNode interface (which is an extension of NodeInfo)
299      * @param document the document wrapper, as a DocumentInfo object
300      * @param node the node to be wrapped. This must be a node within the document wrapped by the
301      * DocumentInfo provided in the first argument
302      * @return the wrapper for the node, as an instance of VirtualNode
303      */

304
305     public NodeInfo wrapNode(DocumentInfo document, Object JavaDoc node) {
306         return ((DocumentWrapper)document).wrap((Node JavaDoc)node);
307     }
308
309     /**
310      * Convert a sequence of values to a NODELIST, as defined in the JAXP XPath API spec. This method
311      * is used when the evaluate() request specifies the return type as NODELIST, regardless of the
312      * actual results of the expression. If the sequence contains things other than nodes, the fallback
313      * is to return the sequence as a Java List object. The method can return null to invoke fallback
314      * behaviour.
315      */

316
317     public Object JavaDoc convertToNodeList(SequenceExtent extent) {
318         try {
319             NodeList JavaDoc nodeList = DOMNodeList.checkAndMake(extent);
320             return nodeList;
321         } catch (XPathException e) {
322             return null;
323         }
324     }
325 }
326
327
328 //
329
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
330
// you may not use this file except in compliance with the License. You may obtain a copy of the
331
// License at http://www.mozilla.org/MPL/
332
//
333
// Software distributed under the License is distributed on an "AS IS" basis,
334
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
335
// See the License for the specific language governing rights and limitations under the License.
336
//
337
// The Original Code is: all this file.
338
//
339
// The Initial Developer of the Original Code is Michael H. Kay.
340
//
341
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
342
//
343
// Contributor(s): Gunther Schadow (changes to allow access to public fields; also wrapping
344
// of extensions and mapping of null to empty sequence).
345
//
346
Popular Tags