001: package net.sf.saxon.tinytree;
002:
003: import net.sf.saxon.type.Type;
004: import net.sf.saxon.om.FastStringBuffer;
005:
006: /**
007: * TinyParentNodeImpl is an implementation of a non-leaf node (specifically, an Element node
008: * or a Document node)
009: * @author Michael H. Kay
010: */
011:
012: abstract class TinyParentNodeImpl extends TinyNodeImpl {
013:
014: /**
015: * Determine if the node has children.
016: */
017:
018: public final boolean hasChildNodes() {
019: return (nodeNr + 1 < tree.numberOfNodes && tree.depth[nodeNr + 1] > tree.depth[nodeNr]);
020: }
021:
022: /**
023: * Return the string-value of the node, that is, the concatenation
024: * of the character content of all descendent elements and text nodes.
025: * @return the accumulated character content of the element, including descendant elements.
026: */
027:
028: public final String getStringValue() {
029: return getStringValue(tree, nodeNr).toString();
030: }
031:
032: /**
033: * Get the value of the item as a CharSequence. This is in some cases more efficient than
034: * the version of the method that returns a String.
035: */
036:
037: public CharSequence getStringValueCS() {
038: return getStringValue(tree, nodeNr);
039: }
040:
041: /**
042: * Get the string value of a node. This static method allows the string value of a node
043: * to be obtained without instantiating the node as a Java object. The method also returns
044: * a CharSequence rather than a string, which means it can sometimes avoid copying the
045: * data.
046: * @param tree The containing document
047: * @param nodeNr identifies the node whose string value is required. This must be a
048: * document or element node. The caller is trusted to ensure this.
049: * @return the string value of the node, as a CharSequence
050: */
051:
052: public static final CharSequence getStringValue(TinyTree tree,
053: int nodeNr) {
054: int level = tree.depth[nodeNr];
055:
056: // note, we can't rely on the value being contiguously stored because of whitespace
057: // nodes: the data for these may still be present.
058:
059: int next = nodeNr + 1;
060:
061: // we optimize two special cases: firstly, where the node has no children, and secondly,
062: // where it has a single text node as a child.
063:
064: if (tree.depth[next] <= level) {
065: return "";
066: } else if (tree.nodeKind[next] == Type.TEXT
067: && tree.depth[next + 1] <= level) {
068: int length = tree.beta[next];
069: int start = tree.alpha[next];
070: return new CharSlice(tree.charBuffer, start, length);
071: }
072:
073: // now handle the general case
074:
075: FastStringBuffer sb = null;
076: while (next < tree.numberOfNodes && tree.depth[next] > level) {
077: if (tree.nodeKind[next] == Type.TEXT) {
078: int length = tree.beta[next];
079: int start = tree.alpha[next];
080: if (sb == null) {
081: sb = new FastStringBuffer(1024);
082: }
083: sb.append(tree.charBuffer, start, length);
084: }
085: next++;
086: }
087: if (sb == null)
088: return "";
089: return sb.condense();
090: }
091:
092: }
093:
094: //
095: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
096: // you may not use this file except in compliance with the License. You may obtain a copy of the
097: // License at http://www.mozilla.org/MPL/
098: //
099: // Software distributed under the License is distributed on an "AS IS" basis,
100: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
101: // See the License for the specific language governing rights and limitations under the License.
102: //
103: // The Original Code is: all this file.
104: //
105: // The Initial Developer of the Original Code is Michael H. Kay.
106: //
107: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
108: //
109: // Contributor(s): none.
110: //
|