package client.net.sf.saxon.ce.tree.linked; import client.net.sf.saxon.ce.om.*; import client.net.sf.saxon.ce.tree.iter.AxisIterator; import client.net.sf.saxon.ce.tree.iter.EmptyIterator; import client.net.sf.saxon.ce.tree.iter.NodeArrayIterator; import client.net.sf.saxon.ce.tree.iter.SingleNodeIterator; import client.net.sf.saxon.ce.pattern.AnyNodeTest; import client.net.sf.saxon.ce.pattern.NodeTest; import client.net.sf.saxon.ce.type.Type; import client.net.sf.saxon.ce.tree.util.Navigator; import client.net.sf.saxon.ce.tree.util.FastStringBuffer; /** * ParentNodeImpl is an implementation of a non-leaf node (specifically, an Element node * or a Document node) * @author Michael H. Kay */ abstract class ParentNodeImpl extends NodeImpl { private Object children = null; // null for no children // a NodeImpl for a single child // a NodeImpl[] for >1 child private int sequence; // sequence number allocated during original tree creation. // set to -1 for nodes added subsequently by XQuery update /** * Get the node sequence number (in document order). Sequence numbers are monotonic but not * consecutive. In the current implementation, parent nodes (elements and document nodes) have a zero * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have * the top word the same as their owner and the bottom half reflecting their relative position. * For nodes added by XQUery Update, the sequence number is -1L * @return the sequence number if there is one, or -1L otherwise. */ protected final int[] getSequenceNumber() { return new int[]{getRawSequenceNumber(), 0}; } protected final int getRawSequenceNumber() { return sequence; } protected final void setRawSequenceNumber(int seq) { sequence = seq; } /** * Set the children of this node * @param children null if there are no children, a single NodeInfo if there is one child, an array of NodeInfo * if there are multiple children */ protected final void setChildren(Object children) { this.children = children; } /** * Determine if the node has any children. */ public final boolean hasChildNodes() { return (children!=null); } /** * Determine how many children the node has * @return the number of children of this parent node */ public final int getNumberOfChildren() { if (children == null) { return 0; } else if (children instanceof NodeImpl) { return 1; } else { return ((NodeInfo[])children).length; } } /** * Get an enumeration of the children of this node * @param test A NodeTest to be satisfied by the child nodes, or null * if all child node are to be returned * @return an iterator over the children of this node */ protected final AxisIterator enumerateChildren(NodeTest test) { if (children==null) { return EmptyIterator.getInstance(); } else if (children instanceof NodeImpl) { NodeImpl child = (NodeImpl)children; if (test == null || test instanceof AnyNodeTest) { return SingleNodeIterator.makeIterator(child); } else { return Navigator.filteredSingleton(child, test); } } else { if (test == null || test instanceof AnyNodeTest) { return new NodeArrayIterator((NodeImpl[])children); } else { return new ChildEnumeration(this, test); } } } /** * Get the first child node of the element * @return the first child node of the required type, or null if there are no children */ public final NodeInfo getFirstChild() { if (children==null) return null; if (children instanceof NodeImpl) return (NodeImpl)children; return ((NodeImpl[])children)[0]; } /** * Get the last child node of the element * @return the last child of the element, or null if there are no children */ public final NodeInfo getLastChild() { if (children==null) return null; if (children instanceof NodeImpl) return (NodeImpl)children; NodeImpl[] n = (NodeImpl[])children; return n[n.length-1]; } /** * Get the nth child node of the element (numbering from 0) * @param n identifies the required child * @return the last child of the element, or null if there is no n'th child */ protected final NodeImpl getNthChild(int n) { if (children==null) return null; if (children instanceof NodeImpl) { return (n==0 ? (NodeImpl)children : null); } NodeImpl[] nodes = (NodeImpl[])children; if (n<0 || n>=nodes.length) return null; return nodes[n]; } /** * Return the string-value of the node, that is, the concatenation * of the character content of all descendent elements and text nodes. * @return the accumulated character content of the element, including descendant elements. */ public String getStringValue() { return getStringValueCS().toString(); } public CharSequence getStringValueCS() { FastStringBuffer sb = null; NodeImpl next = (NodeImpl)getFirstChild(); while (next!=null) { if (next instanceof TextImpl) { if (sb==null) { sb = new FastStringBuffer(FastStringBuffer.SMALL); } sb.append(next.getStringValueCS()); } next = next.getNextInDocument(this); } if (sb==null) return ""; return sb.condense(); } /** * Add a child node to this node. For system use only. Note: normalizing adjacent text nodes * is the responsibility of the caller. * @param node the node to be added as a child of this node. This must be an instance of * {@link client.net.sf.saxon.ce.tree.linked.NodeImpl}. It will be modified as a result of this call (by setting its * parent property and sibling position) * @param index the position where the child is to be added */ protected synchronized void addChild(NodeImpl node, int index) { NodeImpl[] c; if (children == null) { c = new NodeImpl[10]; } else if (children instanceof NodeImpl) { c = new NodeImpl[10]; c[0] = (NodeImpl)children; } else { c = (NodeImpl[])children; } if (index >= c.length) { NodeImpl[] kids = new NodeImpl[c.length * 2]; System.arraycopy(c, 0, kids, 0, c.length); c = kids; } c[index] = node; node.setRawParent(this); node.setSiblingPosition(index); children = c; } /** * Compact the space used by this node * @param size the number of actual children */ public synchronized void compact(int size) { if (size==0) { children = null; } else if (size==1) { if (children instanceof NodeImpl[]) { children = ((NodeImpl[])children)[0]; } } else { NodeImpl[] kids = new NodeImpl[size]; System.arraycopy(children, 0, kids, 0, size); children = kids; } } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.