001: package net.sf.saxon.tree;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.event.Receiver;
005: import net.sf.saxon.om.*;
006: import net.sf.saxon.pattern.AnyNodeTest;
007: import net.sf.saxon.pattern.NameTest;
008: import net.sf.saxon.pattern.NodeTest;
009: import net.sf.saxon.trans.XPathException;
010: import net.sf.saxon.type.Type;
011: import net.sf.saxon.value.UntypedAtomicValue;
012: import net.sf.saxon.value.Value;
013:
014: import javax.xml.transform.SourceLocator;
015:
016: /**
017: * A node in the XML parse tree representing an XML element, character content, or attribute.<P>
018: * This is the top-level class in the implementation class hierarchy; it essentially contains
019: * all those methods that can be defined using other primitive methods, without direct access
020: * to data.
021: *
022: * @author Michael H. Kay
023: */
024:
025: public abstract class NodeImpl implements NodeInfo, FingerprintedNode,
026: SourceLocator {
027:
028: protected ParentNodeImpl parent;
029: protected int index;
030: /**
031: * Chararacteristic letters to identify each type of node, indexed using the node type
032: * values. These are used as the initial letter of the result of generate-id()
033: */
034:
035: public static final char[] NODE_LETTER = { 'x', 'e', 'a', 't', 'x',
036: 'x', 'x', 'p', 'c', 'r', 'x', 'x', 'x', 'n' };
037:
038: /**
039: * Get the value of the item as a CharSequence. This is in some cases more efficient than
040: * the version of the method that returns a String.
041: */
042:
043: public CharSequence getStringValueCS() {
044: return getStringValue();
045: }
046:
047: /**
048: * Get the type annotation of this node, if any
049: */
050:
051: public int getTypeAnnotation() {
052: return -1;
053: }
054:
055: /**
056: * Get the column number of the node.
057: * The default implementation returns -1, meaning unknown
058: */
059:
060: public int getColumnNumber() {
061: return -1;
062: }
063:
064: /**
065: * Get the public identifier of the document entity containing this node.
066: * The default implementation returns null, meaning unknown
067: */
068:
069: public String getPublicId() {
070: return null;
071: }
072:
073: /**
074: * Get the document number of the document containing this node. For a free-standing
075: * orphan node, just return the hashcode.
076: */
077:
078: public int getDocumentNumber() {
079: return getRoot().getDocumentNumber();
080: }
081:
082: /**
083: * Get the typed value of this node.
084: * If there is no type annotation, we return the string value, as an instance
085: * of xdt:untypedAtomic
086: */
087:
088: public SequenceIterator getTypedValue() throws XPathException {
089: return SingletonIterator.makeIterator(new UntypedAtomicValue(
090: getStringValue()));
091: }
092:
093: /**
094: * Get the typed value. The result of this method will always be consistent with the method
095: * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be
096: * more efficient, especially in the common case where the value is expected to be a singleton.
097: *
098: * @return the typed value. If requireSingleton is set to true, the result will always be an
099: * 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 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 generateId() {
161: return getDocumentRoot().generateId()
162: + NODE_LETTER[getNodeKind()] + getSequenceNumber();
163: }
164:
165: /**
166: * Get the system ID for the node. Default implementation for child nodes.
167: */
168:
169: public String 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 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 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 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 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 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: * Get next sibling node
334: *
335: * @return The next sibling node of the required type. Returns null if the current node is the last
336: * child of its parent.
337: */
338:
339: public NodeInfo getNextSibling() {
340: return parent.getNthChild(index + 1);
341: }
342:
343: /**
344: * Get first child - default implementation used for leaf nodes
345: *
346: * @return null
347: */
348:
349: public NodeInfo getFirstChild() {
350: return null;
351: }
352:
353: /**
354: * Get last child - default implementation used for leaf nodes
355: *
356: * @return null
357: */
358:
359: public NodeInfo getLastChild() {
360: return null;
361: }
362:
363: /**
364: * Return an enumeration over the nodes reached by the given axis from this node
365: *
366: * @param axisNumber The axis to be iterated over
367: * @return an AxisIterator that scans the nodes reached by the axis in turn.
368: */
369:
370: public AxisIterator iterateAxis(byte axisNumber) {
371: // Fast path for child axis
372: if (axisNumber == Axis.CHILD) {
373: if (this instanceof ParentNodeImpl) {
374: return ((ParentNodeImpl) this ).enumerateChildren(null);
375: } else {
376: return EmptyIterator.getInstance();
377: }
378: } else {
379: return iterateAxis(axisNumber, AnyNodeTest.getInstance());
380: }
381: }
382:
383: /**
384: * Return an enumeration over the nodes reached by the given axis from this node
385: *
386: * @param axisNumber The axis to be iterated over
387: * @param nodeTest A pattern to be matched by the returned nodes
388: * @return an AxisIterator that scans the nodes reached by the axis in turn.
389: */
390:
391: public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
392:
393: switch (axisNumber) {
394: case Axis.ANCESTOR:
395: return new AncestorEnumeration(this , nodeTest, false);
396:
397: case Axis.ANCESTOR_OR_SELF:
398: return new AncestorEnumeration(this , nodeTest, true);
399:
400: case Axis.ATTRIBUTE:
401: if (this .getNodeKind() != Type.ELEMENT) {
402: return EmptyIterator.getInstance();
403: }
404: return new AttributeEnumeration(this , nodeTest);
405:
406: case Axis.CHILD:
407: if (this instanceof ParentNodeImpl) {
408: return ((ParentNodeImpl) this )
409: .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
419: .getFingerprint());
420: } else if (hasChildNodes()) {
421: return new DescendantEnumeration(this , nodeTest, false);
422: } else {
423: return EmptyIterator.getInstance();
424: }
425:
426: case Axis.DESCENDANT_OR_SELF:
427: return new DescendantEnumeration(this , nodeTest, true);
428:
429: case Axis.FOLLOWING:
430: return new FollowingEnumeration(this , nodeTest);
431:
432: case Axis.FOLLOWING_SIBLING:
433: return new FollowingSiblingEnumeration(this , nodeTest);
434:
435: case Axis.NAMESPACE:
436: if (this .getNodeKind() != Type.ELEMENT) {
437: return EmptyIterator.getInstance();
438: }
439: return new NamespaceIterator(this , nodeTest);
440:
441: case Axis.PARENT:
442: NodeInfo parent = getParent();
443: if (parent == null) {
444: return EmptyIterator.getInstance();
445: }
446: if (nodeTest.matches(parent)) {
447: return SingletonIterator.makeIterator(parent);
448: }
449: return EmptyIterator.getInstance();
450:
451: case Axis.PRECEDING:
452: return new PrecedingEnumeration(this , nodeTest);
453:
454: case Axis.PRECEDING_SIBLING:
455: return new PrecedingSiblingEnumeration(this , nodeTest);
456:
457: case Axis.SELF:
458: if (nodeTest.matches(this )) {
459: return SingletonIterator.makeIterator(this );
460: }
461: return EmptyIterator.getInstance();
462:
463: case Axis.PRECEDING_OR_ANCESTOR:
464: return new PrecedingOrAncestorEnumeration(this , nodeTest);
465:
466: default:
467: throw new IllegalArgumentException("Unknown axis number "
468: + axisNumber);
469: }
470: }
471:
472: /**
473: * Find the value of a given attribute of this node. <BR>
474: * This method is defined on all nodes to meet XSL requirements, but for nodes
475: * other than elements it will always return null.
476: * @param uri the namespace uri of an attribute
477: * @param localName the local name of an attribute
478: * @return the value of the attribute, if it exists, otherwise null
479: */
480:
481: // public String getAttributeValue( String uri, String localName ) {
482: // return null;
483: // }
484: /**
485: * Find the value of a given attribute of this node. <BR>
486: * This method is defined on all nodes to meet XSL requirements, but for nodes
487: * other than elements it will always return null.
488: * @param name the name of an attribute. This must be an unqualified attribute name,
489: * i.e. one with no namespace prefix.
490: * @return the value of the attribute, if it exists, otherwise null
491: */
492:
493: //public String getAttributeValue( String name ) {
494: // return null;
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 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: * Get the previous node in document order
569: *
570: * @return the previous node in the document, or null if there is no such node
571: */
572:
573: public NodeImpl getPreviousInDocument() {
574:
575: // finds the last child of the previous sibling if there is one;
576: // otherwise the previous sibling element if there is one;
577: // otherwise the parent, up to the anchor element.
578: // If this reaches the document root, return null.
579:
580: NodeImpl prev = (NodeImpl) getPreviousSibling();
581: if (prev != null) {
582: return prev.getLastDescendantOrSelf();
583: }
584: return (NodeImpl) getParent();
585: }
586:
587: private NodeImpl getLastDescendantOrSelf() {
588: NodeImpl last = (NodeImpl) getLastChild();
589: if (last == null) {
590: return this ;
591: }
592: return last.getLastDescendantOrSelf();
593: }
594:
595: /**
596: * Output all namespace nodes associated with this element. Does nothing if
597: * the node is not an element.
598: *
599: * @param out The relevant outputter
600: * @param includeAncestors True if namespaces declared on ancestor elements must
601: */
602:
603: public void sendNamespaceDeclarations(Receiver out,
604: boolean includeAncestors) throws XPathException {
605: }
606:
607: /**
608: * Get all namespace undeclarations and undeclarations defined on this element.
609: *
610: * @param buffer If this is non-null, and the result array fits in this buffer, then the result
611: * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
612: * @return An array of integers representing the namespace declarations and undeclarations present on
613: * this element. For a node other than an element, return null. Otherwise, the returned array is a
614: * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
615: * top half word of each namespace code represents the prefix, the bottom half represents the URI.
616: * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
617: * The XML namespace is never included in the list. If the supplied array is larger than required,
618: * then the first unused entry will be set to -1.
619: * <p/>
620: * <p>For a node other than an element, the method returns null.</p>
621: */
622:
623: public int[] getDeclaredNamespaces(int[] buffer) {
624: return null;
625: }
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: // implement DOM Node methods
639: /**
640: * Determine whether the node has any children.
641: *
642: * @return <code>true</code> if the node has any children,
643: * <code>false</code> if the node has no children.
644: */
645:
646: public boolean hasChildNodes() {
647: return getFirstChild() != null;
648: }
649:
650: }
651:
652: //
653: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
654: // you may not use this file except in compliance with the License. You may obtain a copy of the
655: // License at http://www.mozilla.org/MPL/
656: //
657: // Software distributed under the License is distributed on an "AS IS" basis,
658: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
659: // See the License for the specific language governing rights and limitations under the License.
660: //
661: // The Original Code is: all this file.
662: //
663: // The Initial Developer of the Original Code is Michael H. Kay.
664: //
665: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
666: //
667: // Contributor(s): none.
668: //
|