001: package net.sf.saxon.tree;
002:
003: import net.sf.saxon.om.*;
004: import net.sf.saxon.pattern.AnyNodeTest;
005: import net.sf.saxon.pattern.NodeTest;
006:
007: /**
008: * ParentNodeImpl is an implementation of a non-leaf node (specifically, an Element node
009: * or a Document node)
010: * @author Michael H. Kay
011: */
012:
013: abstract class ParentNodeImpl extends NodeImpl {
014:
015: private Object children = null; // null for no children
016: // a NodeInfo for a single child
017: // a NodeInfo[] for >1 child
018:
019: protected int sequence;
020:
021: /**
022: * Get the node sequence number (in document order). Sequence numbers are monotonic but not
023: * consecutive. In the current implementation, parent nodes (elements and roots) have a zero
024: * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have
025: * the top word the same as their owner and the bottom half reflecting their relative position.
026: */
027:
028: protected final long getSequenceNumber() {
029: return ((long) sequence) << 32;
030: }
031:
032: /**
033: * Determine if the node has any children.
034: */
035:
036: public final boolean hasChildNodes() {
037: return (children != null);
038: }
039:
040: /**
041: * Get an enumeration of the children of this node
042: * @param test A NodeTest to be satisfied by the child nodes, or null
043: * if all child node are to be returned
044: */
045:
046: public final AxisIterator enumerateChildren(NodeTest test) {
047: if (children == null) {
048: return EmptyIterator.getInstance();
049: } else if (children instanceof NodeImpl) {
050: NodeImpl child = (NodeImpl) children;
051: if (test == null || test.matches(child)) {
052: return SingletonIterator.makeIterator(child);
053: } else {
054: return EmptyIterator.getInstance();
055: }
056: } else {
057: if (test == null || test instanceof AnyNodeTest) {
058: return new ArrayIterator((NodeImpl[]) children);
059: } else {
060: return new ChildEnumeration(this , test);
061: }
062: }
063: }
064:
065: /**
066: * Get the first child node of the element
067: * @return the first child node of the required type, or null if there are no children
068: */
069:
070: public final NodeInfo getFirstChild() {
071: if (children == null)
072: return null;
073: if (children instanceof NodeImpl)
074: return (NodeImpl) children;
075: return ((NodeImpl[]) children)[0];
076: }
077:
078: /**
079: * Get the last child node of the element
080: * @return the last child of the element, or null if there are no children
081: */
082:
083: public final NodeInfo getLastChild() {
084: if (children == null)
085: return null;
086: if (children instanceof NodeImpl)
087: return (NodeImpl) children;
088: NodeImpl[] n = (NodeImpl[]) children;
089: return n[n.length - 1];
090: }
091:
092: /**
093: * Get the nth child node of the element (numbering from 0)
094: * @return the last child of the element, or null if there is no n'th child
095: */
096:
097: protected final NodeImpl getNthChild(int n) {
098: if (children == null)
099: return null;
100: if (children instanceof NodeImpl) {
101: return (n == 0 ? (NodeImpl) children : null);
102: }
103: NodeImpl[] nodes = (NodeImpl[]) children;
104: if (n < 0 || n >= nodes.length)
105: return null;
106: return nodes[n];
107: }
108:
109: /**
110: * Return the string-value of the node, that is, the concatenation
111: * of the character content of all descendent elements and text nodes.
112: * @return the accumulated character content of the element, including descendant elements.
113: */
114:
115: public String getStringValue() {
116: return getStringValueCS().toString();
117: }
118:
119: public CharSequence getStringValueCS() {
120: FastStringBuffer sb = null;
121:
122: NodeImpl next = (NodeImpl) getFirstChild();
123: while (next != null) {
124: if (next instanceof TextImpl) {
125: if (sb == null) {
126: sb = new FastStringBuffer(1024);
127: }
128: sb.append(next.getStringValueCS());
129: }
130: next = next.getNextInDocument(this );
131: }
132: if (sb == null)
133: return "";
134: return sb.condense();
135: }
136:
137: /**
138: * Copy the string-value of this node to a given outputter
139: */
140: /*
141: public void copyStringValue(Receiver out) throws XPathException {
142: NodeImpl next = (NodeImpl)getFirstChild();
143: while (next!=null) {
144: if (next.getItemType()==Type.TEXT) {
145: next.copyStringValue(out);
146: }
147: next = next.getNextInDocument(this);
148: }
149: }
150: */
151: /**
152: * Supply an array to be used for the array of children. For system use only.
153: */
154:
155: public void useChildrenArray(NodeImpl[] array) {
156: children = array;
157: }
158:
159: /**
160: * Add a child node to this node. For system use only. Note: normalizing adjacent text nodes
161: * is the responsibility of the caller.
162: */
163:
164: public void addChild(NodeImpl node, int index) {
165: NodeImpl[] c;
166: if (children == null) {
167: c = new NodeImpl[10];
168: } else if (children instanceof NodeImpl) {
169: c = new NodeImpl[10];
170: c[0] = (NodeImpl) children;
171: } else {
172: c = (NodeImpl[]) children;
173: }
174: if (index >= c.length) {
175: NodeImpl[] kids = new NodeImpl[c.length * 2];
176: System.arraycopy(c, 0, kids, 0, c.length);
177: c = kids;
178: }
179: c[index] = node;
180: node.parent = this ;
181: node.index = index;
182: children = c;
183: }
184:
185: /**
186: * Compact the space used by this node
187: */
188:
189: public void compact(int size) {
190: if (size == 0) {
191: children = null;
192: } else if (size == 1) {
193: if (children instanceof NodeImpl[]) {
194: children = ((NodeImpl[]) children)[0];
195: }
196: } else {
197: NodeImpl[] kids = new NodeImpl[size];
198: System.arraycopy(children, 0, kids, 0, size);
199: children = kids;
200: }
201: }
202:
203: }
204:
205: //
206: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
207: // you may not use this file except in compliance with the License. You may obtain a copy of the
208: // License at http://www.mozilla.org/MPL/
209: //
210: // Software distributed under the License is distributed on an "AS IS" basis,
211: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
212: // See the License for the specific language governing rights and limitations under the License.
213: //
214: // The Original Code is: all this file.
215: //
216: // The Initial Developer of the Original Code is Michael H. Kay.
217: //
218: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
219: //
220: // Contributor(s): none.
221: //
|