KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > tree > NodeImpl


1 package net.sf.saxon.tree;
2
3 import net.sf.saxon.Configuration;
4 import net.sf.saxon.event.Receiver;
5 import net.sf.saxon.om.*;
6 import net.sf.saxon.pattern.AnyNodeTest;
7 import net.sf.saxon.pattern.NameTest;
8 import net.sf.saxon.pattern.NodeTest;
9 import net.sf.saxon.trans.XPathException;
10 import net.sf.saxon.type.Type;
11 import net.sf.saxon.value.UntypedAtomicValue;
12 import net.sf.saxon.value.Value;
13
14 import javax.xml.transform.SourceLocator JavaDoc;
15
16
17 /**
18  * A node in the XML parse tree representing an XML element, character content, or attribute.<P>
19  * This is the top-level class in the implementation class hierarchy; it essentially contains
20  * all those methods that can be defined using other primitive methods, without direct access
21  * to data.
22  *
23  * @author Michael H. Kay
24  */

25
26 public abstract class NodeImpl implements NodeInfo, FingerprintedNode, SourceLocator JavaDoc {
27
28     protected ParentNodeImpl parent;
29     protected int index;
30     /**
31      * Chararacteristic letters to identify each type of node, indexed using the node type
32      * values. These are used as the initial letter of the result of generate-id()
33      */

34
35     public static final char[] NODE_LETTER =
36             {'x', 'e', 'a', 't', 'x', 'x', 'x', 'p', 'c', 'r', 'x', 'x', 'x', 'n'};
37
38     /**
39      * Get the value of the item as a CharSequence. This is in some cases more efficient than
40      * the version of the method that returns a String.
41      */

42
43     public CharSequence JavaDoc getStringValueCS() {
44         return getStringValue();
45     }
46
47     /**
48      * Get the type annotation of this node, if any
49      */

50
51     public int getTypeAnnotation() {
52         return -1;
53     }
54
55     /**
56      * Get the column number of the node.
57      * The default implementation returns -1, meaning unknown
58      */

59
60     public int getColumnNumber() {
61         return -1;
62     }
63
64     /**
65      * Get the public identifier of the document entity containing this node.
66      * The default implementation returns null, meaning unknown
67      */

68
69     public String JavaDoc getPublicId() {
70         return null;
71     }
72
73
74     /**
75      * Get the document number of the document containing this node. For a free-standing
76      * orphan node, just return the hashcode.
77      */

78
79     public int getDocumentNumber() {
80         return getRoot().getDocumentNumber();
81     }
82
83     /**
84      * Get the typed value of this node.
85      * If there is no type annotation, we return the string value, as an instance
86      * of xdt:untypedAtomic
87      */

88
89     public SequenceIterator getTypedValue() throws XPathException {
90         return SingletonIterator.makeIterator(new UntypedAtomicValue(getStringValue()));
91     }
92
93     /**
94      * Get the typed value. The result of this method will always be consistent with the method
95      * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be
96      * more efficient, especially in the common case where the value is expected to be a singleton.
97      *
98      * @return the typed value. If requireSingleton is set to true, the result will always be an
99      * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
100      * values.
101      * @since 8.5
102      */

103
104     public Value atomize() throws XPathException {
105         return new UntypedAtomicValue(getStringValue());
106     }
107
108     /**
109      * Set the system ID of this node. This method is provided so that a NodeInfo
110      * implements the javax.xml.transform.Source interface, allowing a node to be
111      * used directly as the Source of a transformation
112      */

113
114     public void setSystemId(String JavaDoc uri) {
115         // overridden in DocumentImpl and ElementImpl
116
getParent().setSystemId(uri);
117     }
118
119     /**
120      * Determine whether this is the same node as another node
121      *
122      * @return true if this Node object and the supplied Node object represent the
123      * same node in the tree.
124      */

125
126     public boolean isSameNodeInfo(NodeInfo other) {
127         // default implementation: differs for attribute and namespace nodes
128
return this == other;
129     }
130
131     /**
132      * Get the nameCode of the node. This is used to locate the name in the NamePool
133      */

134
135     public int getNameCode() {
136         // default implementation: return -1 for an unnamed node
137
return -1;
138     }
139
140     /**
141      * Get the fingerprint of the node. This is used to compare whether two nodes
142      * have equivalent names. Return -1 for a node with no name.
143      */

144
145     public int getFingerprint() {
146         int nameCode = getNameCode();
147         if (nameCode == -1) {
148             return -1;
149         }
150         return nameCode & 0xfffff;
151     }
152
153     /**
154      * Get a character string that uniquely identifies this node within this document
155      * (The calling code will prepend a document identifier)
156      *
157      * @return a string.
158      */

159
160     public String JavaDoc generateId() {
161         return getDocumentRoot().generateId() + NODE_LETTER[getNodeKind()] +
162                 getSequenceNumber();
163     }
164
165     /**
166      * Get the system ID for the node. Default implementation for child nodes.
167      */

168
169     public String JavaDoc getSystemId() {
170         return parent.getSystemId();
171     }
172
173     /**
174      * Get the base URI for the node. Default implementation for child nodes.
175      */

176
177     public String JavaDoc getBaseURI() {
178         return parent.getBaseURI();
179     }
180
181     /**
182      * Get the node sequence number (in document order). Sequence numbers are monotonic but not
183      * consecutive. In the current implementation, parent nodes (elements and roots) have a zero
184      * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have
185      * the top word the same as their owner and the bottom half reflecting their relative position.
186      * This is the default implementation for child nodes.
187      */

188
189     protected long getSequenceNumber() {
190         NodeImpl prev = this;
191         for (int i = 0; ; i++) {
192             if (prev instanceof ParentNodeImpl) {
193                 return prev.getSequenceNumber() + 0x10000 + i;
194                 // note the 0x10000 is to leave room for namespace and attribute nodes.
195
}
196             prev = prev.getPreviousInDocument();
197         }
198
199     }
200
201     /**
202      * Determine the relative position of this node and another node, in document order.
203      * The other node will always be in the same document.
204      *
205      * @param other The other node, whose position is to be compared with this node
206      * @return -1 if this node precedes the other node, +1 if it follows the other
207      * node, or 0 if they are the same node. (In this case, isSameNode() will always
208      * return true, and the two nodes will produce the same result for generateId())
209      */

210
211     public final int compareOrder(NodeInfo other) {
212         long a = getSequenceNumber();
213         long b = ((NodeImpl)other).getSequenceNumber();
214         if (a < b) {
215             return -1;
216         }
217         if (a > b) {
218             return +1;
219         }
220         return 0;
221     }
222
223     /**
224      * Get the configuration
225      */

226
227     public Configuration getConfiguration() {
228         return getDocumentRoot().getConfiguration();
229     }
230
231     /**
232      * Get the NamePool
233      */

234
235     public NamePool getNamePool() {
236         return getDocumentRoot().getNamePool();
237     }
238
239     /**
240      * Get the prefix part of the name of this node. This is the name before the ":" if any.
241      *
242      * @return the prefix part of the name. For an unnamed node, return an empty string.
243      */

244
245     public String JavaDoc getPrefix() {
246         int nameCode = getNameCode();
247         if (nameCode == -1) {
248             return "";
249         }
250         if ((nameCode >> 20 & 0xff) == 0) {
251             return "";
252         }
253         return getNamePool().getPrefix(nameCode);
254     }
255
256     /**
257      * Get the URI part of the name of this node. This is the URI corresponding to the
258      * prefix, or the URI of the default namespace if appropriate.
259      *
260      * @return The URI of the namespace of this node. For the default namespace, return an
261      * empty string. For an unnamed node, return the empty string.
262      */

263
264     public String JavaDoc getURI() {
265         int nameCode = getNameCode();
266         if (nameCode == -1) {
267             return "";
268         }
269         return getNamePool().getURI(nameCode);
270     }
271
272     /**
273      * Get the display name of this node. For elements and attributes this is [prefix:]localname.
274      * For unnamed nodes, it is an empty string.
275      *
276      * @return The display name of this node.
277      * For a node with no name, return an empty string.
278      */

279
280     public String JavaDoc getDisplayName() {
281         int nameCode = getNameCode();
282         if (nameCode == -1) {
283             return "";
284         }
285         return getNamePool().getDisplayName(nameCode);
286     }
287
288     /**
289      * Get the local name of this node.
290      *
291      * @return The local name of this node.
292      * For a node with no name, return "",.
293      */

294
295     public String JavaDoc getLocalPart() {
296         int nameCode = getNameCode();
297         if (nameCode == -1) {
298             return "";
299         }
300         return getNamePool().getLocalName(nameCode);
301     }
302
303     /**
304      * Get the line number of the node within its source document entity
305      */

306
307     public int getLineNumber() {
308         return parent.getLineNumber();
309     }
310
311     /**
312      * Find the parent node of this node.
313      *
314      * @return The Node object describing the containing element or root node.
315      */

316
317     public final NodeInfo getParent() {
318         return parent;
319     }
320
321     /**
322      * Get the previous sibling of the node
323      *
324      * @return The previous sibling node. Returns null if the current node is the first
325      * child of its parent.
326      */

327
328     public NodeInfo getPreviousSibling() {
329         return parent.getNthChild(index - 1);
330     }
331
332
333     /**
334      * Get next sibling node
335      *
336      * @return The next sibling node of the required type. Returns null if the current node is the last
337      * child of its parent.
338      */

339
340     public NodeInfo getNextSibling() {
341         return parent.getNthChild(index + 1);
342     }
343
344     /**
345      * Get first child - default implementation used for leaf nodes
346      *
347      * @return null
348      */

349
350     public NodeInfo getFirstChild() {
351         return null;
352     }
353
354     /**
355      * Get last child - default implementation used for leaf nodes
356      *
357      * @return null
358      */

359
360     public NodeInfo getLastChild() {
361         return null;
362     }
363
364     /**
365      * Return an enumeration over the nodes reached by the given axis from this node
366      *
367      * @param axisNumber The axis to be iterated over
368      * @return an AxisIterator that scans the nodes reached by the axis in turn.
369      */

370
371     public AxisIterator iterateAxis(byte axisNumber) {
372         // Fast path for child axis
373
if (axisNumber == Axis.CHILD) {
374             if (this instanceof ParentNodeImpl) {
375                 return ((ParentNodeImpl)this).enumerateChildren(null);
376             } else {
377                 return EmptyIterator.getInstance();
378             }
379         } else {
380             return iterateAxis(axisNumber, AnyNodeTest.getInstance());
381         }
382     }
383
384     /**
385      * Return an enumeration over the nodes reached by the given axis from this node
386      *
387      * @param axisNumber The axis to be iterated over
388      * @param nodeTest A pattern to be matched by the returned nodes
389      * @return an AxisIterator that scans the nodes reached by the axis in turn.
390      */

391
392     public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
393
394         switch (axisNumber) {
395             case Axis.ANCESTOR:
396                 return new AncestorEnumeration(this, nodeTest, false);
397
398             case Axis.ANCESTOR_OR_SELF:
399                 return new AncestorEnumeration(this, nodeTest, true);
400
401             case Axis.ATTRIBUTE:
402                 if (this.getNodeKind() != Type.ELEMENT) {
403                     return EmptyIterator.getInstance();
404                 }
405                 return new AttributeEnumeration(this, nodeTest);
406
407             case Axis.CHILD:
408                 if (this instanceof ParentNodeImpl) {
409                     return ((ParentNodeImpl)this).enumerateChildren(nodeTest);
410                 } else {
411                     return EmptyIterator.getInstance();
412                 }
413
414             case Axis.DESCENDANT:
415                 if (getNodeKind() == Type.DOCUMENT &&
416                         nodeTest instanceof NameTest &&
417                         nodeTest.getPrimitiveType() == Type.ELEMENT) {
418                     return ((DocumentImpl)this).getAllElements(nodeTest.getFingerprint());
419                 } else if (hasChildNodes()) {
420                     return new DescendantEnumeration(this, nodeTest, false);
421                 } else {
422                     return EmptyIterator.getInstance();
423                 }
424
425             case Axis.DESCENDANT_OR_SELF:
426                 return new DescendantEnumeration(this, nodeTest, true);
427
428             case Axis.FOLLOWING:
429                 return new FollowingEnumeration(this, nodeTest);
430
431             case Axis.FOLLOWING_SIBLING:
432                 return new FollowingSiblingEnumeration(this, nodeTest);
433
434             case Axis.NAMESPACE:
435                 if (this.getNodeKind() != Type.ELEMENT) {
436                     return EmptyIterator.getInstance();
437                 }
438                 return new NamespaceIterator(this, nodeTest);
439
440             case Axis.PARENT:
441                 NodeInfo parent = getParent();
442                 if (parent == null) {
443                     return EmptyIterator.getInstance();
444                 }
445                 if (nodeTest.matches(parent)) {
446                     return SingletonIterator.makeIterator(parent);
447                 }
448                 return EmptyIterator.getInstance();
449
450             case Axis.PRECEDING:
451                 return new PrecedingEnumeration(this, nodeTest);
452
453             case Axis.PRECEDING_SIBLING:
454                 return new PrecedingSiblingEnumeration(this, nodeTest);
455
456             case Axis.SELF:
457                 if (nodeTest.matches(this)) {
458                     return SingletonIterator.makeIterator(this);
459                 }
460                 return EmptyIterator.getInstance();
461
462             case Axis.PRECEDING_OR_ANCESTOR:
463                 return new PrecedingOrAncestorEnumeration(this, nodeTest);
464
465             default:
466                 throw new IllegalArgumentException JavaDoc("Unknown axis number " + axisNumber);
467         }
468     }
469
470     /**
471      * Find the value of a given attribute of this node. <BR>
472      * This method is defined on all nodes to meet XSL requirements, but for nodes
473      * other than elements it will always return null.
474      * @param uri the namespace uri of an attribute
475      * @param localName the local name of an attribute
476      * @return the value of the attribute, if it exists, otherwise null
477      */

478
479 // public String getAttributeValue( String uri, String localName ) {
480
// return null;
481
// }
482

483     /**
484      * Find the value of a given attribute of this node. <BR>
485      * This method is defined on all nodes to meet XSL requirements, but for nodes
486      * other than elements it will always return null.
487      * @param name the name of an attribute. This must be an unqualified attribute name,
488      * i.e. one with no namespace prefix.
489      * @return the value of the attribute, if it exists, otherwise null
490      */

491
492     //public String getAttributeValue( String name ) {
493
// return null;
494
//}
495

496     /**
497      * Get the value of a given attribute of this node
498      *
499      * @param fingerprint The fingerprint of the attribute name
500      * @return the attribute value if it exists or null if not
501      */

502
503     public String JavaDoc getAttributeValue(int fingerprint) {
504         return null;
505     }
506
507     /**
508      * Get the root node
509      *
510      * @return the NodeInfo representing the containing document
511      */

512
513     public NodeInfo getRoot() {
514         return getDocumentRoot();
515     }
516
517     /**
518      * Get the root (document) node
519      *
520      * @return the DocumentInfo representing the containing document
521      */

522
523     public DocumentInfo getDocumentRoot() {
524         return getParent().getDocumentRoot();
525     }
526
527     /**
528      * Get the next node in document order
529      *
530      * @param anchor the scan stops when it reaches a node that is not a descendant of the specified
531      * anchor node
532      * @return the next node in the document, or null if there is no such node
533      */

534
535     public NodeImpl getNextInDocument(NodeImpl anchor) {
536         // find the first child node if there is one; otherwise the next sibling node
537
// if there is one; otherwise the next sibling of the parent, grandparent, etc, up to the anchor element.
538
// If this yields no result, return null.
539

540         NodeImpl next = (NodeImpl)getFirstChild();
541         if (next != null) {
542             return next;
543         }
544         if (this == anchor) {
545             return null;
546         }
547         next = (NodeImpl)getNextSibling();
548         if (next != null) {
549             return next;
550         }
551         NodeImpl parent = this;
552         while (true) {
553             parent = (NodeImpl)parent.getParent();
554             if (parent == null) {
555                 return null;
556             }
557             if (parent == anchor) {
558                 return null;
559             }
560             next = (NodeImpl)parent.getNextSibling();
561             if (next != null) {
562                 return next;
563             }
564         }
565     }
566
567
568     /**
569      * Get the previous node in document order
570      *
571      * @return the previous node in the document, or null if there is no such node
572      */

573
574     public NodeImpl getPreviousInDocument() {
575
576         // finds the last child of the previous sibling if there is one;
577
// otherwise the previous sibling element if there is one;
578
// otherwise the parent, up to the anchor element.
579
// If this reaches the document root, return null.
580

581         NodeImpl prev = (NodeImpl)getPreviousSibling();
582         if (prev != null) {
583             return prev.getLastDescendantOrSelf();
584         }
585         return (NodeImpl)getParent();
586     }
587
588     private NodeImpl getLastDescendantOrSelf() {
589         NodeImpl last = (NodeImpl)getLastChild();
590         if (last == null) {
591             return this;
592         }
593         return last.getLastDescendantOrSelf();
594     }
595
596     /**
597      * Output all namespace nodes associated with this element. Does nothing if
598      * the node is not an element.
599      *
600      * @param out The relevant outputter
601      * @param includeAncestors True if namespaces declared on ancestor elements must
602      */

603
604     public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors)
605             throws XPathException {
606     }
607
608     /**
609      * Get all namespace undeclarations and undeclarations defined on this element.
610      *
611      * @param buffer If this is non-null, and the result array fits in this buffer, then the result
612      * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
613      * @return An array of integers representing the namespace declarations and undeclarations present on
614      * this element. For a node other than an element, return null. Otherwise, the returned array is a
615      * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
616      * top half word of each namespace code represents the prefix, the bottom half represents the URI.
617      * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
618      * The XML namespace is never included in the list. If the supplied array is larger than required,
619      * then the first unused entry will be set to -1.
620      * <p/>
621      * <p>For a node other than an element, the method returns null.</p>
622      */

623
624     public int[] getDeclaredNamespaces(int[] buffer) {
625         return null;
626     }
627     /**
628      * Copy nodes. Copying type annotations is not yet supported for this tree
629      * structure, so we simply map the new interface onto the old
630      */

631
632 // public final void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId)
633
// throws XPathException {
634
// copy(out, whichNamespaces);
635
// }
636
//
637
// public abstract void copy(Receiver out, int whichNamespaces) throws XPathException;
638

639     // implement DOM Node methods
640

641     /**
642      * Determine whether the node has any children.
643      *
644      * @return <code>true</code> if the node has any children,
645      * <code>false</code> if the node has no children.
646      */

647
648     public boolean hasChildNodes() {
649         return getFirstChild() != null;
650     }
651
652 }
653
654 //
655
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
656
// you may not use this file except in compliance with the License. You may obtain a copy of the
657
// License at http://www.mozilla.org/MPL/
658
//
659
// Software distributed under the License is distributed on an "AS IS" basis,
660
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
661
// See the License for the specific language governing rights and limitations under the License.
662
//
663
// The Original Code is: all this file.
664
//
665
// The Initial Developer of the Original Code is Michael H. Kay.
666
//
667
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
668
//
669
// Contributor(s): none.
670
//
671
Popular Tags