KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > tinytree > TinyNodeImpl


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

27
28 public abstract class TinyNodeImpl implements NodeInfo, FingerprintedNode, SourceLocator JavaDoc {
29
30     protected TinyTree tree;
31     protected int nodeNr;
32     protected TinyNodeImpl parent = null;
33
34     /**
35     * Chararacteristic letters to identify each type of node, indexed using the node type
36     * values. These are used as the initial letter of the result of generate-id()
37     */

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

46
47     public CharSequence JavaDoc getStringValueCS() {
48         return getStringValue();
49     }
50
51     /**
52     * Get the type annotation of this node, if any
53     */

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

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

72
73     public String JavaDoc getPublicId() {
74         return null;
75     }
76
77     /**
78      * Get the typed value of this node.
79      * If there is no type annotation, we return the string value, as an instance
80      * of xdt:untypedAtomic
81     */

82
83     public SequenceIterator getTypedValue() throws XPathException {
84         int annotation = getTypeAnnotation();
85         if ((annotation & NodeInfo.IS_DTD_TYPE) != 0) {
86             annotation = StandardNames.XDT_UNTYPED_ATOMIC;
87         }
88         if (annotation==-1 || annotation==StandardNames.XDT_UNTYPED_ATOMIC || annotation==StandardNames.XDT_UNTYPED) {
89             return SingletonIterator.makeIterator(new UntypedAtomicValue(getStringValueCS()));
90         } else {
91             SchemaType stype = getConfiguration().getSchemaType(annotation);
92             if (stype == null) {
93                 String JavaDoc typeName = getNamePool().getDisplayName(annotation);
94                 throw new DynamicError("Unknown type annotation " +
95                         Err.wrap(typeName) + " in document instance");
96             } else {
97                 return stype.getTypedValue(this);
98             }
99         }
100     }
101
102     /**
103      * Get the typed value. The result of this method will always be consistent with the method
104      * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be
105      * more efficient, especially in the common case where the value is expected to be a singleton.
106      *
107      * @return the typed value. If requireSingleton is set to true, the result will always be an
108      * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
109      * values.
110      * @since 8.5
111      */

112
113     public Value atomize() throws XPathException {
114         int annotation = getTypeAnnotation();
115         if ((annotation & NodeInfo.IS_DTD_TYPE) != 0) {
116             annotation = StandardNames.XDT_UNTYPED_ATOMIC;
117         }
118         if (annotation==-1 || annotation==StandardNames.XDT_UNTYPED_ATOMIC || annotation==StandardNames.XDT_UNTYPED) {
119             return new UntypedAtomicValue(getStringValueCS());
120         } else {
121             SchemaType stype = getConfiguration().getSchemaType(annotation);
122             if (stype == null) {
123                 String JavaDoc typeName = getNamePool().getDisplayName(annotation);
124                 throw new DynamicError("Unknown type annotation " +
125                         Err.wrap(typeName) + " in document instance");
126             } else {
127                 return stype.atomize(this);
128             }
129         }
130     }
131
132
133     /**
134     * Set the system id of this node. <br />
135     * This method is present to ensure that
136     * the class implements the javax.xml.transform.Source interface, so a node can
137     * be used as the source of a transformation.
138     */

139
140     public void setSystemId(String JavaDoc uri) {
141         short type = tree.nodeKind[nodeNr];
142         if (type==Type.ATTRIBUTE || type==Type.NAMESPACE) {
143             getParent().setSystemId(uri);
144         } else {
145             tree.setSystemId(nodeNr, uri);
146         }
147     }
148
149     /**
150     * Set the parent of this node. Providing this information is useful,
151     * if it is known, because otherwise getParent() has to search backwards
152     * through the document.
153     */

154
155     protected void setParentNode(TinyNodeImpl parent) {
156         this.parent = parent;
157     }
158
159     /**
160     * Determine whether this is the same node as another node
161     * @return true if this Node object and the supplied Node object represent the
162     * same node in the tree.
163     */

164
165     public boolean isSameNodeInfo(NodeInfo other) {
166         if (this==other) return true;
167         if (!(other instanceof TinyNodeImpl)) return false;
168         if (this.tree != ((TinyNodeImpl)other).tree) return false;
169         if (this.nodeNr != ((TinyNodeImpl)other).nodeNr) return false;
170         if (this.getNodeKind() != other.getNodeKind()) return false;
171         return true;
172     }
173
174     /**
175     * Get the system ID for the entity containing the node.
176     */

177
178     public String JavaDoc getSystemId() {
179         return tree.getSystemId(nodeNr);
180     }
181
182     /**
183     * Get the base URI for the node. Default implementation for child nodes gets
184     * the base URI of the parent node.
185     */

186
187     public String JavaDoc getBaseURI() {
188         return (getParent()).getBaseURI();
189     }
190
191     /**
192     * Get the line number of the node within its source document entity
193     */

194
195     public int getLineNumber() {
196         return tree.getLineNumber(nodeNr);
197     }
198
199     /**
200     * Get the node sequence number (in document order). Sequence numbers are monotonic but not
201     * consecutive. The sequence number must be unique within the document (not, as in
202     * previous releases, within the whole document collection).
203     * For document nodes, elements, text nodes, comment nodes, and PIs, the sequence number
204      * is a long with the sequential node number in the top half and zero in the bottom half.
205      * The bottom half is used only for attributes and namespace.
206     */

207
208     protected long getSequenceNumber() {
209         return (long)nodeNr << 32;
210     }
211
212     /**
213     * Determine the relative position of this node and another node, in document order.
214     * The other node will always be in the same document.
215     * @param other The other node, whose position is to be compared with this node
216     * @return -1 if this node precedes the other node, +1 if it follows the other
217     * node, or 0 if they are the same node. (In this case, isSameNode() will always
218     * return true, and the two nodes will produce the same result for generateId())
219     */

220
221     public final int compareOrder(NodeInfo other) {
222         long a = getSequenceNumber();
223         if (other instanceof TinyNodeImpl) {
224             long b = ((TinyNodeImpl)other).getSequenceNumber();
225             if (a<b) return -1;
226             if (a>b) return +1;
227             return 0;
228         } else {
229             // it must be a namespace node
230
return 0 - other.compareOrder(this);
231         }
232     }
233
234     /**
235     * Get the fingerprint of the node, used for matching names
236     */

237
238     public int getFingerprint() {
239         int nc = getNameCode();
240         if (nc==-1) return -1;
241         return nc & 0xfffff;
242     }
243
244     /**
245     * Get the name code of the node, used for matching names
246     */

247
248     public int getNameCode() {
249         // overridden for attributes and namespace nodes.
250
return tree.nameCode[nodeNr];
251     }
252
253     /**
254     * Get the prefix part of the name of this node. This is the name before the ":" if any.
255     * @return the prefix part of the name. For an unnamed node, return "".
256     */

257
258     public String JavaDoc getPrefix() {
259         int code = tree.nameCode[nodeNr];
260         if (code<0) return "";
261         if ((code>>20 & 0xff) == 0) return "";
262         return tree.getNamePool().getPrefix(code);
263     }
264
265     /**
266     * Get the URI part of the name of this node. This is the URI corresponding to the
267     * prefix, or the URI of the default namespace if appropriate.
268     * @return The URI of the namespace of this node. For an unnamed node, or for
269     * an element or attribute in the default namespace, return an empty string.
270     */

271
272     public String JavaDoc getURI() {
273         int code = tree.nameCode[nodeNr];
274         if (code<0) return "";
275         return tree.getNamePool().getURI(code);
276     }
277
278     /**
279     * Get the display name of this node (a lexical QName). For elements and attributes this is [prefix:]localname.
280     * The original prefix is retained. For unnamed nodes, the result is an empty string.
281     * @return The display name of this node.
282     * For a node with no name, return an empty string.
283     */

284
285     public String JavaDoc getDisplayName() {
286         int code = tree.nameCode[nodeNr];
287         if (code<0) return "";
288         return tree.getNamePool().getDisplayName(code);
289     }
290
291     /**
292     * Get the local part of the name of this node.
293     * @return The local name of this node.
294     * For a node with no name, return "".
295     */

296
297     public String JavaDoc getLocalPart() {
298         int code = tree.nameCode[nodeNr];
299         if (code<0) return "";
300         return tree.getNamePool().getLocalName(code);
301     }
302
303     /**
304     * Return an iterator over all the nodes reached by the given axis from this node
305     * @param axisNumber Identifies the required axis, eg. Axis.CHILD or Axis.PARENT
306     * @return a AxisIteratorImpl that scans the nodes reached by the axis in turn.
307     */

308
309     public AxisIterator iterateAxis(byte axisNumber) {
310         // fast path for child axis
311
if (axisNumber == Axis.CHILD) {
312              if (hasChildNodes()) {
313                 return new SiblingEnumeration(tree, this, null, true);
314              } else {
315                 return EmptyIterator.getInstance();
316              }
317         } else {
318             return iterateAxis(axisNumber, AnyNodeTest.getInstance());
319         }
320     }
321
322     /**
323     * Return an iterator over the nodes reached by the given axis from this node
324     * @param axisNumber Identifies the required axis, eg. Axis.CHILD or Axis.PARENT
325     * @param nodeTest A pattern to be matched by the returned nodes.
326     * @return a AxisIteratorImpl that scans the nodes reached by the axis in turn.
327     */

328
329     public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
330
331         int type = getNodeKind();
332         switch (axisNumber) {
333             case Axis.ANCESTOR:
334                  return new AncestorEnumeration(this, nodeTest, false);
335
336             case Axis.ANCESTOR_OR_SELF:
337                  return new AncestorEnumeration(this, nodeTest, true);
338
339             case Axis.ATTRIBUTE:
340                  if (type!=Type.ELEMENT) {
341                      return EmptyIterator.getInstance();
342                  }
343                  if (tree.alpha[nodeNr]<0) {
344                      return EmptyIterator.getInstance();
345                  }
346                  return new AttributeEnumeration(tree, nodeNr, nodeTest);
347
348             case Axis.CHILD:
349                  if (hasChildNodes()) {
350                     return new SiblingEnumeration(tree, this, nodeTest, true);
351                  } else {
352                     return EmptyIterator.getInstance();
353                  }
354
355             case Axis.DESCENDANT:
356                 if (type==Type.DOCUMENT &&
357                         nodeTest instanceof NameTest &&
358                         nodeTest.getPrimitiveType()==Type.ELEMENT) {
359                     return ((TinyDocumentImpl)this).getAllElements(nodeTest.getFingerprint());
360                 } else if (hasChildNodes()) {
361                     return new DescendantEnumeration(tree, this, nodeTest, false);
362                 } else {
363                     return EmptyIterator.getInstance();
364                 }
365
366             case Axis.DESCENDANT_OR_SELF:
367                 if (hasChildNodes()) {
368                     return new DescendantEnumeration(tree, this, nodeTest, true);
369                 } else {
370                     if (nodeTest.matches(this)) {
371                         return SingletonIterator.makeIterator(this);
372                     } else {
373                         return EmptyIterator.getInstance();
374                     }
375                 }
376
377             case Axis.FOLLOWING:
378                 if (type==Type.ATTRIBUTE || type==Type.NAMESPACE) {
379                     return new FollowingEnumeration(tree, (TinyNodeImpl)getParent(), nodeTest, true);
380                 } else if (tree.depth[nodeNr] == 0) {
381                     return EmptyIterator.getInstance();
382                 } else {
383                     return new FollowingEnumeration(tree, this, nodeTest, false);
384                 }
385
386             case Axis.FOLLOWING_SIBLING:
387                 if (type==Type.ATTRIBUTE || type==Type.NAMESPACE || tree.depth[nodeNr] == 0) {
388                     return EmptyIterator.getInstance();
389                 } else {
390                     return new SiblingEnumeration(tree, this, nodeTest, false);
391                 }
392
393             case Axis.NAMESPACE:
394                 if (type!=Type.ELEMENT) {
395                     return EmptyIterator.getInstance();
396                 }
397                 return new NamespaceIterator(this, nodeTest);
398
399             case Axis.PARENT:
400                  NodeInfo parent = getParent();
401                  if (parent==null) return EmptyIterator.getInstance();
402                  if (nodeTest.matches(parent)) {
403                      return SingletonIterator.makeIterator(parent);
404                  }
405                  return EmptyIterator.getInstance();
406
407             case Axis.PRECEDING:
408                 if (type==Type.ATTRIBUTE || type==Type.NAMESPACE) {
409                     return new PrecedingEnumeration(tree, (TinyNodeImpl)getParent(), nodeTest, false);
410                 } else if (tree.depth[nodeNr] == 0) {
411                     return EmptyIterator.getInstance();
412                 } else {
413                     return new PrecedingEnumeration(tree, this, nodeTest, false);
414                 }
415
416             case Axis.PRECEDING_SIBLING:
417                 if (type==Type.ATTRIBUTE || type==Type.NAMESPACE || tree.depth[nodeNr] == 0) {
418                     return EmptyIterator.getInstance();
419                 } else {
420                     return new PrecedingSiblingEnumeration(tree, this, nodeTest);
421                 }
422
423             case Axis.SELF:
424                 if (nodeTest.matches(this)) {
425                     return SingletonIterator.makeIterator(this);
426                 }
427                 return EmptyIterator.getInstance();
428
429             case Axis.PRECEDING_OR_ANCESTOR:
430                 if (type==Type.DOCUMENT) {
431                     return EmptyIterator.getInstance();
432                 } else if (type==Type.ATTRIBUTE || type==Type.NAMESPACE) {
433                     // See test numb32.
434
TinyNodeImpl el = (TinyNodeImpl)getParent();
435                     return new PrependIterator(el, new PrecedingEnumeration(tree, el, nodeTest, true));
436                 } else {
437                     return new PrecedingEnumeration(tree, this, nodeTest, true);
438                 }
439
440             default:
441                  throw new IllegalArgumentException JavaDoc("Unknown axis number " + axisNumber);
442         }
443     }
444
445     /**
446      * Find the parent node of this node.
447      * @return The Node object describing the containing element or root node.
448      */

449
450     public NodeInfo getParent() {
451         if (parent != null) {
452             return parent;
453         }
454         int p = getParentNodeNr(tree, nodeNr);
455         if (p == -1) {
456             parent = null;
457         } else {
458             parent = tree.getNode(p);
459         }
460         return parent;
461     }
462
463     /**
464      * Static method to get the parent of a given node, without instantiating the node as an object.
465      * The starting node is any node other than an attribute or namespace node.
466      * @param tree the tree containing the starting node
467      * @param nodeNr the node number of the starting node within the tree
468      * @return the node number of the parent node, or -1 if there is no parent.
469      */

470
471     static final int getParentNodeNr(TinyTree tree, int nodeNr) {
472
473         if (tree.depth[nodeNr] == 0) {
474             return -1;
475         }
476
477         // follow the next-sibling pointers until we reach either a next sibling pointer that
478
// points backwards, or a parent-pointer pseudo-node
479
int p = tree.next[nodeNr];
480         while (p > nodeNr) {
481             if (tree.nodeKind[p] == Type.PARENT_POINTER) {
482                 return tree.alpha[p];
483             }
484             p = tree.next[p];
485         }
486         return p;
487     }
488
489     /**
490     * Determine whether the node has any children.
491     * @return <code>true</code> if this node has any attributes,
492     * <code>false</code> otherwise.
493     */

494
495     public boolean hasChildNodes() {
496         // overridden in TinyParentNodeImpl
497
return false;
498     }
499
500     /**
501     * Get the value of a given attribute of this node
502     * @param fingerprint The fingerprint of the attribute name
503     * @return the attribute value if it exists or null if not
504     */

505
506     public String JavaDoc getAttributeValue(int fingerprint) {
507         // overridden in TinyElementImpl
508
return null;
509     }
510
511     /**
512     * Get the root node of the tree (not necessarily a document node)
513     * @return the NodeInfo representing the root of this tree
514     */

515
516     public NodeInfo getRoot() {
517         if (tree.depth[nodeNr] == 0) {
518             return this;
519         }
520         if (parent != null) {
521             return parent.getRoot();
522         }
523         return tree.getNode(tree.getRootNode(nodeNr));
524     }
525
526     /**
527     * Get the root (document) node
528     * @return the DocumentInfo representing the containing document
529     */

530
531     public DocumentInfo getDocumentRoot() {
532         NodeInfo root = getRoot();
533         if (root instanceof DocumentInfo) {
534             return (DocumentInfo)root;
535         } else {
536             return null;
537         }
538     }
539
540     /**
541      * Get the configuration
542      */

543
544     public Configuration getConfiguration() {
545         return tree.getConfiguration();
546     }
547
548     /**
549      * Get the NamePool for the tree containing this node
550      * @return the NamePool
551      */

552
553     public NamePool getNamePool() {
554         return tree.getNamePool();
555     }
556
557     /**
558     * Output all namespace nodes associated with this element. Does nothing if
559     * the node is not an element.
560     * @param out The relevant outputter
561      * @param includeAncestors True if namespaces declared on ancestor elements must
562      */

563
564     public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors)
565         throws XPathException
566     {}
567
568     /**
569      * Get all namespace undeclarations and undeclarations defined on this element.
570      *
571      * @param buffer If this is non-null, and the result array fits in this buffer, then the result
572      * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
573      * @return An array of integers representing the namespace declarations and undeclarations present on
574      * this element. For a node other than an element, return null. Otherwise, the returned array is a
575      * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
576      * top half word of each namespace code represents the prefix, the bottom half represents the URI.
577      * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
578      * The XML namespace is never included in the list. If the supplied array is larger than required,
579      * then the first unused entry will be set to -1.
580      * <p/>
581      * <p>For a node other than an element, the method returns null.</p>
582      */

583
584     public int[] getDeclaredNamespaces(int[] buffer) {
585         return null;
586     }
587
588     /**
589     * Get a character string that uniquely identifies this node
590     * @return a string.
591     */

592
593     public String JavaDoc generateId() {
594         return "d" + tree.getDocumentNumber() +
595                 NODE_LETTER[getNodeKind()] +
596                 nodeNr;
597     }
598
599     /**
600      * Get the document number of the document containing this node
601      * (Needed when the document isn't a real node, for sorting free-standing elements)
602      */

603
604     public final int getDocumentNumber() {
605         return tree.getDocumentNumber();
606     }
607
608 }
609
610 //
611
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
612
// you may not use this file except in compliance with the License. You may obtain a copy of the
613
// License at http://www.mozilla.org/MPL/
614
//
615
// Software distributed under the License is distributed on an "AS IS" basis,
616
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
617
// See the License for the specific language governing rights and limitations under the License.
618
//
619
// The Original Code is: all this file.
620
//
621
// The Initial Developer of the Original Code is Michael H. Kay.
622
//
623
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
624
//
625
// Contributor(s): none.
626
//
627
Popular Tags