KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.dom;
2 import net.sf.saxon.functions.DeepEqual;
3 import net.sf.saxon.om.*;
4 import net.sf.saxon.pattern.NodeKindTest;
5 import net.sf.saxon.sort.AtomicComparer;
6 import net.sf.saxon.sort.CodepointCollator;
7 import net.sf.saxon.style.StandardNames;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.Type;
10 import org.w3c.dom.*;
11
12 import java.util.ArrayList JavaDoc;
13 import java.util.List JavaDoc;
14
15
16 /**
17   * This class implements the DOM Node interface as a wrapper around a Saxon NodeInfo object
18   */

19
20 public abstract class NodeOverNodeInfo implements Node {
21
22     protected NodeInfo node;
23
24     public NodeInfo getUnderlyingNodeInfo() {
25         return node;
26     }
27
28     public void setUnderlyingNodeInfo(NodeInfo node) {
29         this.node = node;
30     }
31
32     public static NodeOverNodeInfo wrap(NodeInfo node) {
33         NodeOverNodeInfo n = null;
34         if (node == null) {
35             return null;
36         }
37         switch (node.getNodeKind()) {
38             case Type.DOCUMENT:
39                 n = new DocumentOverNodeInfo();
40                 break;
41             case Type.ELEMENT:
42                 n = new ElementOverNodeInfo();
43                 break;
44             case Type.ATTRIBUTE:
45                 n = new AttrOverNodeInfo();
46                 break;
47             case Type.TEXT:
48             case Type.COMMENT:
49                 n = new TextOverNodeInfo();
50                 break;
51             case Type.PROCESSING_INSTRUCTION:
52                 n = new PIOverNodeInfo();
53                 break;
54             case Type.NAMESPACE:
55                 throw new IllegalArgumentException JavaDoc("Cannot wrap a namespace node as a DOM Node");
56         }
57         n.node = node;
58         return n;
59     }
60
61
62     /**
63     * Determine whether this is the same node as another node. DOM Level 3 method.
64     * @return true if this Node object and the supplied Node object represent the
65     * same node in the tree.
66     */

67
68     public final boolean isSameNode(Node other) {
69         if (other instanceof NodeOverNodeInfo) {
70             return node.isSameNodeInfo(((NodeOverNodeInfo)other).node);
71         } else {
72             return false;
73         }
74     }
75
76     /**
77     * Get the base URI for the node. Default implementation for child nodes gets
78     * the base URI of the parent node.
79     */

80
81     public String JavaDoc getBaseURI() {
82         return node.getBaseURI();
83     }
84
85     /**
86     * Get the name of this node, following the DOM rules
87     * @return The name of the node. For an element this is the element name, for an attribute
88     * it is the attribute name, as a QName. Other node types return conventional names such
89     * as "#text" or "#comment"
90     */

91
92     public String JavaDoc getNodeName() {
93         switch (node.getNodeKind()) {
94             case Type.DOCUMENT:
95                 return "#document";
96             case Type.ELEMENT:
97                 return node.getDisplayName();
98             case Type.ATTRIBUTE:
99                 return node.getDisplayName();
100             case Type.TEXT:
101                 return "#text";
102             case Type.COMMENT:
103                 return "#comment";
104             case Type.PROCESSING_INSTRUCTION:
105                 return node.getLocalPart();
106             case Type.NAMESPACE:
107                 return node.getLocalPart();
108             default:
109                 return "#unknown";
110        }
111     }
112
113     /**
114     * Get the local name of this node, following the DOM rules
115     * @return The local name of the node. For an element this is the element name, for an attribute
116     * it is the attribute name, as a QName. Other node types return conventional names such
117     * as "#text" or "#comment"
118     */

119
120     public String JavaDoc getLocalName() {
121         switch (node.getNodeKind()) {
122             case Type.ELEMENT:
123             case Type.ATTRIBUTE:
124                 return node.getLocalPart();
125             case Type.DOCUMENT:
126             case Type.TEXT:
127             case Type.COMMENT:
128             case Type.PROCESSING_INSTRUCTION:
129             case Type.NAMESPACE:
130             default:
131                 return null;
132        }
133     }
134
135     /**
136      * Determine whether this (attribute) node is an ID. This method is introduced
137      * in DOM Level 3. The current implementation is simplistic; it returns true if the
138      * type annotation of the node is xs:ID (subtypes not allowed).
139      */

140
141     public boolean isId() {
142         return (node.getTypeAnnotation() & NamePool.FP_MASK) == StandardNames.XS_ID;
143     }
144
145     /**
146     * Determine whether the node has any children.
147     * @return <code>true</code> if this node has any attributes,
148     * <code>false</code> otherwise.
149     */

150
151     public boolean hasChildNodes() {
152         return node.iterateAxis(Axis.CHILD).next() != null;
153     }
154
155     /**
156      * Returns whether this node has any attributes.
157      * @return <code>true</code> if this node has any attributes,
158      * <code>false</code> otherwise.
159      * @since DOM Level 2
160      */

161
162     public boolean hasAttributes() {
163         return node.iterateAxis(Axis.ATTRIBUTE).next() != null;
164     }
165
166     /**
167     * Get the type of this node (DOM method). Note, the numbers assigned to node kinds
168     * in Saxon (see module Type) are the same as those assigned in the DOM
169     */

170
171     public short getNodeType() {
172         return (short)node.getNodeKind();
173     }
174
175     /**
176      * Find the parent node of this node (DOM method).
177      * @return The Node object describing the containing element or root node.
178      */

179
180     public Node getParentNode() {
181         return wrap(node.getParent());
182     }
183
184     /**
185     * Get the previous sibling of the node (DOM method)
186     * @return The previous sibling node. Returns null if the current node is the first
187     * child of its parent.
188     */

189
190     public Node getPreviousSibling() {
191         return wrap((NodeInfo)node.iterateAxis(Axis.PRECEDING_SIBLING).next());
192     }
193
194    /**
195     * Get next sibling node (DOM method)
196     * @return The next sibling node. Returns null if the current node is the last
197     * child of its parent.
198     */

199
200     public Node getNextSibling() {
201         return wrap((NodeInfo)node.iterateAxis(Axis.FOLLOWING_SIBLING).next());
202     }
203
204     /**
205     * Get first child (DOM method)
206     * @return the first child node of this node, or null if it has no children
207     */

208
209     public Node getFirstChild() {
210         return wrap((NodeInfo)node.iterateAxis(Axis.CHILD).next());
211     }
212
213     /**
214     * Get last child (DOM method)
215     * @return last child of this node, or null if it has no children
216     */

217
218     public Node getLastChild() {
219         AxisIterator children = node.iterateAxis(Axis.CHILD);
220         NodeInfo last = null;
221         while (true) {
222             NodeInfo next = (NodeInfo)children.next();
223             if (next == null) {
224                 return wrap(last);
225             } else {
226                 last = next;
227             }
228         }
229     }
230
231
232     /**
233      * Get the outermost element. (DOM method)
234      * @return the Element for the outermost element of the document. If the document is
235      * not well-formed, this returns the first element child of the root if there is one, otherwise
236      * null.
237      */

238
239     public Element getDocumentElement() {
240         NodeInfo root = node.getDocumentRoot();
241         if (root==null) {
242             return null;
243         }
244         AxisIterator children =
245             root.iterateAxis(Axis.CHILD, NodeKindTest.ELEMENT);
246         return (Element)wrap((NodeInfo)children.next());
247     }
248
249
250     /**
251     * Get the node value as defined in the DOM.
252     * This is not necessarily the same as the XPath string-value.
253     */

254
255     public String JavaDoc getNodeValue() {
256         switch (node.getNodeKind()) {
257             case Type.DOCUMENT:
258             case Type.ELEMENT:
259                 return null;
260             case Type.ATTRIBUTE:
261             case Type.TEXT:
262             case Type.COMMENT:
263             case Type.PROCESSING_INSTRUCTION:
264             case Type.NAMESPACE:
265                 return node.getStringValue();
266             default:
267                 return null;
268         }
269     }
270
271     /**
272     * Set the node value. DOM method: always fails
273     */

274
275     public void setNodeValue(String JavaDoc nodeValue) throws DOMException {
276         disallowUpdate();
277     }
278
279     /**
280      * Return a <code>NodeList</code> that contains all children of this node. If
281      * there are no children, this is a <code>NodeList</code> containing no
282      * nodes. DOM Method.
283      */

284
285     public NodeList getChildNodes() {
286         try {
287             List JavaDoc nodes = new ArrayList JavaDoc(10);
288             SequenceIterator iter = node.iterateAxis(Axis.CHILD);
289             while (true) {
290                 NodeInfo node = (NodeInfo)iter.next();
291                 if (node == null) break;
292                 nodes.add(NodeOverNodeInfo.wrap(node));
293             }
294             return new DOMNodeList(nodes);
295         } catch (XPathException err) {
296             return null;
297             // can't happen
298
}
299     }
300
301     /**
302      * Return a <code>NamedNodeMap</code> containing the attributes of this node (if
303      * it is an <code>Element</code> ) or <code>null</code> otherwise. (DOM method)
304      */

305
306     public NamedNodeMap getAttributes() {
307         if (node.getNodeKind()==Type.ELEMENT) {
308             return new DOMAttributeMap(node);
309         } else {
310             return null;
311         }
312     }
313
314     /**
315      * Return the <code>Document</code> object associated with this node. (DOM method)
316      */

317
318     public Document getOwnerDocument() {
319         return (Document)wrap(node.getDocumentRoot());
320     }
321
322     /**
323      * Insert the node <code>newChild</code> before the existing child node
324      * <code>refChild</code>. DOM method: always fails.
325      * @param newChild The node to insert.
326      * @param refChild The reference node, i.e., the node before which the
327      * new node must be inserted.
328      * @return The node being inserted.
329      * @exception org.w3c.dom.DOMException
330      * NO_MODIFICATION_ALLOWED_ERR: Always raised.
331      */

332
333     public Node insertBefore(Node newChild,
334                              Node refChild)
335                              throws DOMException {
336         disallowUpdate();
337         return null;
338     }
339
340     /**
341      * Replace the child node <code>oldChild</code> with
342      * <code>newChild</code> in the list of children, and returns the
343      * <code>oldChild</code> node. Always fails.
344      * @param newChild The new node to put in the child list.
345      * @param oldChild The node being replaced in the list.
346      * @return The node replaced.
347      * @exception org.w3c.dom.DOMException
348      * NO_MODIFICATION_ALLOWED_ERR: Always raised.
349      */

350
351     public Node replaceChild(Node newChild,
352                              Node oldChild)
353                              throws DOMException{
354         disallowUpdate();
355         return null;
356     }
357
358     /**
359      * Remove the child node indicated by <code>oldChild</code> from the
360      * list of children, and returns it. DOM method: always fails.
361      * @param oldChild The node being removed.
362      * @return The node removed.
363      * @exception org.w3c.dom.DOMException
364      * NO_MODIFICATION_ALLOWED_ERR: Always raised.
365      */

366
367     public Node removeChild(Node oldChild) throws DOMException {
368         disallowUpdate();
369         return null;
370     }
371
372     /**
373      * Adds the node <code>newChild</code> to the end of the list of children
374      * of this node. DOM method: always fails.
375      * @param newChild The node to add.
376      * @return The node added.
377      * @exception org.w3c.dom.DOMException
378      * <br> NO_MODIFICATION_ALLOWED_ERR: Always raised.
379      */

380
381     public Node appendChild(Node newChild) throws DOMException {
382         disallowUpdate();
383         return null;
384     }
385
386     /**
387      * Returns a duplicate of this node, i.e., serves as a generic copy
388      * constructor for nodes. The duplicate node has no parent. Not
389      * implemented: always returns null. (Because trees are read-only, there
390      * would be no way of using the resulting node.)
391      * @param deep If <code>true</code> , recursively clone the subtree under
392      * the specified node; if <code>false</code> , clone only the node
393      * itself (and its attributes, if it is an <code>Element</code> ).
394      * @return The duplicate node.
395      */

396
397     public Node cloneNode(boolean deep) {
398         // Not implemented
399
return null;
400     }
401
402     /**
403      * Puts all <code>Text</code> nodes in the full depth of the sub-tree
404      * underneath this <code>Node</code>, including attribute nodes, into a
405      * "normal" form where only structure (e.g., elements, comments,
406      * processing instructions, CDATA sections, and entity references)
407      * separates <code>Text</code> nodes, i.e., there are neither adjacent
408      * <code>Text</code> nodes nor empty <code>Text</code> nodes.
409      * @since DOM Level 2
410      */

411
412     public void normalize() {
413         // null operation; nodes are always normalized
414
}
415
416     /**
417      * Tests whether the DOM implementation implements a specific feature and
418      * that feature is supported by this node.
419      * @param feature The name of the feature to test. This is the same name
420      * which can be passed to the method <code>hasFeature</code> on
421      * <code>DOMImplementation</code> .
422      * @param version This is the version number of the feature to test. In
423      * Level 2, version 1, this is the string "2.0". If the version is not
424      * specified, supporting any version of the feature will cause the
425      * method to return <code>true</code> .
426      * @return Returns <code>true</code> if the specified feature is supported
427      * on this node, <code>false</code> otherwise.
428      * @since DOM Level 2
429      */

430
431     public boolean isSupported(String JavaDoc feature,
432                                String JavaDoc version) {
433         return feature.equalsIgnoreCase("xml");
434     }
435
436     /**
437     * Alternative to isSupported(), defined in a draft DOM spec
438     */

439
440     public boolean supports(String JavaDoc feature,
441                                String JavaDoc version) {
442         return isSupported(feature, version);
443     }
444
445     /**
446      * The namespace URI of this node, or <code>null</code> if it is
447      * unspecified. DOM method.
448      * <br> This is not a computed value that is the result of a namespace
449      * lookup based on an examination of the namespace declarations in scope.
450      * It is merely the namespace URI given at creation time.
451      * <br> For nodes of any type other than <code>ELEMENT_NODE</code> and
452      * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1
453      * method, such as <code>createElement</code> from the
454      * <code>Document</code> interface, this is always <code>null</code> .
455      * Per the Namespaces in XML Specification an attribute does not
456      * inherit its namespace from the element it is attached to. If an
457      * attribute is not explicitly given a namespace, it simply has no
458      * namespace.
459      * @since DOM Level 2
460      */

461
462     public String JavaDoc getNamespaceURI() {
463         String JavaDoc uri = node.getURI();
464         return ("".equals(uri) ? null : uri);
465     }
466
467     /**
468      * The namespace prefix of this node, or <code>null</code> if it is
469      * unspecified.
470      * <br>For nodes of any type other than <code>ELEMENT_NODE</code> and
471      * <code>ATTRIBUTE_NODE</code> and nodes created with a DOM Level 1
472      * method, such as <code>createElement</code> from the
473      * <code>Document</code> interface, this is always <code>null</code>.
474      *
475      * @since DOM Level 2
476      */

477
478     public String JavaDoc getPrefix() {
479         String JavaDoc p = node.getNamePool().getPrefix(node.getNameCode());
480         return ("".equals(p) ? null : p);
481     }
482
483     /**
484     * Set the namespace prefix of this node. Always fails.
485     */

486
487     public void setPrefix(String JavaDoc prefix)
488                             throws DOMException {
489         disallowUpdate();
490     }
491
492     /**
493      * Compare the position of the (other) node in document order with the reference node (this node).
494      * DOM Level 3 method.
495      * @param other the other node.
496      * @return -1 (this node is first), 0 (same node), +1 (other node is first)
497      * @throws org.w3c.dom.DOMException
498      */

499
500     public short compareDocumentPosition(Node other) throws DOMException {
501         final short DOCUMENT_POSITION_DISCONNECTED = 0x01;
502         final short DOCUMENT_POSITION_PRECEDING = 0x02;
503         final short DOCUMENT_POSITION_FOLLOWING = 0x04;
504         final short DOCUMENT_POSITION_CONTAINS = 0x08;
505         final short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
506         if (!(other instanceof NodeOverNodeInfo)) {
507             return DOCUMENT_POSITION_DISCONNECTED;
508         }
509         int c = node.compareOrder(((NodeOverNodeInfo)other).node);
510         if (c==0) {
511             return (short)0;
512         } else if (c==-1) {
513             short d = compareDocumentPosition(other.getParentNode());
514             short result = DOCUMENT_POSITION_FOLLOWING;
515             if (d==0 || (d&DOCUMENT_POSITION_CONTAINED_BY) != 0) {
516                 d |= DOCUMENT_POSITION_CONTAINED_BY;
517             }
518             return result;
519         } else if (c==+1) {
520             short d = ((NodeOverNodeInfo)getParentNode()).compareDocumentPosition(other);
521             short result = DOCUMENT_POSITION_PRECEDING;
522             if (d==0 || (d&DOCUMENT_POSITION_CONTAINS) != 0) {
523                 d |= DOCUMENT_POSITION_CONTAINS;
524             }
525             return result;
526         } else {
527             throw new AssertionError JavaDoc();
528         }
529     }
530
531     /**
532      * Get the text content of a node. This is a DOM Level 3 method. The definition
533      * is the same as the definition of the string value of a node in XPath, except
534      * in the case of document nodes.
535      * @return the string value of the node, or null in the case of document nodes.
536      * @throws org.w3c.dom.DOMException
537      */

538
539     public String JavaDoc getTextContent() throws DOMException {
540         if (node.getNodeKind() == Type.DOCUMENT) {
541             return null;
542         } else {
543             return node.getStringValue();
544         }
545     }
546
547     /**
548      * Set the text content of a node. DOM Level 3 method, not supported.
549      * @param textContent
550      * @throws org.w3c.dom.DOMException
551      */

552
553     public void setTextContent(String JavaDoc textContent) throws DOMException {
554         disallowUpdate();
555     }
556
557     /**
558      * Get the (first) prefix assigned to a specified namespace URI, or null
559      * if the namespace is not in scope. DOM Level 3 method.
560      * @param namespaceURI the namespace whose prefix is required
561      * @return the corresponding prefix
562      */

563
564     public String JavaDoc lookupPrefix(String JavaDoc namespaceURI){
565         AxisIterator iter = node.iterateAxis(Axis.NAMESPACE);
566         while (true) {
567             NodeInfo ns = (NodeInfo)iter.next();
568             if (ns==null) {
569                 return null;
570             }
571             if (ns.getStringValue().equals(namespaceURI)) {
572                 return ns.getLocalPart();
573             }
574         }
575     }
576
577     /**
578      * Test whether a particular namespace is the default namespace.
579      * DOM Level 3 method.
580      * @param namespaceURI the namespace to be tested
581      * @return true if this is the default namespace
582      */

583
584     public boolean isDefaultNamespace(String JavaDoc namespaceURI) {
585         return namespaceURI.equals(lookupNamespaceURI(""));
586     }
587
588     /**
589      * Find the URI corresponding to a given in-scope prefix
590      * @param prefix The namespace prefix whose namespace URI is required.
591      * @return the corresponding namespace URI, or null if the prefix is
592      * not declared.
593      */

594
595     public String JavaDoc lookupNamespaceURI(String JavaDoc prefix) {
596         AxisIterator iter = node.iterateAxis(Axis.NAMESPACE);
597         while (true) {
598             NodeInfo ns = (NodeInfo)iter.next();
599             if (ns==null) {
600                 return null;
601             }
602             if (ns.getLocalPart().equals(prefix)) {
603                 return ns.getStringValue();
604             }
605         }
606     }
607
608     /**
609      * Compare whether two nodes have the same content. This is a DOM Level 3 method; the implementation
610      * uses the same algorithm as the XPath deep-equals() function.
611      * @param arg The node to be compared. This must wrap a Saxon NodeInfo.
612      * @return true if the two nodes are deep-equal.
613      */

614
615     public boolean isEqualNode(Node arg) {
616         if (!(arg instanceof NodeOverNodeInfo)) {
617             throw new IllegalArgumentException JavaDoc("Other Node must wrap a Saxon NodeInfo");
618         }
619         return DeepEqual.deepEquals(
620                 SingletonIterator.makeIterator(node),
621                 SingletonIterator.makeIterator(((NodeOverNodeInfo)arg).node),
622                 new AtomicComparer(CodepointCollator.getInstance(), node.getConfiguration()),
623                 node.getConfiguration());
624     }
625
626     /**
627      * Get a feature of this node. DOM Level 3 method, always returns null.
628      * @param feature the required feature
629      * @param version the version of the required feature
630      * @return the value of the feature. Always null in this implementation
631      */

632
633     public Object JavaDoc getFeature(String JavaDoc feature, String JavaDoc version) {
634         return null;
635     }
636
637     /**
638      * Set user data. Always throws UnsupportedOperationException in this implementation
639      * @param key
640      * @param data
641      * @param handler
642      * @return This implementation always throws an exception
643      */

644
645     public Object JavaDoc setUserData(String JavaDoc key, Object JavaDoc data, UserDataHandler handler) {
646         disallowUpdate();
647         return null;
648     }
649
650     /**
651      * Get user data associated with this node. DOM Level 3 method, always returns
652      * null in this implementation
653      * @param key identifies the user data required
654      * @return always null in this implementation
655      */

656     public Object JavaDoc getUserData(String JavaDoc key) {
657         return null;
658     }
659
660     /**
661     * Internal method used to indicate that update operations are not allowed
662     */

663
664     protected static void disallowUpdate() throws DOMException {
665         throw new UnsupportedOperationException JavaDoc("The Saxon DOM cannot be updated");
666     }
667
668 }
669
670 //
671
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
672
// you may not use this file except in compliance with the License. You may obtain a copy of the
673
// License at http://www.mozilla.org/MPL/
674
//
675
// Software distributed under the License is distributed on an "AS IS" basis,
676
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
677
// See the License for the specific language governing rights and limitations under the License.
678
//
679
// The Original Code is: all this file.
680
//
681
// The Initial Developer of the Original Code is Michael H. Kay.
682
//
683
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
684
//
685
// Contributor(s): none.
686
//
687
Popular Tags