KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > tree > NodeImpl


1 package com.icl.saxon.tree;
2 import com.icl.saxon.om.NodeInfo;
3 import com.icl.saxon.om.DocumentInfo;
4 import com.icl.saxon.om.NamePool;
5 import com.icl.saxon.om.Axis;
6 import com.icl.saxon.pattern.NodeTest;
7 import com.icl.saxon.pattern.NameTest;
8 import com.icl.saxon.expr.NodeSetExtent;
9 import com.icl.saxon.om.AxisEnumeration;
10 import com.icl.saxon.om.SingletonEnumeration;
11 import com.icl.saxon.om.EmptyEnumeration;
12 import com.icl.saxon.om.AbstractNode;
13 import com.icl.saxon.expr.XPathException;
14 import com.icl.saxon.output.Outputter;
15
16 import org.w3c.dom.*;
17 import javax.xml.transform.SourceLocator JavaDoc;
18 import javax.xml.transform.TransformerException JavaDoc;
19
20
21 /**
22   * A node in the XML parse tree representing an XML element, character content, or attribute.<P>
23   * This is the top-level class in the implementation class hierarchy; it essentially contains
24   * all those methods that can be defined using other primitive methods, without direct access
25   * to data.
26   * @author <A HREF="mailto:mhkay@iclway.co.uk>Michael H. Kay</A>
27   */

28
29 abstract public class NodeImpl extends AbstractNode {
30     
31     protected static NodeInfo[] emptyArray = new NodeInfo[0];
32
33     protected ParentNodeImpl parent;
34     protected int index;
35
36     /**
37     * Set the system ID of this node. This method is provided so that a NodeInfo
38     * implements the javax.xml.transform.Source interface, allowing a node to be
39     * used directly as the Source of a transformation
40     */

41     
42     public void setSystemId(String JavaDoc uri) {
43         // overridden in DocumentImpl and ElementImpl
44
getParent().setSystemId(uri);
45     }
46
47     /**
48     * Determine whether this is the same node as another node
49     * @return true if this Node object and the supplied Node object represent the
50     * same node in the tree.
51     */

52
53     public boolean isSameNode(NodeInfo other) {
54         // default implementation: differs for attribute and namespace nodes
55
return this==other;
56     }
57
58     /**
59     * Get the nameCode of the node. This is used to locate the name in the NamePool
60     */

61     
62     public int getNameCode() {
63         // default implementation: return -1 for an unnamed node
64
return -1;
65     }
66
67     /**
68     * Get the fingerprint of the node. This is used to compare whether two nodes
69     * have equivalent names. Return -1 for a node with no name.
70     */

71     
72     public int getFingerprint() {
73         int nameCode = getNameCode();
74         if (nameCode==-1) return -1;
75         return nameCode & 0xfffff;
76     }
77
78     /**
79     * Get a character string that uniquely identifies this node within this document
80     * (The calling code will prepend a document identifier)
81     * @return a string.
82     */

83
84     public String JavaDoc generateId() {
85         return "" + NODE_LETTER[getNodeType()] +
86             getSequenceNumber();
87     }
88
89     /**
90     * Get the node corresponding to this javax.xml.transform.dom.DOMLocator
91     */

92
93     public Node getOriginatingNode() {
94         return this;
95     }
96
97     /**
98     * Get the system ID for the node. Default implementation for child nodes.
99     */

100
101     public String JavaDoc getSystemId() {
102         return parent.getSystemId();
103     }
104
105     /**
106     * Get the base URI for the node. Default implementation for child nodes.
107     */

108
109     public String JavaDoc getBaseURI() {
110         return parent.getBaseURI();
111     }
112
113     /**
114     * Get the node sequence number (in document order). Sequence numbers are monotonic but not
115     * consecutive. In the current implementation, parent nodes (elements and roots) have a zero
116     * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have
117     * the top word the same as their owner and the bottom half reflecting their relative position.
118     * This is the default implementation for child nodes.
119     */

120
121     protected long getSequenceNumber() {
122         NodeImpl prev = this;
123         for (int i=0;; i++) {
124             if (prev instanceof ParentNodeImpl) {
125                 return prev.getSequenceNumber() + 0x10000 + i;
126                 // note the 0x10000 is to leave room for namespace and attribute nodes.
127
}
128             prev = prev.getPreviousInDocument();
129         }
130         
131     }
132
133     /**
134     * Determine the relative position of this node and another node, in document order.
135     * The other node will always be in the same document.
136     * @param other The other node, whose position is to be compared with this node
137     * @return -1 if this node precedes the other node, +1 if it follows the other
138     * node, or 0 if they are the same node. (In this case, isSameNode() will always
139     * return true, and the two nodes will produce the same result for generateId())
140     */

141     
142     public final int compareOrder(NodeInfo other) {
143         long a = getSequenceNumber();
144         long b = ((NodeImpl)other).getSequenceNumber();
145         if (a<b) return -1;
146         if (a>b) return +1;
147         return 0;
148     }
149
150     /**
151     * Get the NamePool
152     */

153     
154     public NamePool getNamePool() {
155         return getDocumentRoot().getNamePool();
156     }
157
158     /**
159     * Get the prefix part of the name of this node. This is the name before the ":" if any.
160     * @return the prefix part of the name. For an unnamed node, return an empty string.
161     */

162
163     public String JavaDoc getPrefix() {
164         int nameCode = getNameCode();
165         if (nameCode == -1) return "";
166         if ((nameCode>>20 & 0xff) == 0) return "";
167         return getNamePool().getPrefix(nameCode);
168     }
169
170     /**
171     * Get the URI part of the name of this node. This is the URI corresponding to the
172     * prefix, or the URI of the default namespace if appropriate.
173     * @return The URI of the namespace of this node. For the default namespace, return an
174     * empty string. For an unnamed node, return null.
175     */

176
177     public String JavaDoc getURI() {
178         int nameCode = getNameCode();
179         if (nameCode == -1) return null;
180         return getNamePool().getURI(nameCode);
181     }
182
183     /**
184     * Get the name of this node, following the DOM rules
185     * @return The name of the node. For an element this is the element name, for an attribute
186     * it is the attribute name, as a QName. Other node types return conventional names such
187     * as "#text" or "#comment"
188     */

189
190     //public String getNodeName() {
191
// default implementation
192
// return getDisplayName();
193
//}
194

195     
196     /**
197     * Get the display name of this node. For elements and attributes this is [prefix:]localname.
198     * For unnamed nodes, it is an empty string.
199     * @return The display name of this node.
200     * For a node with no name, return an empty string.
201     */

202
203     public String JavaDoc getDisplayName() {
204         int nameCode = getNameCode();
205         if (nameCode == -1) return "";
206         return getNamePool().getDisplayName(nameCode);
207     }
208
209     /**
210     * Get the local name of this node.
211     * @return The local name of this node.
212     * For a node with no name, return an empty string.
213     */

214
215     public String JavaDoc getLocalName() {
216         int nameCode = getNameCode();
217         if (nameCode == -1) return "";
218         return getNamePool().getLocalName(nameCode);
219     }
220     
221     /**
222     * Get the line number of the node within its source document entity
223     */

224
225     public int getLineNumber() {
226         return parent.getLineNumber();
227     }
228
229     /**
230     * Get the column number of the node. This is not maintained, so
231     * return -1
232     */

233
234     //public int getColumnNumber() {
235
// return -1;
236
//}
237

238
239     /**
240     * Get the public identifier of the document entity containing this node. This
241     * is not currently maintained: return null
242     */

243
244     //public String getPublicId() {
245
// return null;
246
//}
247

248     /**
249      * Find the parent node of this node.
250      * @return The Node object describing the containing element or root node.
251      */

252
253     public final NodeInfo getParent() {
254         return parent;
255     }
256
257     /**
258      * Find the parent node of this node.
259      * @return The Node object describing the containing element or root node.
260      */

261
262     //public final Node getParentNode() {
263
// return parent;
264
//}
265

266     /**
267     * Get the previous sibling of the node
268     * @return The previous sibling node. Returns null if the current node is the first
269     * child of its parent.
270     */

271     
272     public Node getPreviousSibling() {
273         return parent.getNthChild(index-1);
274     }
275
276
277    /**
278     * Get next sibling node
279     * @return The next sibling node of the required type. Returns null if the current node is the last
280     * child of its parent.
281     */

282
283     public Node getNextSibling() {
284         return parent.getNthChild(index+1);
285     }
286
287     /**
288     * Get first child - default implementation used for leaf nodes
289     * @return null
290     */

291
292     public Node getFirstChild() {
293         return null;
294     }
295
296     /**
297     * Get last child - default implementation used for leaf nodes
298     * @return null
299     */

300
301     public Node getLastChild() {
302         return null;
303     }
304
305     /**
306     * Return an enumeration over the nodes reached by the given axis from this node
307     * @param node NodeInfo representing the node from which the enumeration starts
308     * @param nodeType the type(s) of node to be included, e.g. NodeInfo.ELEMENT, NodeInfo.TEXT.
309     * The value NodeInfo.NODE means include any type of node.
310     * @param nodeTest A pattern to be matched by the returned nodes
311     * @return an AxisEnumeration that scans the nodes reached by the axis in turn.
312     */

313
314     public AxisEnumeration getEnumeration(
315                                         byte axisNumber,
316                                         NodeTest nodeTest) {
317                                             
318         switch (axisNumber) {
319             case Axis.ANCESTOR:
320                  return new AncestorEnumeration(this, nodeTest, false);
321                  
322             case Axis.ANCESTOR_OR_SELF:
323                  return new AncestorEnumeration(this, nodeTest, true);
324                  
325             case Axis.ATTRIBUTE:
326                  if (this.getNodeType()!=ELEMENT) return EmptyEnumeration.getInstance();
327                  return new AttributeEnumeration(this, nodeTest);
328                  
329             case Axis.CHILD:
330                  if (this instanceof ParentNodeImpl) {
331                     return ((ParentNodeImpl)this).enumerateChildren(nodeTest);
332                  } else {
333                     return EmptyEnumeration.getInstance();
334                  }
335                  
336             case Axis.DESCENDANT:
337                 if (getNodeType()==ROOT &&
338                         nodeTest instanceof NameTest &&
339                         nodeTest.getNodeType()==ELEMENT) {
340                     return ((DocumentImpl)this).getAllElements(
341                                 ((NameTest)nodeTest).getFingerprint());
342                 } else if (hasChildNodes()) {
343                     return new DescendantEnumeration(this, nodeTest, false);
344                 } else {
345                     return EmptyEnumeration.getInstance();
346                 }
347                  
348             case Axis.DESCENDANT_OR_SELF:
349                  return new DescendantEnumeration(this, nodeTest, true);
350                  
351             case Axis.FOLLOWING:
352                  return new FollowingEnumeration(this, nodeTest);
353                  
354             case Axis.FOLLOWING_SIBLING:
355                  return new FollowingSiblingEnumeration(this, nodeTest);
356                  
357             case Axis.NAMESPACE:
358                  if (this.getNodeType()!=ELEMENT) return EmptyEnumeration.getInstance();
359                  return new NamespaceEnumeration(this, nodeTest);
360                     
361             case Axis.PARENT:
362                  NodeInfo parent = (NodeInfo)getParentNode();
363                  if (parent==null) return EmptyEnumeration.getInstance();
364                  if (nodeTest.matches(parent)) return new SingletonEnumeration(parent);
365                  return EmptyEnumeration.getInstance();
366                  
367             case Axis.PRECEDING:
368                  return new PrecedingEnumeration(this, nodeTest);
369                  
370             case Axis.PRECEDING_SIBLING:
371                  return new PrecedingSiblingEnumeration(this, nodeTest);
372                  
373             case Axis.SELF:
374                  if (nodeTest.matches(this)) return new SingletonEnumeration(this);
375                  return EmptyEnumeration.getInstance();
376                  
377             case Axis.PRECEDING_OR_ANCESTOR:
378                  return new PrecedingOrAncestorEnumeration(this, nodeTest);
379                  
380             default:
381                  throw new IllegalArgumentException JavaDoc("Unknown axis number " + axisNumber);
382         }
383     }
384
385     /**
386      * Returns whether this node (if it is an element) has any attributes.
387      * @return <code>true</code> if this node has any attributes,
388      * <code>false</code> otherwise.
389      * @since DOM Level 2
390      */

391     
392     public boolean hasAttributes() {
393         return false;
394     }
395     
396     /**
397      * Find the value of a given attribute of this node. <BR>
398      * This method is defined on all nodes to meet XSL requirements, but for nodes
399      * other than elements it will always return null.
400      * @param uri the namespace uri of an attribute
401      * @param localName the local name of an attribute
402      * @return the value of the attribute, if it exists, otherwise null
403      */

404
405     public String JavaDoc getAttributeValue( String JavaDoc uri, String JavaDoc localName ) {
406         return null;
407     }
408
409     /**
410      * Find the value of a given attribute of this node. <BR>
411      * This method is defined on all nodes to meet XSL requirements, but for nodes
412      * other than elements it will always return null.
413      * @param name the name of an attribute. This must be an unqualified attribute name,
414      * i.e. one with no namespace prefix.
415      * @return the value of the attribute, if it exists, otherwise null
416      */

417
418     //public String getAttributeValue( String name ) {
419
// return null;
420
//}
421

422     /**
423     * Get the value of a given attribute of this node
424     * @param fingerprint The fingerprint of the attribute name
425     * @return the attribute value if it exists or null if not
426     */

427     
428     public String JavaDoc getAttributeValue(int fingerprint) {
429         return null;
430     }
431
432     /**
433      * Get the outermost element.
434      * @return the Element node for the outermost element of the document. If the document is
435      * not well-formed, this returns the last element child of the root if there is one, otherwise
436      * null.
437      */

438      
439     public Element getDocumentElement() {
440         return ((DocumentImpl)getDocumentRoot()).getDocumentElement();
441
442     }
443
444     /**
445     * Get the root (document) node
446     * @return the DocumentInfo representing the containing document
447     */

448
449     public DocumentInfo getDocumentRoot() {
450         return getParent().getDocumentRoot();
451     }
452
453     /**
454     * Get the next node in document order
455     * @param anchor: the scan stops when it reaches a node that is not a descendant of the specified
456     * anchor node
457     * @return the next node in the document, or null if there is no such node
458     */

459
460     public NodeImpl getNextInDocument(NodeImpl anchor) {
461         // find the first child node if there is one; otherwise the next sibling node
462
// if there is one; otherwise the next sibling of the parent, grandparent, etc, up to the anchor element.
463
// If this yields no result, return null.
464

465         NodeImpl next = (NodeImpl)getFirstChild();
466         if (next!=null) return next;
467         if (this==anchor) return null;
468         next = (NodeImpl)getNextSibling();
469         if (next!=null) return next;
470         NodeImpl parent = this;
471         while (true) {
472             parent = (NodeImpl)parent.getParent();
473             if (parent==null) return null;
474             if (parent==anchor) return null;
475             next = (NodeImpl)parent.getNextSibling();
476             if (next!=null) return next;
477         }
478     }
479
480
481     /**
482     * Get the previous node in document order
483     * @return the previous node in the document, or null if there is no such node
484     */

485
486     public NodeImpl getPreviousInDocument() {
487
488         // finds the last child of the previous sibling if there is one;
489
// otherwise the previous sibling element if there is one;
490
// otherwise the parent, up to the anchor element.
491
// If this reaches the document root, return null.
492

493         NodeImpl prev = (NodeImpl)getPreviousSibling();
494         if (prev!=null) {
495             return ((NodeImpl)prev).getLastDescendantOrSelf();
496         }
497         return (NodeImpl)getParentNode();
498     }
499
500     private NodeImpl getLastDescendantOrSelf() {
501         NodeImpl last = (NodeImpl)getLastChild();
502         if (last==null) return this;
503         return last.getLastDescendantOrSelf();
504     }
505
506     /**
507     * Output all namespace nodes associated with this element. Does nothing if
508     * the node is not an element.
509     * @param out The relevant outputter
510     * @param includeAncestors True if namespaces declared on ancestor elements must
511     * be output; false if it is known that these are already on the result tree
512     */

513
514     public void outputNamespaceNodes(Outputter out, boolean includeAncestors)
515         throws TransformerException JavaDoc
516     {}
517
518     /**
519     * Remove this node from the tree. For system use only.
520     * When one or more nodes have been removed, renumberChildren()
521     * must be called to adjust the numbering of remaining nodes.
522     * PRECONDITION: The node must have a parent node.
523     */

524
525     public void removeNode() {
526         parent.removeChild(index);
527     }
528
529
530     // implement DOM Node methods
531

532     /**
533     * Get the node value as defined in the DOM. This is not the same as the XPath string-value.
534     */

535
536     //public String getNodeValue() {
537
// default implementation
538
// return getStringValue();
539
//}
540

541     /**
542      * Return a <code>NodeList</code> that contains all children of this node. If
543      * there are no children, this is a <code>NodeList</code> containing no
544      * nodes.
545      */

546      
547     public NodeList getChildNodes() {
548         try {
549             return new NodeSetExtent(EmptyEnumeration.getInstance(), null);
550         } catch (XPathException err) {
551             return null;
552         }
553     }
554
555     /**
556      * Return a <code>NamedNodeMap</code> containing the attributes of this node (if
557      * it is an <code>Element</code> ) or <code>null</code> otherwise. (DOM method)
558      */

559      
560     public NamedNodeMap getAttributes() {
561         // default implementation
562
return null;
563     }
564
565
566   
567     /**
568      * Determine whether the node has any children.
569      * @return <code>true</code> if the node has any children,
570      * <code>false</code> if the node has no children.
571      */

572      
573     public boolean hasChildNodes() {
574         return getFirstChild() != null;
575     }
576
577 }
578
579 //
580
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
581
// you may not use this file except in compliance with the License. You may obtain a copy of the
582
// License at http://www.mozilla.org/MPL/
583
//
584
// Software distributed under the License is distributed on an "AS IS" basis,
585
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
586
// See the License for the specific language governing rights and limitations under the License.
587
//
588
// The Original Code is: all this file.
589
//
590
// The Initial Developer of the Original Code is
591
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
592
//
593
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
594
//
595
// Contributor(s): none.
596
//
597
Popular Tags