286N/A/*
286N/A * reserved comment block
286N/A * DO NOT REMOVE OR ALTER!
286N/A */
286N/A/*
286N/A * Copyright 1999-2005 The Apache Software Foundation.
286N/A *
286N/A * Licensed under the Apache License, Version 2.0 (the "License");
286N/A * you may not use this file except in compliance with the License.
286N/A * You may obtain a copy of the License at
286N/A *
286N/A * http://www.apache.org/licenses/LICENSE-2.0
286N/A *
286N/A * Unless required by applicable law or agreed to in writing, software
286N/A * distributed under the License is distributed on an "AS IS" BASIS,
286N/A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286N/A * See the License for the specific language governing permissions and
286N/A * limitations under the License.
286N/A */
286N/A/*
286N/A * $Id: SAX2DTM2.java,v 1.2.4.1 2005/09/15 08:15:12 suresh_emailid Exp $
286N/A */
286N/Apackage com.sun.org.apache.xml.internal.dtm.ref.sax2dtm;
286N/A
286N/Aimport com.sun.org.apache.xml.internal.dtm.*;
286N/Aimport com.sun.org.apache.xml.internal.dtm.ref.*;
286N/Aimport com.sun.org.apache.xml.internal.utils.FastStringBuffer;
286N/Aimport com.sun.org.apache.xml.internal.utils.XMLString;
286N/Aimport com.sun.org.apache.xml.internal.utils.XMLStringDefault;
286N/Aimport com.sun.org.apache.xml.internal.utils.XMLStringFactory;
286N/Aimport com.sun.org.apache.xml.internal.res.XMLMessages;
286N/Aimport com.sun.org.apache.xml.internal.res.XMLErrorResources;
286N/Aimport com.sun.org.apache.xml.internal.serializer.SerializationHandler;
286N/A
286N/Aimport javax.xml.transform.Source;
286N/Aimport java.util.Vector;
286N/Aimport com.sun.org.apache.xml.internal.utils.SuballocatedIntVector;
286N/Aimport org.xml.sax.*;
286N/A
286N/A/**
286N/A * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
286N/A * It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
286N/A * and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
286N/A * access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
286N/A * are also overridden in SAX2DTM2 for performance reasons.
286N/A * <p>
286N/A * Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
286N/A * efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
286N/A * use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
286N/A * a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
286N/A * SuballocatedIntVectors.
286N/A * <p>
286N/A * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
286N/A * SAX2DTM model, please extend from SAX2DTM instead of this class.
286N/A * <p>
286N/A * TODO: This class is currently only used by XSLTC. We need to investigate the possibility
286N/A * of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant
286N/A * boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case.
286N/A * <p>
286N/A * %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
286N/A * when making changes here!
286N/A */
286N/Apublic class SAX2DTM2 extends SAX2DTM
286N/A{
286N/A
286N/A /****************************************************************
286N/A * Optimized version of the nested iterators
286N/A ****************************************************************/
286N/A
286N/A /**
286N/A * Iterator that returns all immediate children of a given node
286N/A */
286N/A public final class ChildrenIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /**
286N/A * Setting start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A * <p>
286N/A * If the iterator is not restartable, this has no effect.
286N/A * %REVIEW% Should it return/throw something in that case,
286N/A * or set current node to END, to indicate request-not-honored?
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A _currentNode = (node == DTM.NULL) ? DTM.NULL
286N/A : _firstch2(makeNodeIdentity(node));
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END if no more
286N/A * are available.
286N/A */
286N/A public int next()
286N/A {
286N/A if (_currentNode != NULL) {
286N/A int node = _currentNode;
286N/A _currentNode = _nextsib2(node);
286N/A return returnNode(makeNodeHandle(node));
286N/A }
286N/A
286N/A return END;
286N/A }
286N/A } // end of ChildrenIterator
286N/A
286N/A /**
286N/A * Iterator that returns the parent of a given node. Note that
286N/A * this delivers only a single node; if you want all the ancestors,
286N/A * see AncestorIterator.
286N/A */
286N/A public final class ParentIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private int _nodeType = DTM.NULL;
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A
286N/A if (node != DTM.NULL)
286N/A _currentNode = _parent2(makeNodeIdentity(node));
286N/A else
286N/A _currentNode = DTM.NULL;
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Set the node type of the parent that we're looking for.
286N/A * Note that this does _not_ mean "find the nearest ancestor of
286N/A * this type", but "yield the parent if it is of this type".
286N/A *
286N/A *
286N/A * @param type extended type ID.
286N/A *
286N/A * @return ParentIterator configured with the type filter set.
286N/A */
286N/A public DTMAxisIterator setNodeType(final int type)
286N/A {
286N/A
286N/A _nodeType = type;
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration. In this case, we return
286N/A * only the immediate parent, _if_ it matches the requested nodeType.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A int result = _currentNode;
286N/A if (result == END)
286N/A return DTM.NULL;
286N/A
286N/A // %OPT% The most common case is handled first.
286N/A if (_nodeType == NULL) {
286N/A _currentNode = END;
286N/A return returnNode(makeNodeHandle(result));
286N/A }
286N/A else if (_nodeType >= DTM.NTYPES) {
286N/A if (_nodeType == _exptype2(result)) {
286N/A _currentNode = END;
286N/A return returnNode(makeNodeHandle(result));
286N/A }
286N/A }
286N/A else {
286N/A if (_nodeType == _type2(result)) {
286N/A _currentNode = END;
286N/A return returnNode(makeNodeHandle(result));
286N/A }
286N/A }
286N/A
286N/A return DTM.NULL;
286N/A }
286N/A } // end of ParentIterator
286N/A
286N/A /**
286N/A * Iterator that returns children of a given type for a given node.
286N/A * The functionality chould be achieved by putting a filter on top
286N/A * of a basic child iterator, but a specialised iterator is used
286N/A * for efficiency (both speed and size of translet).
286N/A */
286N/A public final class TypedChildrenIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedChildrenIterator
286N/A *
286N/A *
286N/A * @param nodeType The extended type ID being requested.
286N/A */
286N/A public TypedChildrenIterator(int nodeType)
286N/A {
286N/A _nodeType = nodeType;
286N/A }
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A _currentNode = (node == DTM.NULL)
286N/A ? DTM.NULL
286N/A : _firstch2(makeNodeIdentity(_startNode));
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A int node = _currentNode;
286N/A if (node == DTM.NULL)
286N/A return DTM.NULL;
286N/A
286N/A final int nodeType = _nodeType;
286N/A
286N/A if (nodeType != DTM.ELEMENT_NODE) {
286N/A while (node != DTM.NULL && _exptype2(node) != nodeType) {
286N/A node = _nextsib2(node);
286N/A }
286N/A }
286N/A // %OPT% If the nodeType is element (matching child::*), we only
286N/A // need to compare the expType with DTM.NTYPES. A child node of
286N/A // an element can be either an element, text, comment or
286N/A // processing instruction node. Only element node has an extended
286N/A // type greater than or equal to DTM.NTYPES.
286N/A else {
286N/A int eType;
286N/A while (node != DTM.NULL) {
286N/A eType = _exptype2(node);
286N/A if (eType >= DTM.NTYPES)
286N/A break;
286N/A else
286N/A node = _nextsib2(node);
286N/A }
286N/A }
286N/A
286N/A if (node == DTM.NULL) {
286N/A _currentNode = DTM.NULL;
286N/A return DTM.NULL;
286N/A } else {
286N/A _currentNode = _nextsib2(node);
286N/A return returnNode(makeNodeHandle(node));
286N/A }
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Return the node at the given position.
286N/A */
286N/A public int getNodeByPosition(int position)
286N/A {
286N/A if (position <= 0)
286N/A return DTM.NULL;
286N/A
286N/A int node = _currentNode;
286N/A int pos = 0;
286N/A
286N/A final int nodeType = _nodeType;
286N/A if (nodeType != DTM.ELEMENT_NODE) {
286N/A while (node != DTM.NULL) {
286N/A if (_exptype2(node) == nodeType) {
286N/A pos++;
286N/A if (pos == position)
286N/A return makeNodeHandle(node);
286N/A }
286N/A
286N/A node = _nextsib2(node);
286N/A }
286N/A return NULL;
286N/A }
286N/A else {
286N/A while (node != DTM.NULL) {
286N/A if (_exptype2(node) >= DTM.NTYPES) {
286N/A pos++;
286N/A if (pos == position)
286N/A return makeNodeHandle(node);
286N/A }
286N/A node = _nextsib2(node);
286N/A }
286N/A return NULL;
286N/A }
286N/A }
286N/A
286N/A } // end of TypedChildrenIterator
286N/A
286N/A /**
286N/A * Iterator that returns the namespace nodes as defined by the XPath data model
286N/A * for a given node, filtered by extended type ID.
286N/A */
286N/A public class TypedRootIterator extends RootIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedRootIterator
286N/A *
286N/A * @param nodeType The extended type ID being requested.
286N/A */
286N/A public TypedRootIterator(int nodeType)
286N/A {
286N/A super();
286N/A _nodeType = nodeType;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A if(_startNode == _currentNode)
286N/A return NULL;
286N/A
286N/A final int node = _startNode;
286N/A int expType = _exptype2(makeNodeIdentity(node));
286N/A
286N/A _currentNode = node;
286N/A
286N/A if (_nodeType >= DTM.NTYPES) {
286N/A if (_nodeType == expType) {
286N/A return returnNode(node);
286N/A }
286N/A }
286N/A else {
286N/A if (expType < DTM.NTYPES) {
286N/A if (expType == _nodeType) {
286N/A return returnNode(node);
286N/A }
286N/A }
286N/A else {
286N/A if (m_extendedTypes[expType].getNodeType() == _nodeType) {
286N/A return returnNode(node);
286N/A }
286N/A }
286N/A }
286N/A
286N/A return NULL;
286N/A }
286N/A } // end of TypedRootIterator
286N/A
286N/A /**
286N/A * Iterator that returns all siblings of a given node.
286N/A */
286N/A public class FollowingSiblingIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A _currentNode = makeNodeIdentity(node);
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A _currentNode = (_currentNode == DTM.NULL) ? DTM.NULL
286N/A : _nextsib2(_currentNode);
286N/A return returnNode(makeNodeHandle(_currentNode));
286N/A }
286N/A } // end of FollowingSiblingIterator
286N/A
286N/A /**
286N/A * Iterator that returns all following siblings of a given node.
286N/A */
286N/A public final class TypedFollowingSiblingIterator
286N/A extends FollowingSiblingIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedFollowingSiblingIterator
286N/A *
286N/A *
286N/A * @param type The extended type ID being requested.
286N/A */
286N/A public TypedFollowingSiblingIterator(int type)
286N/A {
286N/A _nodeType = type;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A if (_currentNode == DTM.NULL) {
286N/A return DTM.NULL;
286N/A }
286N/A
286N/A int node = _currentNode;
286N/A final int nodeType = _nodeType;
286N/A
286N/A if (nodeType != DTM.ELEMENT_NODE) {
286N/A while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) != nodeType) {}
286N/A }
286N/A else {
286N/A while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) < DTM.NTYPES) {}
286N/A }
286N/A
286N/A _currentNode = node;
286N/A
286N/A return (node == DTM.NULL)
286N/A ? DTM.NULL
286N/A : returnNode(makeNodeHandle(node));
286N/A }
286N/A
286N/A } // end of TypedFollowingSiblingIterator
286N/A
286N/A /**
286N/A * Iterator that returns attribute nodes (of what nodes?)
286N/A */
286N/A public final class AttributeIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A // assumes caller will pass element nodes
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A _currentNode = getFirstAttributeIdentity(makeNodeIdentity(node));
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A
286N/A final int node = _currentNode;
286N/A
286N/A if (node != NULL) {
286N/A _currentNode = getNextAttributeIdentity(node);
286N/A return returnNode(makeNodeHandle(node));
286N/A }
286N/A
286N/A return NULL;
286N/A }
286N/A } // end of AttributeIterator
286N/A
286N/A /**
286N/A * Iterator that returns attribute nodes of a given type
286N/A */
286N/A public final class TypedAttributeIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedAttributeIterator
286N/A *
286N/A *
286N/A * @param nodeType The extended type ID that is requested.
286N/A */
286N/A public TypedAttributeIterator(int nodeType)
286N/A {
286N/A _nodeType = nodeType;
286N/A }
286N/A
286N/A // assumes caller will pass element nodes
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A
286N/A _currentNode = getTypedAttribute(node, _nodeType);
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A
286N/A final int node = _currentNode;
286N/A
286N/A // singleton iterator, since there can only be one attribute of
286N/A // a given type.
286N/A _currentNode = NULL;
286N/A
286N/A return returnNode(node);
286N/A }
286N/A } // end of TypedAttributeIterator
286N/A
286N/A /**
286N/A * Iterator that returns preceding siblings of a given node
286N/A */
286N/A public class PrecedingSiblingIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /**
286N/A * The node identity of _startNode for this iterator
286N/A */
286N/A protected int _startNodeID;
286N/A
286N/A /**
286N/A * True if this iterator has a reversed axis.
286N/A *
286N/A * @return true.
286N/A */
286N/A public boolean isReverse()
286N/A {
286N/A return true;
286N/A }
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A node = _startNodeID = makeNodeIdentity(node);
286N/A
286N/A if(node == NULL)
286N/A {
286N/A _currentNode = node;
286N/A return resetPosition();
286N/A }
286N/A
286N/A int type = _type2(node);
286N/A if(ExpandedNameTable.ATTRIBUTE == type
286N/A || ExpandedNameTable.NAMESPACE == type )
286N/A {
286N/A _currentNode = node;
286N/A }
286N/A else
286N/A {
286N/A // Be careful to handle the Document node properly
286N/A _currentNode = _parent2(node);
286N/A if(NULL!=_currentNode)
286N/A _currentNode = _firstch2(_currentNode);
286N/A else
286N/A _currentNode = node;
286N/A }
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A
286N/A if (_currentNode == _startNodeID || _currentNode == DTM.NULL)
286N/A {
286N/A return NULL;
286N/A }
286N/A else
286N/A {
286N/A final int node = _currentNode;
286N/A _currentNode = _nextsib2(node);
286N/A
286N/A return returnNode(makeNodeHandle(node));
286N/A }
286N/A }
286N/A } // end of PrecedingSiblingIterator
286N/A
286N/A /**
286N/A * Iterator that returns preceding siblings of a given type for
286N/A * a given node
286N/A */
286N/A public final class TypedPrecedingSiblingIterator
286N/A extends PrecedingSiblingIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedPrecedingSiblingIterator
286N/A *
286N/A *
286N/A * @param type The extended type ID being requested.
286N/A */
286N/A public TypedPrecedingSiblingIterator(int type)
286N/A {
286N/A _nodeType = type;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A int node = _currentNode;
286N/A
286N/A final int nodeType = _nodeType;
286N/A final int startNodeID = _startNodeID;
286N/A
286N/A if (nodeType != DTM.ELEMENT_NODE) {
286N/A while (node != NULL && node != startNodeID && _exptype2(node) != nodeType) {
286N/A node = _nextsib2(node);
286N/A }
286N/A }
286N/A else {
286N/A while (node != NULL && node != startNodeID && _exptype2(node) < DTM.NTYPES) {
286N/A node = _nextsib2(node);
286N/A }
286N/A }
286N/A
286N/A if (node == DTM.NULL || node == startNodeID) {
286N/A _currentNode = NULL;
286N/A return NULL;
286N/A }
286N/A else {
286N/A _currentNode = _nextsib2(node);
286N/A return returnNode(makeNodeHandle(node));
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Return the index of the last node in this iterator.
286N/A */
286N/A public int getLast()
286N/A {
286N/A if (_last != -1)
286N/A return _last;
286N/A
286N/A setMark();
286N/A
286N/A int node = _currentNode;
286N/A final int nodeType = _nodeType;
286N/A final int startNodeID = _startNodeID;
286N/A
286N/A int last = 0;
286N/A if (nodeType != DTM.ELEMENT_NODE) {
286N/A while (node != NULL && node != startNodeID) {
286N/A if (_exptype2(node) == nodeType) {
286N/A last++;
286N/A }
286N/A node = _nextsib2(node);
286N/A }
286N/A }
286N/A else {
286N/A while (node != NULL && node != startNodeID) {
286N/A if (_exptype2(node) >= DTM.NTYPES) {
286N/A last++;
286N/A }
286N/A node = _nextsib2(node);
286N/A }
286N/A }
286N/A
286N/A gotoMark();
286N/A
286N/A return (_last = last);
286N/A }
286N/A } // end of TypedPrecedingSiblingIterator
286N/A
286N/A /**
286N/A * Iterator that returns preceding nodes of a given node.
286N/A * This includes the node set {root+1, start-1}, but excludes
286N/A * all ancestors, attributes, and namespace nodes.
286N/A */
286N/A public class PrecedingIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /** The max ancestors, but it can grow... */
286N/A private final int _maxAncestors = 8;
286N/A
286N/A /**
286N/A * The stack of start node + ancestors up to the root of the tree,
286N/A * which we must avoid.
286N/A */
286N/A protected int[] _stack = new int[_maxAncestors];
286N/A
286N/A /** (not sure yet... -sb) */
286N/A protected int _sp, _oldsp;
286N/A
286N/A protected int _markedsp, _markedNode, _markedDescendant;
286N/A
286N/A /* _currentNode precedes candidates. This is the identity, not the handle! */
286N/A
286N/A /**
286N/A * True if this iterator has a reversed axis.
286N/A *
286N/A * @return true since this iterator is a reversed axis.
286N/A */
286N/A public boolean isReverse()
286N/A {
286N/A return true;
286N/A }
286N/A
286N/A /**
286N/A * Returns a deep copy of this iterator. The cloned iterator is not reset.
286N/A *
286N/A * @return a deep copy of this iterator.
286N/A */
286N/A public DTMAxisIterator cloneIterator()
286N/A {
286N/A _isRestartable = false;
286N/A
286N/A try
286N/A {
286N/A final PrecedingIterator clone = (PrecedingIterator) super.clone();
286N/A final int[] stackCopy = new int[_stack.length];
286N/A System.arraycopy(_stack, 0, stackCopy, 0, _stack.length);
286N/A
286N/A clone._stack = stackCopy;
286N/A
286N/A // return clone.reset();
286N/A return clone;
286N/A }
286N/A catch (CloneNotSupportedException e)
286N/A {
286N/A throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A node = makeNodeIdentity(node);
286N/A
286N/A // iterator is not a clone
286N/A int parent, index;
286N/A
286N/A if (_type2(node) == DTM.ATTRIBUTE_NODE)
286N/A node = _parent2(node);
286N/A
286N/A _startNode = node;
286N/A _stack[index = 0] = node;
286N/A
286N/A parent=node;
286N/A while ((parent = _parent2(parent)) != NULL)
286N/A {
286N/A if (++index == _stack.length)
286N/A {
286N/A final int[] stack = new int[index*2];
286N/A System.arraycopy(_stack, 0, stack, 0, index);
286N/A _stack = stack;
286N/A }
286N/A _stack[index] = parent;
286N/A }
286N/A
286N/A if(index>0)
286N/A --index; // Pop actual root node (if not start) back off the stack
286N/A
286N/A _currentNode=_stack[index]; // Last parent before root node
286N/A
286N/A _oldsp = _sp = index;
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A // Bugzilla 8324: We were forgetting to skip Attrs and NS nodes.
286N/A // Also recoded the loop controls for clarity and to flatten out
286N/A // the tail-recursion.
286N/A for(++_currentNode; _sp>=0; ++_currentNode)
286N/A {
286N/A if(_currentNode < _stack[_sp])
286N/A {
286N/A int type = _type2(_currentNode);
286N/A if(type != ATTRIBUTE_NODE && type != NAMESPACE_NODE)
286N/A return returnNode(makeNodeHandle(_currentNode));
286N/A }
286N/A else
286N/A --_sp;
286N/A }
286N/A return NULL;
286N/A }
286N/A
286N/A // redefine DTMAxisIteratorBase's reset
286N/A
286N/A /**
286N/A * Resets the iterator to the last start node.
286N/A *
286N/A * @return A DTMAxisIterator, which may or may not be the same as this
286N/A * iterator.
286N/A */
286N/A public DTMAxisIterator reset()
286N/A {
286N/A
286N/A _sp = _oldsp;
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A public void setMark() {
286N/A _markedsp = _sp;
286N/A _markedNode = _currentNode;
286N/A _markedDescendant = _stack[0];
286N/A }
286N/A
286N/A public void gotoMark() {
286N/A _sp = _markedsp;
286N/A _currentNode = _markedNode;
286N/A }
286N/A } // end of PrecedingIterator
286N/A
286N/A /**
286N/A * Iterator that returns preceding nodes of agiven type for a
286N/A * given node. This includes the node set {root+1, start-1}, but
286N/A * excludes all ancestors.
286N/A */
286N/A public final class TypedPrecedingIterator extends PrecedingIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedPrecedingIterator
286N/A *
286N/A *
286N/A * @param type The extended type ID being requested.
286N/A */
286N/A public TypedPrecedingIterator(int type)
286N/A {
286N/A _nodeType = type;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A int node = _currentNode;
286N/A final int nodeType = _nodeType;
286N/A
286N/A if (nodeType >= DTM.NTYPES) {
286N/A while (true) {
286N/A node++;
286N/A
286N/A if (_sp < 0) {
286N/A node = NULL;
286N/A break;
286N/A }
286N/A else if (node >= _stack[_sp]) {
286N/A if (--_sp < 0) {
286N/A node = NULL;
286N/A break;
286N/A }
286N/A }
286N/A else if (_exptype2(node) == nodeType) {
286N/A break;
286N/A }
286N/A }
286N/A }
286N/A else {
286N/A int expType;
286N/A
286N/A while (true) {
286N/A node++;
286N/A
286N/A if (_sp < 0) {
286N/A node = NULL;
286N/A break;
286N/A }
286N/A else if (node >= _stack[_sp]) {
286N/A if (--_sp < 0) {
286N/A node = NULL;
286N/A break;
286N/A }
286N/A }
286N/A else {
286N/A expType = _exptype2(node);
286N/A if (expType < DTM.NTYPES) {
286N/A if (expType == nodeType) {
286N/A break;
286N/A }
286N/A }
286N/A else {
286N/A if (m_extendedTypes[expType].getNodeType() == nodeType) {
286N/A break;
286N/A }
286N/A }
286N/A }
286N/A }
286N/A }
286N/A
286N/A _currentNode = node;
286N/A
286N/A return (node == NULL) ? NULL : returnNode(makeNodeHandle(node));
286N/A }
286N/A } // end of TypedPrecedingIterator
286N/A
286N/A /**
286N/A * Iterator that returns following nodes of for a given node.
286N/A */
286N/A public class FollowingIterator extends InternalAxisIteratorBase
286N/A {
286N/A //DTMAxisTraverser m_traverser; // easier for now
286N/A
286N/A public FollowingIterator()
286N/A {
286N/A //m_traverser = getAxisTraverser(Axis.FOLLOWING);
286N/A }
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A _startNode = node;
286N/A
286N/A //_currentNode = m_traverser.first(node);
286N/A
286N/A node = makeNodeIdentity(node);
286N/A
286N/A int first;
286N/A int type = _type2(node);
286N/A
286N/A if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
286N/A {
286N/A node = _parent2(node);
286N/A first = _firstch2(node);
286N/A
286N/A if (NULL != first) {
286N/A _currentNode = makeNodeHandle(first);
286N/A return resetPosition();
286N/A }
286N/A }
286N/A
286N/A do
286N/A {
286N/A first = _nextsib2(node);
286N/A
286N/A if (NULL == first)
286N/A node = _parent2(node);
286N/A }
286N/A while (NULL == first && NULL != node);
286N/A
286N/A _currentNode = makeNodeHandle(first);
286N/A
286N/A // _currentNode precedes possible following(node) nodes
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A
286N/A int node = _currentNode;
286N/A
286N/A //_currentNode = m_traverser.next(_startNode, _currentNode);
286N/A int current = makeNodeIdentity(node);
286N/A
286N/A while (true)
286N/A {
286N/A current++;
286N/A
286N/A int type = _type2(current);
286N/A if (NULL == type) {
286N/A _currentNode = NULL;
286N/A return returnNode(node);
286N/A }
286N/A
286N/A if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
286N/A continue;
286N/A
286N/A _currentNode = makeNodeHandle(current);
286N/A return returnNode(node);
286N/A }
286N/A }
286N/A
286N/A } // end of FollowingIterator
286N/A
286N/A /**
286N/A * Iterator that returns following nodes of a given type for a given node.
286N/A */
286N/A public final class TypedFollowingIterator extends FollowingIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedFollowingIterator
286N/A *
286N/A *
286N/A * @param type The extended type ID being requested.
286N/A */
286N/A public TypedFollowingIterator(int type)
286N/A {
286N/A _nodeType = type;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A int current;
286N/A int node;
286N/A int type;
286N/A
286N/A final int nodeType = _nodeType;
286N/A int currentNodeID = makeNodeIdentity(_currentNode);
286N/A
286N/A if (nodeType >= DTM.NTYPES) {
286N/A do {
286N/A node = currentNodeID;
286N/A current = node;
286N/A
286N/A do {
286N/A current++;
286N/A type = _type2(current);
286N/A }
286N/A while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
286N/A
286N/A currentNodeID = (type != NULL) ? current : NULL;
286N/A }
286N/A while (node != DTM.NULL && _exptype2(node) != nodeType);
286N/A }
286N/A else {
286N/A do {
286N/A node = currentNodeID;
286N/A current = node;
286N/A
286N/A do {
286N/A current++;
286N/A type = _type2(current);
286N/A }
286N/A while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
286N/A
286N/A currentNodeID = (type != NULL) ? current : NULL;
286N/A }
286N/A while (node != DTM.NULL
286N/A && (_exptype2(node) != nodeType && _type2(node) != nodeType));
286N/A }
286N/A
286N/A _currentNode = makeNodeHandle(currentNodeID);
286N/A return (node == DTM.NULL ? DTM.NULL :returnNode(makeNodeHandle(node)));
286N/A }
286N/A } // end of TypedFollowingIterator
286N/A
286N/A /**
286N/A * Iterator that returns the ancestors of a given node in document
286N/A * order. (NOTE! This was changed from the XSLTC code!)
286N/A */
286N/A public class AncestorIterator extends InternalAxisIteratorBase
286N/A {
286N/A // The initial size of the ancestor array
286N/A private static final int m_blocksize = 32;
286N/A
286N/A // The array for ancestor nodes. This array will grow dynamically.
286N/A int[] m_ancestors = new int[m_blocksize];
286N/A
286N/A // Number of ancestor nodes in the array
286N/A int m_size = 0;
286N/A
286N/A int m_ancestorsPos;
286N/A
286N/A int m_markedPos;
286N/A
286N/A /** The real start node for this axes, since _startNode will be adjusted. */
286N/A int m_realStartNode;
286N/A
286N/A /**
286N/A * Get start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @return The root node of the iteration.
286N/A */
286N/A public int getStartNode()
286N/A {
286N/A return m_realStartNode;
286N/A }
286N/A
286N/A /**
286N/A * True if this iterator has a reversed axis.
286N/A *
286N/A * @return true since this iterator is a reversed axis.
286N/A */
286N/A public final boolean isReverse()
286N/A {
286N/A return true;
286N/A }
286N/A
286N/A /**
286N/A * Returns a deep copy of this iterator. The cloned iterator is not reset.
286N/A *
286N/A * @return a deep copy of this iterator.
286N/A */
286N/A public DTMAxisIterator cloneIterator()
286N/A {
286N/A _isRestartable = false; // must set to false for any clone
286N/A
286N/A try
286N/A {
286N/A final AncestorIterator clone = (AncestorIterator) super.clone();
286N/A
286N/A clone._startNode = _startNode;
286N/A
286N/A // return clone.reset();
286N/A return clone;
286N/A }
286N/A catch (CloneNotSupportedException e)
286N/A {
286N/A throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A m_realStartNode = node;
286N/A
286N/A if (_isRestartable)
286N/A {
286N/A int nodeID = makeNodeIdentity(node);
286N/A m_size = 0;
286N/A
286N/A if (nodeID == DTM.NULL) {
286N/A _currentNode = DTM.NULL;
286N/A m_ancestorsPos = 0;
286N/A return this;
286N/A }
286N/A
286N/A // Start from the current node's parent if
286N/A // _includeSelf is false.
286N/A if (!_includeSelf) {
286N/A nodeID = _parent2(nodeID);
286N/A node = makeNodeHandle(nodeID);
286N/A }
286N/A
286N/A _startNode = node;
286N/A
286N/A while (nodeID != END) {
286N/A //m_ancestors.addElement(node);
286N/A if (m_size >= m_ancestors.length)
286N/A {
286N/A int[] newAncestors = new int[m_size * 2];
286N/A System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
286N/A m_ancestors = newAncestors;
286N/A }
286N/A
286N/A m_ancestors[m_size++] = node;
286N/A nodeID = _parent2(nodeID);
286N/A node = makeNodeHandle(nodeID);
286N/A }
286N/A
286N/A m_ancestorsPos = m_size - 1;
286N/A
286N/A _currentNode = (m_ancestorsPos>=0)
286N/A ? m_ancestors[m_ancestorsPos]
286N/A : DTM.NULL;
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Resets the iterator to the last start node.
286N/A *
286N/A * @return A DTMAxisIterator, which may or may not be the same as this
286N/A * iterator.
286N/A */
286N/A public DTMAxisIterator reset()
286N/A {
286N/A
286N/A m_ancestorsPos = m_size - 1;
286N/A
286N/A _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
286N/A : DTM.NULL;
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A
286N/A int next = _currentNode;
286N/A
286N/A int pos = --m_ancestorsPos;
286N/A
286N/A _currentNode = (pos >= 0) ? m_ancestors[m_ancestorsPos]
286N/A : DTM.NULL;
286N/A
286N/A return returnNode(next);
286N/A }
286N/A
286N/A public void setMark() {
286N/A m_markedPos = m_ancestorsPos;
286N/A }
286N/A
286N/A public void gotoMark() {
286N/A m_ancestorsPos = m_markedPos;
286N/A _currentNode = m_ancestorsPos>=0 ? m_ancestors[m_ancestorsPos]
286N/A : DTM.NULL;
286N/A }
286N/A } // end of AncestorIterator
286N/A
286N/A /**
286N/A * Typed iterator that returns the ancestors of a given node.
286N/A */
286N/A public final class TypedAncestorIterator extends AncestorIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedAncestorIterator
286N/A *
286N/A *
286N/A * @param type The extended type ID being requested.
286N/A */
286N/A public TypedAncestorIterator(int type)
286N/A {
286N/A _nodeType = type;
286N/A }
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A m_realStartNode = node;
286N/A
286N/A if (_isRestartable)
286N/A {
286N/A int nodeID = makeNodeIdentity(node);
286N/A m_size = 0;
286N/A
286N/A if (nodeID == DTM.NULL) {
286N/A _currentNode = DTM.NULL;
286N/A m_ancestorsPos = 0;
286N/A return this;
286N/A }
286N/A
286N/A final int nodeType = _nodeType;
286N/A
286N/A if (!_includeSelf) {
286N/A nodeID = _parent2(nodeID);
286N/A node = makeNodeHandle(nodeID);
286N/A }
286N/A
286N/A _startNode = node;
286N/A
286N/A if (nodeType >= DTM.NTYPES) {
286N/A while (nodeID != END) {
286N/A int eType = _exptype2(nodeID);
286N/A
286N/A if (eType == nodeType) {
286N/A if (m_size >= m_ancestors.length)
286N/A {
286N/A int[] newAncestors = new int[m_size * 2];
286N/A System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
286N/A m_ancestors = newAncestors;
286N/A }
286N/A m_ancestors[m_size++] = makeNodeHandle(nodeID);
286N/A }
286N/A nodeID = _parent2(nodeID);
286N/A }
286N/A }
286N/A else {
286N/A while (nodeID != END) {
286N/A int eType = _exptype2(nodeID);
286N/A
286N/A if ((eType < DTM.NTYPES && eType == nodeType)
286N/A || (eType >= DTM.NTYPES
286N/A && m_extendedTypes[eType].getNodeType() == nodeType)) {
286N/A if (m_size >= m_ancestors.length)
286N/A {
286N/A int[] newAncestors = new int[m_size * 2];
286N/A System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
286N/A m_ancestors = newAncestors;
286N/A }
286N/A m_ancestors[m_size++] = makeNodeHandle(nodeID);
286N/A }
286N/A nodeID = _parent2(nodeID);
286N/A }
286N/A }
286N/A m_ancestorsPos = m_size - 1;
286N/A
286N/A _currentNode = (m_ancestorsPos>=0)
286N/A ? m_ancestors[m_ancestorsPos]
286N/A : DTM.NULL;
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Return the node at the given position.
286N/A */
286N/A public int getNodeByPosition(int position)
286N/A {
286N/A if (position > 0 && position <= m_size) {
286N/A return m_ancestors[position-1];
286N/A }
286N/A else
286N/A return DTM.NULL;
286N/A }
286N/A
286N/A /**
286N/A * Returns the position of the last node within the iteration, as
286N/A * defined by XPath.
286N/A */
286N/A public int getLast() {
286N/A return m_size;
286N/A }
286N/A } // end of TypedAncestorIterator
286N/A
286N/A /**
286N/A * Iterator that returns the descendants of a given node.
286N/A */
286N/A public class DescendantIterator extends InternalAxisIteratorBase
286N/A {
286N/A
286N/A /**
286N/A * Set start to END should 'close' the iterator,
286N/A * i.e. subsequent call to next() should return END.
286N/A *
286N/A * @param node Sets the root of the iteration.
286N/A *
286N/A * @return A DTMAxisIterator set to the start of the iteration.
286N/A */
286N/A public DTMAxisIterator setStartNode(int node)
286N/A {
286N/A//%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
286N/A if (node == DTMDefaultBase.ROOTNODE)
286N/A node = getDocument();
286N/A if (_isRestartable)
286N/A {
286N/A node = makeNodeIdentity(node);
286N/A _startNode = node;
286N/A
286N/A if (_includeSelf)
286N/A node--;
286N/A
286N/A _currentNode = node;
286N/A
286N/A return resetPosition();
286N/A }
286N/A
286N/A return this;
286N/A }
286N/A
286N/A /**
286N/A * Tell if this node identity is a descendant. Assumes that
286N/A * the node info for the element has already been obtained.
286N/A *
286N/A * This one-sided test works only if the parent has been
286N/A * previously tested and is known to be a descendent. It fails if
286N/A * the parent is the _startNode's next sibling, or indeed any node
286N/A * that follows _startNode in document order. That may suffice
286N/A * for this iterator, but it's not really an isDescendent() test.
286N/A * %REVIEW% rename?
286N/A *
286N/A * @param identity The index number of the node in question.
286N/A * @return true if the index is a descendant of _startNode.
286N/A */
286N/A protected final boolean isDescendant(int identity)
286N/A {
286N/A return (_parent2(identity) >= _startNode) || (_startNode == identity);
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A final int startNode = _startNode;
286N/A if (startNode == NULL) {
286N/A return NULL;
286N/A }
286N/A
286N/A if (_includeSelf && (_currentNode + 1) == startNode)
286N/A return returnNode(makeNodeHandle(++_currentNode)); // | m_dtmIdent);
286N/A
286N/A int node = _currentNode;
286N/A int type;
286N/A
286N/A // %OPT% If the startNode is the root node, do not need
286N/A // to do the isDescendant() check.
286N/A if (startNode == ROOTNODE) {
286N/A int eType;
286N/A do {
286N/A node++;
286N/A eType = _exptype2(node);
286N/A
286N/A if (NULL == eType) {
286N/A _currentNode = NULL;
286N/A return END;
286N/A }
286N/A } while (eType == TEXT_NODE
286N/A || (type = m_extendedTypes[eType].getNodeType()) == ATTRIBUTE_NODE
286N/A || type == NAMESPACE_NODE);
286N/A }
286N/A else {
286N/A do {
286N/A node++;
286N/A type = _type2(node);
286N/A
286N/A if (NULL == type ||!isDescendant(node)) {
286N/A _currentNode = NULL;
286N/A return END;
286N/A }
286N/A } while(ATTRIBUTE_NODE == type || TEXT_NODE == type
286N/A || NAMESPACE_NODE == type);
286N/A }
286N/A
286N/A _currentNode = node;
286N/A return returnNode(makeNodeHandle(node)); // make handle.
286N/A }
286N/A
286N/A /**
286N/A * Reset.
286N/A *
286N/A */
286N/A public DTMAxisIterator reset()
286N/A {
286N/A
286N/A final boolean temp = _isRestartable;
286N/A
286N/A _isRestartable = true;
286N/A
286N/A setStartNode(makeNodeHandle(_startNode));
286N/A
286N/A _isRestartable = temp;
286N/A
286N/A return this;
286N/A }
286N/A
286N/A } // end of DescendantIterator
286N/A
286N/A /**
286N/A * Typed iterator that returns the descendants of a given node.
286N/A */
286N/A public final class TypedDescendantIterator extends DescendantIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedDescendantIterator
286N/A *
286N/A *
286N/A * @param nodeType Extended type ID being requested.
286N/A */
286N/A public TypedDescendantIterator(int nodeType)
286N/A {
286N/A _nodeType = nodeType;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A final int startNode = _startNode;
286N/A if (_startNode == NULL) {
286N/A return NULL;
286N/A }
286N/A
286N/A int node = _currentNode;
286N/A
286N/A int expType;
286N/A final int nodeType = _nodeType;
286N/A
286N/A if (nodeType != DTM.ELEMENT_NODE)
286N/A {
286N/A do
286N/A {
286N/A node++;
286N/A expType = _exptype2(node);
286N/A
286N/A if (NULL == expType || _parent2(node) < startNode && startNode != node) {
286N/A _currentNode = NULL;
286N/A return END;
286N/A }
286N/A }
286N/A while (expType != nodeType);
286N/A }
286N/A // %OPT% If the start node is root (e.g. in the case of //node),
286N/A // we can save the isDescendant() check, because all nodes are
286N/A // descendants of root.
286N/A else if (startNode == DTMDefaultBase.ROOTNODE)
286N/A {
286N/A do
286N/A {
286N/A node++;
286N/A expType = _exptype2(node);
286N/A
286N/A if (NULL == expType) {
286N/A _currentNode = NULL;
286N/A return END;
286N/A }
286N/A } while (expType < DTM.NTYPES
286N/A || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
286N/A }
286N/A else
286N/A {
286N/A do
286N/A {
286N/A node++;
286N/A expType = _exptype2(node);
286N/A
286N/A if (NULL == expType || _parent2(node) < startNode && startNode != node) {
286N/A _currentNode = NULL;
286N/A return END;
286N/A }
286N/A }
286N/A while (expType < DTM.NTYPES
286N/A || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
286N/A }
286N/A
286N/A _currentNode = node;
286N/A return returnNode(makeNodeHandle(node));
286N/A }
286N/A } // end of TypedDescendantIterator
286N/A
286N/A /**
286N/A * Iterator that returns a given node only if it is of a given type.
286N/A */
286N/A public final class TypedSingletonIterator extends SingletonIterator
286N/A {
286N/A
286N/A /** The extended type ID that was requested. */
286N/A private final int _nodeType;
286N/A
286N/A /**
286N/A * Constructor TypedSingletonIterator
286N/A *
286N/A *
286N/A * @param nodeType The extended type ID being requested.
286N/A */
286N/A public TypedSingletonIterator(int nodeType)
286N/A {
286N/A _nodeType = nodeType;
286N/A }
286N/A
286N/A /**
286N/A * Get the next node in the iteration.
286N/A *
286N/A * @return The next node handle in the iteration, or END.
286N/A */
286N/A public int next()
286N/A {
286N/A
286N/A final int result = _currentNode;
286N/A if (result == END)
286N/A return DTM.NULL;
286N/A
286N/A _currentNode = END;
286N/A
286N/A if (_nodeType >= DTM.NTYPES) {
286N/A if (_exptype2(makeNodeIdentity(result)) == _nodeType) {
286N/A return returnNode(result);
286N/A }
286N/A }
286N/A else {
286N/A if (_type2(makeNodeIdentity(result)) == _nodeType) {
286N/A return returnNode(result);
286N/A }
286N/A }
286N/A
286N/A return NULL;
286N/A }
286N/A } // end of TypedSingletonIterator
286N/A
286N/A /*******************************************************************
286N/A * End of nested iterators
286N/A *******************************************************************/
286N/A
286N/A
286N/A // %OPT% Array references which are used to cache the map0 arrays in
286N/A // SuballocatedIntVectors. Using the cached arrays reduces the level
286N/A // of indirection and results in better performance than just calling
286N/A // SuballocatedIntVector.elementAt().
286N/A private int[] m_exptype_map0;
286N/A private int[] m_nextsib_map0;
286N/A private int[] m_firstch_map0;
286N/A private int[] m_parent_map0;
286N/A
286N/A // Double array references to the map arrays in SuballocatedIntVectors.
286N/A private int[][] m_exptype_map;
286N/A private int[][] m_nextsib_map;
286N/A private int[][] m_firstch_map;
286N/A private int[][] m_parent_map;
286N/A
286N/A // %OPT% Cache the array of extended types in this class
286N/A protected ExtendedType[] m_extendedTypes;
286N/A
286N/A // A Vector which is used to store the values of attribute, namespace,
286N/A // comment and PI nodes.
286N/A //
286N/A // %OPT% These values are unlikely to be equal. Storing
286N/A // them in a plain Vector is more efficient than storing in the
286N/A // DTMStringPool because we can save the cost for hash calculation.
286N/A //
286N/A // %REVISIT% Do we need a custom class (e.g. StringVector) here?
286N/A protected Vector m_values;
286N/A
286N/A // The current index into the m_values Vector.
286N/A private int m_valueIndex = 0;
286N/A
286N/A // The maximum value of the current node index.
286N/A private int m_maxNodeIndex;
286N/A
286N/A // Cache the shift and mask values for the SuballocatedIntVectors.
286N/A protected int m_SHIFT;
286N/A protected int m_MASK;
286N/A protected int m_blocksize;
286N/A
286N/A /** %OPT% If the offset and length of a Text node are within certain limits,
286N/A * we store a bitwise encoded value into an int, using 10 bits (max. 1024)
286N/A * for length and 21 bits for offset. We can save two SuballocatedIntVector
286N/A * calls for each getStringValueX() and dispatchCharacterEvents() call by
286N/A * doing this.
286N/A */
286N/A // The number of bits for the length of a Text node.
286N/A protected final static int TEXT_LENGTH_BITS = 10;
286N/A
286N/A // The number of bits for the offset of a Text node.
286N/A protected final static int TEXT_OFFSET_BITS = 21;
286N/A
286N/A // The maximum length value
286N/A protected final static int TEXT_LENGTH_MAX = (1<<TEXT_LENGTH_BITS) - 1;
286N/A
286N/A // The maximum offset value
286N/A protected final static int TEXT_OFFSET_MAX = (1<<TEXT_OFFSET_BITS) - 1;
286N/A
286N/A // True if we want to build the ID index table.
286N/A protected boolean m_buildIdIndex = true;
286N/A
286N/A // Constant for empty String
286N/A private static final String EMPTY_STR = "";
286N/A
286N/A // Constant for empty XMLString
286N/A private static final XMLString EMPTY_XML_STR = new XMLStringDefault("");
286N/A
286N/A /**
286N/A * Construct a SAX2DTM2 object using the default block size.
286N/A */
286N/A public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
286N/A DTMWSFilter whiteSpaceFilter,
286N/A XMLStringFactory xstringfactory,
286N/A boolean doIndexing)
286N/A {
286N/A
286N/A this(mgr, source, dtmIdentity, whiteSpaceFilter,
286N/A xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, true, false);
286N/A }
286N/A
286N/A /**
286N/A * Construct a SAX2DTM2 object using the given block size.
286N/A */
286N/A public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
286N/A DTMWSFilter whiteSpaceFilter,
286N/A XMLStringFactory xstringfactory,
286N/A boolean doIndexing,
286N/A int blocksize,
286N/A boolean usePrevsib,
286N/A boolean buildIdIndex,
286N/A boolean newNameTable)
286N/A {
286N/A
286N/A super(mgr, source, dtmIdentity, whiteSpaceFilter,
286N/A xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable);
286N/A
286N/A // Initialize the values of m_SHIFT and m_MASK.
286N/A int shift;
286N/A for(shift=0; (blocksize>>>=1) != 0; ++shift);
286N/A
286N/A m_blocksize = 1<<shift;
286N/A m_SHIFT = shift;
286N/A m_MASK = m_blocksize - 1;
286N/A
286N/A m_buildIdIndex = buildIdIndex;
286N/A
286N/A // Some documents do not have attribute nodes. That is why
286N/A // we set the initial size of this Vector to be small and set
286N/A // the increment to a bigger number.
286N/A m_values = new Vector(32, 512);
286N/A
286N/A m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS;
286N/A
286N/A // Set the map0 values in the constructor.
286N/A m_exptype_map0 = m_exptype.getMap0();
286N/A m_nextsib_map0 = m_nextsib.getMap0();
286N/A m_firstch_map0 = m_firstch.getMap0();
286N/A m_parent_map0 = m_parent.getMap0();
286N/A }
286N/A
286N/A /**
286N/A * Override DTMDefaultBase._exptype() by dropping the incremental code.
286N/A *
286N/A * <p>This one is less efficient than _exptype2. It is only used during
286N/A * DTM building. _exptype2 is used after the document is fully built.
286N/A */
286N/A public final int _exptype(int identity)
286N/A {
286N/A return m_exptype.elementAt(identity);
286N/A }
286N/A
286N/A /************************************************************************
286N/A * DTM base accessor interfaces
286N/A *
286N/A * %OPT% The code in the following interfaces (e.g. _exptype2, etc.) are
286N/A * very important to the DTM performance. To have the best performace,
286N/A * these several interfaces have direct access to the internal arrays of
286N/A * the SuballocatedIntVectors. The final modifier also has a noticeable
286N/A * impact on performance.
286N/A ***********************************************************************/
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase._exptype().
286N/A *
286N/A * @param identity A node identity, which <em>must not</em> be equal to
286N/A * <code>DTM.NULL</code>
286N/A */
286N/A public final int _exptype2(int identity)
286N/A {
286N/A //return m_exptype.elementAt(identity);
286N/A
286N/A if (identity < m_blocksize)
286N/A return m_exptype_map0[identity];
286N/A else
286N/A return m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase._nextsib().
286N/A *
286N/A * @param identity A node identity, which <em>must not</em> be equal to
286N/A * <code>DTM.NULL</code>
286N/A */
286N/A public final int _nextsib2(int identity)
286N/A {
286N/A //return m_nextsib.elementAt(identity);
286N/A
286N/A if (identity < m_blocksize)
286N/A return m_nextsib_map0[identity];
286N/A else
286N/A return m_nextsib_map[identity>>>m_SHIFT][identity&m_MASK];
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase._firstch().
286N/A *
286N/A * @param identity A node identity, which <em>must not</em> be equal to
286N/A * <code>DTM.NULL</code>
286N/A */
286N/A public final int _firstch2(int identity)
286N/A {
286N/A //return m_firstch.elementAt(identity);
286N/A
286N/A if (identity < m_blocksize)
286N/A return m_firstch_map0[identity];
286N/A else
286N/A return m_firstch_map[identity>>>m_SHIFT][identity&m_MASK];
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase._parent().
286N/A *
286N/A * @param identity A node identity, which <em>must not</em> be equal to
286N/A * <code>DTM.NULL</code>
286N/A */
286N/A public final int _parent2(int identity)
286N/A {
286N/A //return m_parent.elementAt(identity);
286N/A
286N/A if (identity < m_blocksize)
286N/A return m_parent_map0[identity];
286N/A else
286N/A return m_parent_map[identity>>>m_SHIFT][identity&m_MASK];
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase._type().
286N/A *
286N/A * @param identity A node identity, which <em>must not</em> be equal to
286N/A * <code>DTM.NULL</code>
286N/A */
286N/A public final int _type2(int identity)
286N/A {
286N/A //int eType = _exptype2(identity);
286N/A int eType;
286N/A if (identity < m_blocksize)
286N/A eType = m_exptype_map0[identity];
286N/A else
286N/A eType = m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
286N/A
286N/A if (NULL != eType)
286N/A return m_extendedTypes[eType].getNodeType();
286N/A else
286N/A return NULL;
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase.getExpandedTypeID(int).
286N/A *
286N/A * <p>This one is only used by DOMAdapter.getExpandedTypeID(int), which
286N/A * is mostly called from the compiled translets.
286N/A */
286N/A public final int getExpandedTypeID2(int nodeHandle)
286N/A {
286N/A int nodeID = makeNodeIdentity(nodeHandle);
286N/A
286N/A //return (nodeID != NULL) ? _exptype2(nodeID) : NULL;
286N/A
286N/A if (nodeID != NULL) {
286N/A if (nodeID < m_blocksize)
286N/A return m_exptype_map0[nodeID];
286N/A else
286N/A return m_exptype_map[nodeID>>>m_SHIFT][nodeID&m_MASK];
286N/A }
286N/A else
286N/A return NULL;
286N/A }
286N/A
286N/A /*************************************************************************
286N/A * END of DTM base accessor interfaces
286N/A *************************************************************************/
286N/A
286N/A
286N/A /**
286N/A * Return the node type from the expanded type
286N/A */
286N/A public final int _exptype2Type(int exptype)
286N/A {
286N/A if (NULL != exptype)
286N/A return m_extendedTypes[exptype].getNodeType();
286N/A else
286N/A return NULL;
286N/A }
286N/A
286N/A /**
286N/A * Get a prefix either from the uri mapping, or just make
286N/A * one up!
286N/A *
286N/A * @param uri The namespace URI, which may be null.
286N/A *
286N/A * @return The prefix if there is one, or null.
286N/A */
286N/A public int getIdForNamespace(String uri)
286N/A {
286N/A int index = m_values.indexOf(uri);
286N/A if (index < 0)
286N/A {
286N/A m_values.addElement(uri);
286N/A return m_valueIndex++;
286N/A }
286N/A else
286N/A return index;
286N/A }
286N/A
286N/A /**
286N/A * Override SAX2DTM.startElement()
286N/A *
286N/A * <p>Receive notification of the start of an element.
286N/A *
286N/A * <p>By default, do nothing. Application writers may override this
286N/A * method in a subclass to take specific actions at the start of
286N/A * each element (such as allocating a new tree node or writing
286N/A * output to a file).</p>
286N/A *
286N/A * @param uri The Namespace URI, or the empty string if the
286N/A * element has no Namespace URI or if Namespace
286N/A * processing is not being performed.
286N/A * @param localName The local name (without prefix), or the
286N/A * empty string if Namespace processing is not being
286N/A * performed.
286N/A * @param qName The qualified name (with prefix), or the
286N/A * empty string if qualified names are not available.
286N/A * @param attributes The specified or defaulted attributes.
286N/A * @throws SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A * @see org.xml.sax.ContentHandler#startElement
286N/A */
286N/A public void startElement(String uri, String localName, String qName, Attributes attributes)
286N/A throws SAXException
286N/A {
286N/A
286N/A charactersFlush();
286N/A
286N/A int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE);
286N/A
286N/A int prefixIndex = (qName.length() != localName.length())
286N/A ? m_valuesOrPrefixes.stringToIndex(qName) : 0;
286N/A
286N/A int elemNode = addNode(DTM.ELEMENT_NODE, exName,
286N/A m_parents.peek(), m_previous, prefixIndex, true);
286N/A
286N/A if(m_indexing)
286N/A indexNode(exName, elemNode);
286N/A
286N/A m_parents.push(elemNode);
286N/A
286N/A int startDecls = m_contextIndexes.peek();
286N/A int nDecls = m_prefixMappings.size();
286N/A String prefix;
286N/A
286N/A if(!m_pastFirstElement)
286N/A {
286N/A // SPECIAL CASE: Implied declaration at root element
286N/A prefix="xml";
286N/A String declURL = "http://www.w3.org/XML/1998/namespace";
286N/A exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
286N/A m_values.addElement(declURL);
286N/A int val = m_valueIndex++;
286N/A addNode(DTM.NAMESPACE_NODE, exName, elemNode,
286N/A DTM.NULL, val, false);
286N/A m_pastFirstElement=true;
286N/A }
286N/A
286N/A for (int i = startDecls; i < nDecls; i += 2)
286N/A {
286N/A prefix = (String) m_prefixMappings.elementAt(i);
286N/A
286N/A if (prefix == null)
286N/A continue;
286N/A
286N/A String declURL = (String) m_prefixMappings.elementAt(i + 1);
286N/A
286N/A exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
286N/A
286N/A m_values.addElement(declURL);
286N/A int val = m_valueIndex++;
286N/A
286N/A addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false);
286N/A }
286N/A
286N/A int n = attributes.getLength();
286N/A
286N/A for (int i = 0; i < n; i++)
286N/A {
286N/A String attrUri = attributes.getURI(i);
286N/A String attrQName = attributes.getQName(i);
286N/A String valString = attributes.getValue(i);
286N/A
286N/A int nodeType;
286N/A
286N/A String attrLocalName = attributes.getLocalName(i);
286N/A
286N/A if ((null != attrQName)
286N/A && (attrQName.equals("xmlns")
286N/A || attrQName.startsWith("xmlns:")))
286N/A {
286N/A prefix = getPrefix(attrQName, attrUri);
286N/A if (declAlreadyDeclared(prefix))
286N/A continue; // go to the next attribute.
286N/A
286N/A nodeType = DTM.NAMESPACE_NODE;
286N/A }
286N/A else
286N/A {
286N/A nodeType = DTM.ATTRIBUTE_NODE;
286N/A
286N/A if (m_buildIdIndex && attributes.getType(i).equalsIgnoreCase("ID"))
286N/A setIDAttribute(valString, elemNode);
286N/A }
286N/A
286N/A // Bit of a hack... if somehow valString is null, stringToIndex will
286N/A // return -1, which will make things very unhappy.
286N/A if(null == valString)
286N/A valString = "";
286N/A
286N/A m_values.addElement(valString);
286N/A int val = m_valueIndex++;
286N/A
286N/A if (attrLocalName.length() != attrQName.length())
286N/A {
286N/A
286N/A prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName);
286N/A
286N/A int dataIndex = m_data.size();
286N/A
286N/A m_data.addElement(prefixIndex);
286N/A m_data.addElement(val);
286N/A
286N/A val = -dataIndex;
286N/A }
286N/A
286N/A exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType);
286N/A addNode(nodeType, exName, elemNode, DTM.NULL, val,
286N/A false);
286N/A }
286N/A
286N/A if (null != m_wsfilter)
286N/A {
286N/A short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this);
286N/A boolean shouldStrip = (DTMWSFilter.INHERIT == wsv)
286N/A ? getShouldStripWhitespace()
286N/A : (DTMWSFilter.STRIP == wsv);
286N/A
286N/A pushShouldStripWhitespace(shouldStrip);
286N/A }
286N/A
286N/A m_previous = DTM.NULL;
286N/A
286N/A m_contextIndexes.push(m_prefixMappings.size()); // for the children.
286N/A }
286N/A
286N/A /**
286N/A * Receive notification of the end of an element.
286N/A *
286N/A * <p>By default, do nothing. Application writers may override this
286N/A * method in a subclass to take specific actions at the end of
286N/A * each element (such as finalising a tree node or writing
286N/A * output to a file).</p>
286N/A *
286N/A * @param uri The Namespace URI, or the empty string if the
286N/A * element has no Namespace URI or if Namespace
286N/A * processing is not being performed.
286N/A * @param localName The local name (without prefix), or the
286N/A * empty string if Namespace processing is not being
286N/A * performed.
286N/A * @param qName The qualified XML 1.0 name (with prefix), or the
286N/A * empty string if qualified names are not available.
286N/A * @throws SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A * @see org.xml.sax.ContentHandler#endElement
286N/A */
286N/A public void endElement(String uri, String localName, String qName)
286N/A throws SAXException
286N/A {
286N/A charactersFlush();
286N/A
286N/A // If no one noticed, startPrefixMapping is a drag.
286N/A // Pop the context for the last child (the one pushed by startElement)
286N/A m_contextIndexes.quickPop(1);
286N/A
286N/A // Do it again for this one (the one pushed by the last endElement).
286N/A int topContextIndex = m_contextIndexes.peek();
286N/A if (topContextIndex != m_prefixMappings.size()) {
286N/A m_prefixMappings.setSize(topContextIndex);
286N/A }
286N/A
286N/A m_previous = m_parents.pop();
286N/A
286N/A popShouldStripWhitespace();
286N/A }
286N/A
286N/A /**
286N/A * Report an XML comment anywhere in the document.
286N/A *
286N/A * <p>This callback will be used for comments inside or outside the
286N/A * document element, including comments in the external DTD
286N/A * subset (if read).</p>
286N/A *
286N/A * @param ch An array holding the characters in the comment.
286N/A * @param start The starting position in the array.
286N/A * @param length The number of characters to use from the array.
286N/A * @throws SAXException The application may raise an exception.
286N/A */
286N/A public void comment(char ch[], int start, int length) throws SAXException
286N/A {
286N/A
286N/A if (m_insideDTD) // ignore comments if we're inside the DTD
286N/A return;
286N/A
286N/A charactersFlush();
286N/A
286N/A // %OPT% Saving the comment string in a Vector has a lower cost than
286N/A // saving it in DTMStringPool.
286N/A m_values.addElement(new String(ch, start, length));
286N/A int dataIndex = m_valueIndex++;
286N/A
286N/A m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE,
286N/A m_parents.peek(), m_previous, dataIndex, false);
286N/A }
286N/A
286N/A /**
286N/A * Receive notification of the beginning of the document.
286N/A *
286N/A * @throws SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A * @see org.xml.sax.ContentHandler#startDocument
286N/A */
286N/A public void startDocument() throws SAXException
286N/A {
286N/A
286N/A int doc = addNode(DTM.DOCUMENT_NODE,
286N/A DTM.DOCUMENT_NODE,
286N/A DTM.NULL, DTM.NULL, 0, true);
286N/A
286N/A m_parents.push(doc);
286N/A m_previous = DTM.NULL;
286N/A
286N/A m_contextIndexes.push(m_prefixMappings.size()); // for the next element.
286N/A }
286N/A
286N/A /**
286N/A * Receive notification of the end of the document.
286N/A *
286N/A * @throws SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A * @see org.xml.sax.ContentHandler#endDocument
286N/A */
286N/A public void endDocument() throws SAXException
286N/A {
286N/A super.endDocument();
286N/A
286N/A // Add a NULL entry to the end of the node arrays as
286N/A // the end indication.
286N/A m_exptype.addElement(NULL);
286N/A m_parent.addElement(NULL);
286N/A m_nextsib.addElement(NULL);
286N/A m_firstch.addElement(NULL);
286N/A
286N/A // Set the cached references after the document is built.
286N/A m_extendedTypes = m_expandedNameTable.getExtendedTypes();
286N/A m_exptype_map = m_exptype.getMap();
286N/A m_nextsib_map = m_nextsib.getMap();
286N/A m_firstch_map = m_firstch.getMap();
286N/A m_parent_map = m_parent.getMap();
286N/A }
286N/A
286N/A /**
286N/A * Construct the node map from the node.
286N/A *
286N/A * @param type raw type ID, one of DTM.XXX_NODE.
286N/A * @param expandedTypeID The expended type ID.
286N/A * @param parentIndex The current parent index.
286N/A * @param previousSibling The previous sibling index.
286N/A * @param dataOrPrefix index into m_data table, or string handle.
286N/A * @param canHaveFirstChild true if the node can have a first child, false
286N/A * if it is atomic.
286N/A *
286N/A * @return The index identity of the node that was added.
286N/A */
286N/A protected final int addNode(int type, int expandedTypeID,
286N/A int parentIndex, int previousSibling,
286N/A int dataOrPrefix, boolean canHaveFirstChild)
286N/A {
286N/A // Common to all nodes:
286N/A int nodeIndex = m_size++;
286N/A
286N/A // Have we overflowed a DTM Identity's addressing range?
286N/A //if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
286N/A if (nodeIndex == m_maxNodeIndex)
286N/A {
286N/A addNewDTMID(nodeIndex);
286N/A m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
286N/A }
286N/A
286N/A m_firstch.addElement(DTM.NULL);
286N/A m_nextsib.addElement(DTM.NULL);
286N/A m_parent.addElement(parentIndex);
286N/A m_exptype.addElement(expandedTypeID);
286N/A m_dataOrQName.addElement(dataOrPrefix);
286N/A
286N/A if (m_prevsib != null) {
286N/A m_prevsib.addElement(previousSibling);
286N/A }
286N/A
286N/A if (m_locator != null && m_useSourceLocationProperty) {
286N/A setSourceLocation();
286N/A }
286N/A
286N/A // Note that nextSibling is not processed until charactersFlush()
286N/A // is called, to handle successive characters() events.
286N/A
286N/A // Special handling by type: Declare namespaces, attach first child
286N/A switch(type)
286N/A {
286N/A case DTM.NAMESPACE_NODE:
286N/A declareNamespaceInContext(parentIndex,nodeIndex);
286N/A break;
286N/A case DTM.ATTRIBUTE_NODE:
286N/A break;
286N/A default:
286N/A if (DTM.NULL != previousSibling) {
286N/A m_nextsib.setElementAt(nodeIndex,previousSibling);
286N/A }
286N/A else if (DTM.NULL != parentIndex) {
286N/A m_firstch.setElementAt(nodeIndex,parentIndex);
286N/A }
286N/A break;
286N/A }
286N/A
286N/A return nodeIndex;
286N/A }
286N/A
286N/A /**
286N/A * Check whether accumulated text should be stripped; if not,
286N/A * append the appropriate flavor of text/cdata node.
286N/A */
286N/A protected final void charactersFlush()
286N/A {
286N/A
286N/A if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress
286N/A {
286N/A int length = m_chars.size() - m_textPendingStart;
286N/A boolean doStrip = false;
286N/A
286N/A if (getShouldStripWhitespace())
286N/A {
286N/A doStrip = m_chars.isWhitespace(m_textPendingStart, length);
286N/A }
286N/A
286N/A if (doStrip) {
286N/A m_chars.setLength(m_textPendingStart); // Discard accumulated text
286N/A } else {
286N/A // Guard against characters/ignorableWhitespace events that
286N/A // contained no characters. They should not result in a node.
286N/A if (length > 0) {
286N/A // If the offset and length do not exceed the given limits
286N/A // (offset < 2^21 and length < 2^10), then save both the offset
286N/A // and length in a bitwise encoded value.
286N/A if (length <= TEXT_LENGTH_MAX
286N/A && m_textPendingStart <= TEXT_OFFSET_MAX) {
286N/A m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
286N/A m_parents.peek(), m_previous,
286N/A length + (m_textPendingStart << TEXT_LENGTH_BITS),
286N/A false);
286N/A
286N/A } else {
286N/A // Store offset and length in the m_data array if one exceeds
286N/A // the given limits. Use a negative dataIndex as an indication.
286N/A int dataIndex = m_data.size();
286N/A m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
286N/A m_parents.peek(), m_previous, -dataIndex, false);
286N/A
286N/A m_data.addElement(m_textPendingStart);
286N/A m_data.addElement(length);
286N/A }
286N/A }
286N/A }
286N/A
286N/A // Reset for next text block
286N/A m_textPendingStart = -1;
286N/A m_textType = m_coalescedTextType = DTM.TEXT_NODE;
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Override the processingInstruction() interface in SAX2DTM2.
286N/A * <p>
286N/A * %OPT% This one is different from SAX2DTM.processingInstruction()
286N/A * in that we do not use extended types for PI nodes. The name of
286N/A * the PI is saved in the DTMStringPool.
286N/A *
286N/A * Receive notification of a processing instruction.
286N/A *
286N/A * @param target The processing instruction target.
286N/A * @param data The processing instruction data, or null if
286N/A * none is supplied.
286N/A * @throws SAXException Any SAX exception, possibly
286N/A * wrapping another exception.
286N/A * @see org.xml.sax.ContentHandler#processingInstruction
286N/A */
286N/A public void processingInstruction(String target, String data)
286N/A throws SAXException
286N/A {
286N/A
286N/A charactersFlush();
286N/A
286N/A int dataIndex = m_data.size();
286N/A m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE,
286N/A DTM.PROCESSING_INSTRUCTION_NODE,
286N/A m_parents.peek(), m_previous,
286N/A -dataIndex, false);
286N/A
286N/A m_data.addElement(m_valuesOrPrefixes.stringToIndex(target));
286N/A m_values.addElement(data);
286N/A m_data.addElement(m_valueIndex++);
286N/A
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase.getFirstAttribute().
286N/A * <p>
286N/A * Given a node handle, get the index of the node's first attribute.
286N/A *
286N/A * @param nodeHandle int Handle of the node.
286N/A * @return Handle of first attribute, or DTM.NULL to indicate none exists.
286N/A */
286N/A public final int getFirstAttribute(int nodeHandle)
286N/A {
286N/A int nodeID = makeNodeIdentity(nodeHandle);
286N/A
286N/A if (nodeID == DTM.NULL)
286N/A return DTM.NULL;
286N/A
286N/A int type = _type2(nodeID);
286N/A
286N/A if (DTM.ELEMENT_NODE == type)
286N/A {
286N/A // Assume that attributes and namespaces immediately follow the element.
286N/A while (true)
286N/A {
286N/A nodeID++;
286N/A // Assume this can not be null.
286N/A type = _type2(nodeID);
286N/A
286N/A if (type == DTM.ATTRIBUTE_NODE)
286N/A {
286N/A return makeNodeHandle(nodeID);
286N/A }
286N/A else if (DTM.NAMESPACE_NODE != type)
286N/A {
286N/A break;
286N/A }
286N/A }
286N/A }
286N/A
286N/A return DTM.NULL;
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
286N/A * <p>
286N/A * Given a node identity, get the index of the node's first attribute.
286N/A *
286N/A * @param identity int identity of the node.
286N/A * @return Identity of first attribute, or DTM.NULL to indicate none exists.
286N/A */
286N/A protected int getFirstAttributeIdentity(int identity) {
286N/A if (identity == NULL) {
286N/A return NULL;
286N/A }
286N/A int type = _type2(identity);
286N/A
286N/A if (DTM.ELEMENT_NODE == type)
286N/A {
286N/A // Assume that attributes and namespaces immediately follow the element.
286N/A while (true)
286N/A {
286N/A identity++;
286N/A
286N/A // Assume this can not be null.
286N/A type = _type2(identity);
286N/A
286N/A if (type == DTM.ATTRIBUTE_NODE)
286N/A {
286N/A return identity;
286N/A }
286N/A else if (DTM.NAMESPACE_NODE != type)
286N/A {
286N/A break;
286N/A }
286N/A }
286N/A }
286N/A
286N/A return DTM.NULL;
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
286N/A * <p>
286N/A * Given a node identity for an attribute, advance to the next attribute.
286N/A *
286N/A * @param identity int identity of the attribute node. This
286N/A * <strong>must</strong> be an attribute node.
286N/A *
286N/A * @return int DTM node-identity of the resolved attr,
286N/A * or DTM.NULL to indicate none exists.
286N/A *
286N/A */
286N/A protected int getNextAttributeIdentity(int identity) {
286N/A // Assume that attributes and namespace nodes immediately follow the element
286N/A while (true) {
286N/A identity++;
286N/A int type = _type2(identity);
286N/A
286N/A if (type == DTM.ATTRIBUTE_NODE) {
286N/A return identity;
286N/A } else if (type != DTM.NAMESPACE_NODE) {
286N/A break;
286N/A }
286N/A }
286N/A
286N/A return DTM.NULL;
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
286N/A * <p>
286N/A * Given a node handle and an expanded type ID, get the index of the node's
286N/A * attribute of that type, if any.
286N/A *
286N/A * @param nodeHandle int Handle of the node.
286N/A * @param attType int expanded type ID of the required attribute.
286N/A * @return Handle of attribute of the required type, or DTM.NULL to indicate
286N/A * none exists.
286N/A */
286N/A protected final int getTypedAttribute(int nodeHandle, int attType)
286N/A {
286N/A
286N/A int nodeID = makeNodeIdentity(nodeHandle);
286N/A
286N/A if (nodeID == DTM.NULL)
286N/A return DTM.NULL;
286N/A
286N/A int type = _type2(nodeID);
286N/A
286N/A if (DTM.ELEMENT_NODE == type)
286N/A {
286N/A int expType;
286N/A while (true)
286N/A {
286N/A nodeID++;
286N/A expType = _exptype2(nodeID);
286N/A
286N/A if (expType != DTM.NULL)
286N/A type = m_extendedTypes[expType].getNodeType();
286N/A else
286N/A return DTM.NULL;
286N/A
286N/A if (type == DTM.ATTRIBUTE_NODE)
286N/A {
286N/A if (expType == attType) return makeNodeHandle(nodeID);
286N/A }
286N/A else if (DTM.NAMESPACE_NODE != type)
286N/A {
286N/A break;
286N/A }
286N/A }
286N/A }
286N/A
286N/A return DTM.NULL;
286N/A }
286N/A
286N/A /**
286N/A * Override SAX2DTM.getLocalName() in SAX2DTM2.
286N/A * <p>Processing for PIs is different.
286N/A *
286N/A * Given a node handle, return its XPath- style localname. (As defined in
286N/A * Namespaces, this is the portion of the name after any colon character).
286N/A *
286N/A * @param nodeHandle the id of the node.
286N/A * @return String Local name of this node.
286N/A */
286N/A public String getLocalName(int nodeHandle)
286N/A {
286N/A int expType = _exptype(makeNodeIdentity(nodeHandle));
286N/A
286N/A if (expType == DTM.PROCESSING_INSTRUCTION_NODE)
286N/A {
286N/A int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle));
286N/A dataIndex = m_data.elementAt(-dataIndex);
286N/A return m_valuesOrPrefixes.indexToString(dataIndex);
286N/A }
286N/A else
286N/A return m_expandedNameTable.getLocalName(expType);
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of SAX2DTM.getNodeNameX().
286N/A * <p>
286N/A * Given a node handle, return the XPath node name. This should be the name
286N/A * as described by the XPath data model, NOT the DOM- style name.
286N/A *
286N/A * @param nodeHandle the id of the node.
286N/A * @return String Name of this node, which may be an empty string.
286N/A */
286N/A public final String getNodeNameX(int nodeHandle)
286N/A {
286N/A
286N/A int nodeID = makeNodeIdentity(nodeHandle);
286N/A int eType = _exptype2(nodeID);
286N/A
286N/A if (eType == DTM.PROCESSING_INSTRUCTION_NODE)
286N/A {
286N/A int dataIndex = _dataOrQName(nodeID);
286N/A dataIndex = m_data.elementAt(-dataIndex);
286N/A return m_valuesOrPrefixes.indexToString(dataIndex);
286N/A }
286N/A
286N/A final ExtendedType extType = m_extendedTypes[eType];
286N/A
286N/A if (extType.getNamespace().length() == 0)
286N/A {
286N/A return extType.getLocalName();
286N/A }
286N/A else
286N/A {
286N/A int qnameIndex = m_dataOrQName.elementAt(nodeID);
286N/A
286N/A if (qnameIndex == 0)
286N/A return extType.getLocalName();
286N/A
286N/A if (qnameIndex < 0)
286N/A {
286N/A qnameIndex = -qnameIndex;
286N/A qnameIndex = m_data.elementAt(qnameIndex);
286N/A }
286N/A
286N/A return m_valuesOrPrefixes.indexToString(qnameIndex);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of SAX2DTM.getNodeName().
286N/A * <p>
286N/A * Given a node handle, return its DOM-style node name. This will include
286N/A * names such as #text or #document.
286N/A *
286N/A * @param nodeHandle the id of the node.
286N/A * @return String Name of this node, which may be an empty string.
286N/A * %REVIEW% Document when empty string is possible...
286N/A * %REVIEW-COMMENT% It should never be empty, should it?
286N/A */
286N/A public String getNodeName(int nodeHandle)
286N/A {
286N/A
286N/A int nodeID = makeNodeIdentity(nodeHandle);
286N/A int eType = _exptype2(nodeID);
286N/A
286N/A final ExtendedType extType = m_extendedTypes[eType];
286N/A if (extType.getNamespace().length() == 0)
286N/A {
286N/A int type = extType.getNodeType();
286N/A
286N/A String localName = extType.getLocalName();
286N/A if (type == DTM.NAMESPACE_NODE)
286N/A {
286N/A if (localName.length() == 0)
286N/A return "xmlns";
286N/A else
286N/A return "xmlns:" + localName;
286N/A }
286N/A else if (type == DTM.PROCESSING_INSTRUCTION_NODE)
286N/A {
286N/A int dataIndex = _dataOrQName(nodeID);
286N/A dataIndex = m_data.elementAt(-dataIndex);
286N/A return m_valuesOrPrefixes.indexToString(dataIndex);
286N/A }
286N/A else if (localName.length() == 0)
286N/A {
286N/A return getFixedNames(type);
286N/A }
286N/A else
286N/A return localName;
286N/A }
286N/A else
286N/A {
286N/A int qnameIndex = m_dataOrQName.elementAt(nodeID);
286N/A
286N/A if (qnameIndex == 0)
286N/A return extType.getLocalName();
286N/A
286N/A if (qnameIndex < 0)
286N/A {
286N/A qnameIndex = -qnameIndex;
286N/A qnameIndex = m_data.elementAt(qnameIndex);
286N/A }
286N/A
286N/A return m_valuesOrPrefixes.indexToString(qnameIndex);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Override SAX2DTM.getStringValue(int)
286N/A * <p>
286N/A * This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
286N/A * <p>
286N/A * If the caller supplies an XMLStringFactory, the getStringValue() interface
286N/A * in SAX2DTM will be called. Otherwise just calls getStringValueX() and
286N/A * wraps the returned String in an XMLString.
286N/A *
286N/A * Get the string-value of a node as a String object
286N/A * (see http://www.w3.org/TR/xpath#data-model
286N/A * for the definition of a node's string-value).
286N/A *
286N/A * @param nodeHandle The node ID.
286N/A *
286N/A * @return A string object that represents the string-value of the given node.
286N/A */
286N/A public XMLString getStringValue(int nodeHandle)
286N/A {
286N/A int identity = makeNodeIdentity(nodeHandle);
286N/A if (identity == DTM.NULL)
286N/A return EMPTY_XML_STR;
286N/A
286N/A int type= _type2(identity);
286N/A
286N/A if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
286N/A {
286N/A int startNode = identity;
286N/A identity = _firstch2(identity);
286N/A if (DTM.NULL != identity)
286N/A {
286N/A int offset = -1;
286N/A int length = 0;
286N/A
286N/A do
286N/A {
286N/A type = _exptype2(identity);
286N/A
286N/A if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A if (dataIndex >= 0)
286N/A {
286N/A if (-1 == offset)
286N/A {
286N/A offset = dataIndex >>> TEXT_LENGTH_BITS;
286N/A }
286N/A
286N/A length += dataIndex & TEXT_LENGTH_MAX;
286N/A }
286N/A else
286N/A {
286N/A if (-1 == offset)
286N/A {
286N/A offset = m_data.elementAt(-dataIndex);
286N/A }
286N/A
286N/A length += m_data.elementAt(-dataIndex + 1);
286N/A }
286N/A }
286N/A
286N/A identity++;
286N/A } while (_parent2(identity) >= startNode);
286N/A
286N/A if (length > 0)
286N/A {
286N/A if (m_xstrf != null)
286N/A return m_xstrf.newstr(m_chars, offset, length);
286N/A else
286N/A return new XMLStringDefault(m_chars.getString(offset, length));
286N/A }
286N/A else
286N/A return EMPTY_XML_STR;
286N/A }
286N/A else
286N/A return EMPTY_XML_STR;
286N/A }
286N/A else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A if (dataIndex >= 0)
286N/A {
286N/A if (m_xstrf != null)
286N/A return m_xstrf.newstr(m_chars, dataIndex >>> TEXT_LENGTH_BITS,
286N/A dataIndex & TEXT_LENGTH_MAX);
286N/A else
286N/A return new XMLStringDefault(m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
286N/A dataIndex & TEXT_LENGTH_MAX));
286N/A }
286N/A else
286N/A {
286N/A if (m_xstrf != null)
286N/A return m_xstrf.newstr(m_chars, m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex+1));
286N/A else
286N/A return new XMLStringDefault(m_chars.getString(m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex+1)));
286N/A }
286N/A }
286N/A else
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A
286N/A if (dataIndex < 0)
286N/A {
286N/A dataIndex = -dataIndex;
286N/A dataIndex = m_data.elementAt(dataIndex + 1);
286N/A }
286N/A
286N/A if (m_xstrf != null)
286N/A return m_xstrf.newstr((String)m_values.elementAt(dataIndex));
286N/A else
286N/A return new XMLStringDefault((String)m_values.elementAt(dataIndex));
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of SAX2DTM.getStringValue(int).
286N/A * <p>
286N/A * %OPT% This is one of the most often used interfaces. Performance is
286N/A * critical here. This one is different from SAX2DTM.getStringValue(int) in
286N/A * that it returns a String instead of a XMLString.
286N/A *
286N/A * Get the string- value of a node as a String object (see http: //www. w3.
286N/A * org/TR/xpath#data- model for the definition of a node's string- value).
286N/A *
286N/A * @param nodeHandle The node ID.
286N/A *
286N/A * @return A string object that represents the string-value of the given node.
286N/A */
286N/A public final String getStringValueX(final int nodeHandle)
286N/A {
286N/A int identity = makeNodeIdentity(nodeHandle);
286N/A if (identity == DTM.NULL)
286N/A return EMPTY_STR;
286N/A
286N/A int type= _type2(identity);
286N/A
286N/A if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
286N/A {
286N/A int startNode = identity;
286N/A identity = _firstch2(identity);
286N/A if (DTM.NULL != identity)
286N/A {
286N/A int offset = -1;
286N/A int length = 0;
286N/A
286N/A do
286N/A {
286N/A type = _exptype2(identity);
286N/A
286N/A if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A if (dataIndex >= 0)
286N/A {
286N/A if (-1 == offset)
286N/A {
286N/A offset = dataIndex >>> TEXT_LENGTH_BITS;
286N/A }
286N/A
286N/A length += dataIndex & TEXT_LENGTH_MAX;
286N/A }
286N/A else
286N/A {
286N/A if (-1 == offset)
286N/A {
286N/A offset = m_data.elementAt(-dataIndex);
286N/A }
286N/A
286N/A length += m_data.elementAt(-dataIndex + 1);
286N/A }
286N/A }
286N/A
286N/A identity++;
286N/A } while (_parent2(identity) >= startNode);
286N/A
286N/A if (length > 0)
286N/A {
286N/A return m_chars.getString(offset, length);
286N/A }
286N/A else
286N/A return EMPTY_STR;
286N/A }
286N/A else
286N/A return EMPTY_STR;
286N/A }
286N/A else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A if (dataIndex >= 0)
286N/A {
286N/A return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
286N/A dataIndex & TEXT_LENGTH_MAX);
286N/A }
286N/A else
286N/A {
286N/A return m_chars.getString(m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex+1));
286N/A }
286N/A }
286N/A else
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A
286N/A if (dataIndex < 0)
286N/A {
286N/A dataIndex = -dataIndex;
286N/A dataIndex = m_data.elementAt(dataIndex + 1);
286N/A }
286N/A
286N/A return (String)m_values.elementAt(dataIndex);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Returns the string value of the entire tree
286N/A */
286N/A public String getStringValue()
286N/A {
286N/A int child = _firstch2(ROOTNODE);
286N/A if (child == DTM.NULL) return EMPTY_STR;
286N/A
286N/A // optimization: only create StringBuffer if > 1 child
286N/A if ((_exptype2(child) == DTM.TEXT_NODE) && (_nextsib2(child) == DTM.NULL))
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(child);
286N/A if (dataIndex >= 0)
286N/A return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, dataIndex & TEXT_LENGTH_MAX);
286N/A else
286N/A return m_chars.getString(m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex + 1));
286N/A }
286N/A else
286N/A return getStringValueX(getDocument());
286N/A
286N/A }
286N/A
286N/A /**
286N/A * The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
286N/A * <p>
286N/A * Directly call the
286N/A * characters method on the passed ContentHandler for the
286N/A * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
286N/A * for the definition of a node's string-value). Multiple calls to the
286N/A * ContentHandler's characters methods may well occur for a single call to
286N/A * this method.
286N/A *
286N/A * @param nodeHandle The node ID.
286N/A * @param ch A non-null reference to a ContentHandler.
286N/A * @param normalize true if the content should be normalized according to
286N/A * the rules for the XPath
286N/A * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
286N/A * function.
286N/A *
286N/A * @throws SAXException
286N/A */
286N/A public final void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
286N/A boolean normalize)
286N/A throws SAXException
286N/A {
286N/A
286N/A int identity = makeNodeIdentity(nodeHandle);
286N/A
286N/A if (identity == DTM.NULL)
286N/A return;
286N/A
286N/A int type = _type2(identity);
286N/A
286N/A if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
286N/A {
286N/A int startNode = identity;
286N/A identity = _firstch2(identity);
286N/A if (DTM.NULL != identity)
286N/A {
286N/A int offset = -1;
286N/A int length = 0;
286N/A
286N/A do
286N/A {
286N/A type = _exptype2(identity);
286N/A
286N/A if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A
286N/A if (dataIndex >= 0)
286N/A {
286N/A if (-1 == offset)
286N/A {
286N/A offset = dataIndex >>> TEXT_LENGTH_BITS;
286N/A }
286N/A
286N/A length += dataIndex & TEXT_LENGTH_MAX;
286N/A }
286N/A else
286N/A {
286N/A if (-1 == offset)
286N/A {
286N/A offset = m_data.elementAt(-dataIndex);
286N/A }
286N/A
286N/A length += m_data.elementAt(-dataIndex + 1);
286N/A }
286N/A }
286N/A
286N/A identity++;
286N/A } while (_parent2(identity) >= startNode);
286N/A
286N/A if (length > 0)
286N/A {
286N/A if(normalize)
286N/A m_chars.sendNormalizedSAXcharacters(ch, offset, length);
286N/A else
286N/A m_chars.sendSAXcharacters(ch, offset, length);
286N/A }
286N/A }
286N/A }
286N/A else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A
286N/A if (dataIndex >= 0)
286N/A {
286N/A if (normalize)
286N/A m_chars.sendNormalizedSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
286N/A dataIndex & TEXT_LENGTH_MAX);
286N/A else
286N/A m_chars.sendSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
286N/A dataIndex & TEXT_LENGTH_MAX);
286N/A }
286N/A else
286N/A {
286N/A if (normalize)
286N/A m_chars.sendNormalizedSAXcharacters(ch, m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex+1));
286N/A else
286N/A m_chars.sendSAXcharacters(ch, m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex+1));
286N/A }
286N/A }
286N/A else
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A
286N/A if (dataIndex < 0)
286N/A {
286N/A dataIndex = -dataIndex;
286N/A dataIndex = m_data.elementAt(dataIndex + 1);
286N/A }
286N/A
286N/A String str = (String)m_values.elementAt(dataIndex);
286N/A
286N/A if(normalize)
286N/A FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(),
286N/A 0, str.length(), ch);
286N/A else
286N/A ch.characters(str.toCharArray(), 0, str.length());
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Given a node handle, return its node value. This is mostly
286N/A * as defined by the DOM, but may ignore some conveniences.
286N/A * <p>
286N/A *
286N/A * @param nodeHandle The node id.
286N/A * @return String Value of this node, or null if not
286N/A * meaningful for this node type.
286N/A */
286N/A public String getNodeValue(int nodeHandle)
286N/A {
286N/A
286N/A int identity = makeNodeIdentity(nodeHandle);
286N/A int type = _type2(identity);
286N/A
286N/A if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
286N/A {
286N/A int dataIndex = _dataOrQName(identity);
286N/A if (dataIndex > 0)
286N/A {
286N/A return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
286N/A dataIndex & TEXT_LENGTH_MAX);
286N/A }
286N/A else
286N/A {
286N/A return m_chars.getString(m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex+1));
286N/A }
286N/A }
286N/A else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
286N/A || DTM.DOCUMENT_NODE == type)
286N/A {
286N/A return null;
286N/A }
286N/A else
286N/A {
286N/A int dataIndex = m_dataOrQName.elementAt(identity);
286N/A
286N/A if (dataIndex < 0)
286N/A {
286N/A dataIndex = -dataIndex;
286N/A dataIndex = m_data.elementAt(dataIndex + 1);
286N/A }
286N/A
286N/A return (String)m_values.elementAt(dataIndex);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Copy the String value of a Text node to a SerializationHandler
286N/A */
286N/A protected final void copyTextNode(final int nodeID, SerializationHandler handler)
286N/A throws SAXException
286N/A {
286N/A if (nodeID != DTM.NULL) {
286N/A int dataIndex = m_dataOrQName.elementAt(nodeID);
286N/A if (dataIndex >= 0) {
286N/A m_chars.sendSAXcharacters(handler,
286N/A dataIndex >>> TEXT_LENGTH_BITS,
286N/A dataIndex & TEXT_LENGTH_MAX);
286N/A } else {
286N/A m_chars.sendSAXcharacters(handler, m_data.elementAt(-dataIndex),
286N/A m_data.elementAt(-dataIndex+1));
286N/A }
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Copy an Element node to a SerializationHandler.
286N/A *
286N/A * @param nodeID The node identity
286N/A * @param exptype The expanded type of the Element node
286N/A * @param handler The SerializationHandler
286N/A * @return The qualified name of the Element node.
286N/A */
286N/A protected final String copyElement(int nodeID, int exptype,
286N/A SerializationHandler handler)
286N/A throws SAXException
286N/A {
286N/A final ExtendedType extType = m_extendedTypes[exptype];
286N/A String uri = extType.getNamespace();
286N/A String name = extType.getLocalName();
286N/A
286N/A if (uri.length() == 0) {
286N/A handler.startElement(name);
286N/A return name;
286N/A }
286N/A else {
286N/A int qnameIndex = m_dataOrQName.elementAt(nodeID);
286N/A
286N/A if (qnameIndex == 0) {
286N/A handler.startElement(name);
286N/A handler.namespaceAfterStartElement(EMPTY_STR, uri);
286N/A return name;
286N/A }
286N/A
286N/A if (qnameIndex < 0) {
286N/A qnameIndex = -qnameIndex;
286N/A qnameIndex = m_data.elementAt(qnameIndex);
286N/A }
286N/A
286N/A String qName = m_valuesOrPrefixes.indexToString(qnameIndex);
286N/A handler.startElement(qName);
286N/A int prefixIndex = qName.indexOf(':');
286N/A String prefix;
286N/A if (prefixIndex > 0) {
286N/A prefix = qName.substring(0, prefixIndex);
286N/A }
286N/A else {
286N/A prefix = null;
286N/A }
286N/A handler.namespaceAfterStartElement(prefix, uri);
286N/A return qName;
286N/A }
286N/A
286N/A }
286N/A
286N/A /**
286N/A * Copy namespace nodes.
286N/A *
286N/A * @param nodeID The Element node identity
286N/A * @param handler The SerializationHandler
286N/A * @param inScope true if all namespaces in scope should be copied,
286N/A * false if only the namespace declarations should be copied.
286N/A */
286N/A protected final void copyNS(final int nodeID, SerializationHandler handler, boolean inScope)
286N/A throws SAXException
286N/A {
286N/A // %OPT% Optimization for documents which does not have any explicit
286N/A // namespace nodes. For these documents, there is an implicit
286N/A // namespace node (xmlns:xml="http://www.w3.org/XML/1998/namespace")
286N/A // declared on the root element node. In this case, there is no
286N/A // need to do namespace copying. We can safely return without
286N/A // doing anything.
286N/A if (m_namespaceDeclSetElements != null &&
286N/A m_namespaceDeclSetElements.size() == 1 &&
286N/A m_namespaceDeclSets != null &&
286N/A ((SuballocatedIntVector)m_namespaceDeclSets.elementAt(0))
286N/A .size() == 1)
286N/A return;
286N/A
286N/A SuballocatedIntVector nsContext = null;
286N/A int nextNSNode;
286N/A
286N/A // Find the first namespace node
286N/A if (inScope) {
286N/A nsContext = findNamespaceContext(nodeID);
286N/A if (nsContext == null || nsContext.size() < 1)
286N/A return;
286N/A else
286N/A nextNSNode = makeNodeIdentity(nsContext.elementAt(0));
286N/A }
286N/A else
286N/A nextNSNode = getNextNamespaceNode2(nodeID);
286N/A
286N/A int nsIndex = 1;
286N/A while (nextNSNode != DTM.NULL) {
286N/A // Retrieve the name of the namespace node
286N/A int eType = _exptype2(nextNSNode);
286N/A String nodeName = m_extendedTypes[eType].getLocalName();
286N/A
286N/A // Retrieve the node value of the namespace node
286N/A int dataIndex = m_dataOrQName.elementAt(nextNSNode);
286N/A
286N/A if (dataIndex < 0) {
286N/A dataIndex = -dataIndex;
286N/A dataIndex = m_data.elementAt(dataIndex + 1);
286N/A }
286N/A
286N/A String nodeValue = (String)m_values.elementAt(dataIndex);
286N/A
286N/A handler.namespaceAfterStartElement(nodeName, nodeValue);
286N/A
286N/A if (inScope) {
286N/A if (nsIndex < nsContext.size()) {
286N/A nextNSNode = makeNodeIdentity(nsContext.elementAt(nsIndex));
286N/A nsIndex++;
286N/A }
286N/A else
286N/A return;
286N/A }
286N/A else
286N/A nextNSNode = getNextNamespaceNode2(nextNSNode);
286N/A }
286N/A }
286N/A
286N/A /**
286N/A * Return the next namespace node following the given base node.
286N/A *
286N/A * @baseID The node identity of the base node, which can be an
286N/A * element, attribute or namespace node.
286N/A * @return The namespace node immediately following the base node.
286N/A */
286N/A protected final int getNextNamespaceNode2(int baseID) {
286N/A int type;
286N/A while ((type = _type2(++baseID)) == DTM.ATTRIBUTE_NODE);
286N/A
286N/A if (type == DTM.NAMESPACE_NODE)
286N/A return baseID;
286N/A else
286N/A return NULL;
286N/A }
286N/A
286N/A /**
286N/A * Copy attribute nodes from an element .
286N/A *
286N/A * @param nodeID The Element node identity
286N/A * @param handler The SerializationHandler
286N/A */
286N/A protected final void copyAttributes(final int nodeID, SerializationHandler handler)
286N/A throws SAXException{
286N/A
286N/A for(int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)){
286N/A int eType = _exptype2(current);
286N/A copyAttribute(current, eType, handler);
286N/A }
286N/A }
286N/A
286N/A
286N/A
286N/A /**
286N/A * Copy an Attribute node to a SerializationHandler
286N/A *
286N/A * @param nodeID The node identity
286N/A * @param exptype The expanded type of the Element node
286N/A * @param handler The SerializationHandler
286N/A */
286N/A protected final void copyAttribute(int nodeID, int exptype,
286N/A SerializationHandler handler)
286N/A throws SAXException
286N/A {
286N/A /*
286N/A final String uri = getNamespaceName(node);
286N/A if (uri.length() != 0) {
286N/A final String prefix = getPrefix(node);
286N/A handler.namespaceAfterStartElement(prefix, uri);
286N/A }
286N/A handler.addAttribute(getNodeName(node), getNodeValue(node));
286N/A */
286N/A final ExtendedType extType = m_extendedTypes[exptype];
286N/A final String uri = extType.getNamespace();
286N/A final String localName = extType.getLocalName();
286N/A
286N/A String prefix = null;
286N/A String qname = null;
286N/A int dataIndex = _dataOrQName(nodeID);
286N/A int valueIndex = dataIndex;
286N/A if (dataIndex <= 0) {
286N/A int prefixIndex = m_data.elementAt(-dataIndex);
286N/A valueIndex = m_data.elementAt(-dataIndex+1);
286N/A qname = m_valuesOrPrefixes.indexToString(prefixIndex);
286N/A int colonIndex = qname.indexOf(':');
286N/A if (colonIndex > 0) {
286N/A prefix = qname.substring(0, colonIndex);
286N/A }
286N/A }
286N/A if (uri.length() != 0) {
286N/A handler.namespaceAfterStartElement(prefix, uri);
286N/A }
286N/A
286N/A String nodeName = (prefix != null) ? qname : localName;
286N/A String nodeValue = (String)m_values.elementAt(valueIndex);
286N/A
286N/A handler.addAttribute(uri, localName, nodeName, "CDATA", nodeValue);
286N/A }
286N/A
286N/A}