- /*
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 1999 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xalan" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 1999, Lotus
- * Development Corporation., http://www.lotus.com. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
- package org.apache.xml.dtm.ref;
-
- import org.apache.xml.dtm.*;
-
- import javax.xml.transform.Source;
-
- import org.apache.xml.utils.XMLStringFactory;
-
- import org.apache.xalan.res.XSLTErrorResources;
- import org.apache.xalan.res.XSLMessages;
-
-
- /**
- * This class implements the traversers for DTMDefaultBase.
- *
- * PLEASE NOTE that the public interface for all traversers should be
- * in terms of DTM Node Handles... but they may use the internal node
- * identity indices within their logic, for efficiency's sake. Be very
- * careful to avoid confusing these when maintaining this code.
- * */
- public abstract class DTMDefaultBaseTraversers extends DTMDefaultBase
- {
-
- /**
- * Construct a DTMDefaultBaseTraversers object from a DOM node.
- *
- * @param mgr The DTMManager who owns this DTM.
- * @param domSource the DOM source that this DTM will wrap.
- * @param source The object that is used to specify the construction source.
- * @param dtmIdentity The DTM identity ID for this DTM.
- * @param whiteSpaceFilter The white space filter for this DTM, which may
- * be null.
- * @param xstringfactory The factory to use for creating XMLStrings.
- * @param doIndexing true if the caller considers it worth it to use
- * indexing schemes.
- */
- public DTMDefaultBaseTraversers(DTMManager mgr, Source source,
- int dtmIdentity,
- DTMWSFilter whiteSpaceFilter,
- XMLStringFactory xstringfactory,
- boolean doIndexing)
- {
- super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
- doIndexing);
- }
-
- /**
- * This returns a stateless "traverser", that can navigate
- * over an XPath axis, though perhaps not in document order.
- *
- * @param axis One of Axes.ANCESTORORSELF, etc.
- *
- * @return A DTMAxisTraverser, or null if the given axis isn't supported.
- */
- public DTMAxisTraverser getAxisTraverser(final int axis)
- {
-
- DTMAxisTraverser traverser;
-
- if (null == m_traversers) // Cache of stateless traversers for this DTM
- {
- m_traversers = new DTMAxisTraverser[Axis.names.length];
- traverser = null;
- }
- else
- {
- traverser = m_traversers[axis]; // Share/reuse existing traverser
-
- if (traverser != null)
- return traverser;
- }
-
- switch (axis) // Generate new traverser
- {
- case Axis.ANCESTOR :
- traverser = new AncestorTraverser();
- break;
- case Axis.ANCESTORORSELF :
- traverser = new AncestorOrSelfTraverser();
- break;
- case Axis.ATTRIBUTE :
- traverser = new AttributeTraverser();
- break;
- case Axis.CHILD :
- traverser = new ChildTraverser();
- break;
- case Axis.DESCENDANT :
- traverser = new DescendantTraverser();
- break;
- case Axis.DESCENDANTORSELF :
- traverser = new DescendantOrSelfTraverser();
- break;
- case Axis.FOLLOWING :
- traverser = new FollowingTraverser();
- break;
- case Axis.FOLLOWINGSIBLING :
- traverser = new FollowingSiblingTraverser();
- break;
- case Axis.NAMESPACE :
- traverser = new NamespaceTraverser();
- break;
- case Axis.NAMESPACEDECLS :
- traverser = new NamespaceDeclsTraverser();
- break;
- case Axis.PARENT :
- traverser = new ParentTraverser();
- break;
- case Axis.PRECEDING :
- traverser = new PrecedingTraverser();
- break;
- case Axis.PRECEDINGSIBLING :
- traverser = new PrecedingSiblingTraverser();
- break;
- case Axis.SELF :
- traverser = new SelfTraverser();
- break;
- case Axis.ALL :
- traverser = new AllFromRootTraverser();
- break;
- case Axis.ALLFROMNODE :
- traverser = new AllFromNodeTraverser();
- break;
- case Axis.PRECEDINGANDANCESTOR :
- traverser = new PrecedingAndAncestorTraverser();
- break;
- case Axis.DESCENDANTSFROMROOT :
- traverser = new DescendantFromRootTraverser();
- break;
- case Axis.DESCENDANTSORSELFFROMROOT :
- traverser = new DescendantOrSelfFromRootTraverser();
- break;
- case Axis.ROOT :
- traverser = new RootTraverser();
- break;
- case Axis.FILTEREDLIST :
- return null; // Don't want to throw an exception for this one.
- default :
- throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_UNKNOWN_AXIS_TYPE, new Object[]{Integer.toString(axis)})); //"Unknown axis traversal type: "+axis);
- }
-
- if (null == traverser)
- throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_AXIS_TRAVERSER_NOT_SUPPORTED, new Object[]{Axis.names[axis]}));
- // "Axis traverser not supported: "
- // + Axis.names[axis]);
-
- m_traversers[axis] = traverser;
-
- return traverser;
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class AncestorTraverser extends DTMAxisTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node if this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- return getParent(current);
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- // Process using identities
- current = makeNodeIdentity(current);
-
- while (DTM.NULL != (current = m_parent.elementAt(current)))
- {
- if (m_exptype.elementAt(current) == expandedTypeID)
- return makeNodeHandle(current);
- }
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class AncestorOrSelfTraverser extends AncestorTraverser
- {
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. To see if
- * the self node should be processed, use this function.
- *
- * @param context The context node of this traversal.
- *
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return context;
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. To see if
- * the self node should be processed, use this function. If the context
- * node does not match the expanded type ID, this function will return
- * false.
- *
- * @param context The context node of this traversal.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
- return (getExpandedTypeID(context) == expandedTypeID)
- ? context : next(context, context, expandedTypeID);
- }
- }
-
- /**
- * Implements traversal of the Attribute access
- */
- private class AttributeTraverser extends DTMAxisTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- return (context == current)
- ? getFirstAttribute(context) : getNextAttribute(current);
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
-
- current = (context == current)
- ? getFirstAttribute(context) : getNextAttribute(current);
-
- do
- {
- if (getExpandedTypeID(current) == expandedTypeID)
- return current;
- }
- while (DTM.NULL != (current = getNextAttribute(current)));
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class ChildTraverser extends DTMAxisTraverser
- {
-
- /**
- * Get the next indexed node that matches the expanded type ID. Before
- * calling this function, one should first call
- * {@link #isIndexed(int) isIndexed} to make sure that the index can
- * contain nodes that match the given expanded type ID.
- *
- * @param axisRoot The root identity of the axis.
- * @param nextPotential The node found must match or occur after this node.
- * @param expandedTypeID The expanded type ID for the request.
- *
- * @return The node ID or NULL if not found.
- */
- protected int getNextIndexed(int axisRoot, int nextPotential,
- int expandedTypeID)
- {
-
- int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
- int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
-
- for (; ; )
- {
- int nextID = findElementFromIndex(nsIndex, lnIndex, nextPotential);
-
- if (NOTPROCESSED != nextID)
- {
- int parentID = m_parent.elementAt(nextID);
-
- // Is it a child?
- if(parentID == axisRoot)
- return nextID;
-
- // If the parent occured before the subtree root, then
- // we know it is past the child axis.
- if(parentID < axisRoot)
- return NULL;
-
- // Otherwise, it could be a descendant below the subtree root
- // children, or it could be after the subtree root. So we have
- // to climb up until the parent is less than the subtree root, in
- // which case we return NULL, or until it is equal to the subtree
- // root, in which case we continue to look.
- do
- {
- parentID = m_parent.elementAt(parentID);
- if(parentID < axisRoot)
- return NULL;
- }
- while(parentID > axisRoot);
-
- // System.out.println("Found node via index: "+first);
- nextPotential = nextID+1;
- continue;
- }
-
- nextNode();
-
- if(!(m_nextsib.elementAt(axisRoot) == NOTPROCESSED))
- break;
- }
-
- return DTM.NULL;
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. So to traverse
- * an axis, the first function must be used to get the first node.
- *
- * <p>This method needs to be overloaded only by those axis that process
- * the self node. <\p>
- *
- * @param context The context node of this traversal. This is the point
- * that the traversal starts from.
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return getFirstChild(context);
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. So to traverse
- * an axis, the first function must be used to get the first node.
- *
- * <p>This method needs to be overloaded only by those axis that process
- * the self node. <\p>
- *
- * @param context The context node of this traversal. This is the point
- * of origin for the traversal -- its "root node" or starting point.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
- if(true)
- {
- int identity = makeNodeIdentity(context);
-
- int firstMatch = getNextIndexed(identity, _firstch(identity),
- expandedTypeID);
-
- return makeNodeHandle(firstMatch);
- }
- else
- {
- // %REVIEW% Dead code. Eliminate?
- for (int current = _firstch(makeNodeIdentity(context));
- DTM.NULL != current;
- current = _nextsib(current))
- {
- if (m_exptype.elementAt(current) == expandedTypeID)
- return makeNodeHandle(current);
- }
- return NULL;
- }
- }
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- return getNextSibling(current);
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- // Process in Identifier space
- for (current = _nextsib(makeNodeIdentity(current));
- DTM.NULL != current;
- current = _nextsib(current))
- {
- if (m_exptype.elementAt(current) == expandedTypeID)
- return makeNodeHandle(current);
- }
-
- return NULL;
- }
- }
-
- /**
- * Super class for derived classes that want a convenient way to access
- * the indexing mechanism.
- */
- private abstract class IndexedDTMAxisTraverser extends DTMAxisTraverser
- {
-
- /**
- * Tell if the indexing is on and the given expanded type ID matches
- * what is in the indexes. Derived classes should call this before
- * calling {@link #getNextIndexed(int, int, int) getNextIndexed} method.
- *
- * @param expandedTypeID The expanded type ID being requested.
- *
- * @return true if it is OK to call the
- * {@link #getNextIndexed(int, int, int) getNextIndexed} method.
- */
- protected final boolean isIndexed(int expandedTypeID)
- {
- return (m_indexing
- && ExpandedNameTable.ELEMENT
- == m_expandedNameTable.getType(expandedTypeID));
- }
-
- /**
- * Tell if a node is outside the axis being traversed. This method must be
- * implemented by derived classes, and must be robust enough to handle any
- * node that occurs after the axis root.
- *
- * @param axisRoot The root identity of the axis.
- * @param identity The node in question.
- *
- * @return true if the given node falls outside the axis being traversed.
- */
- protected abstract boolean isAfterAxis(int axisRoot, int identity);
-
- /**
- * Tell if the axis has been fully processed to tell if a the wait for
- * an arriving node should terminate. This method must be implemented
- * be a derived class.
- *
- * @param axisRoot The root identity of the axis.
- *
- * @return true if the axis has been fully processed.
- */
- protected abstract boolean axisHasBeenProcessed(int axisRoot);
-
- /**
- * Get the next indexed node that matches the expanded type ID. Before
- * calling this function, one should first call
- * {@link #isIndexed(int) isIndexed} to make sure that the index can
- * contain nodes that match the given expanded type ID.
- *
- * @param axisRoot The root identity of the axis.
- * @param nextPotential The node found must match or occur after this node.
- * @param expandedTypeID The expanded type ID for the request.
- *
- * @return The node ID or NULL if not found.
- */
- protected int getNextIndexed(int axisRoot, int nextPotential,
- int expandedTypeID)
- {
-
- int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
- int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
-
- while(true)
- {
- int next = findElementFromIndex(nsIndex, lnIndex, nextPotential);
-
- if (NOTPROCESSED != next)
- {
- if (isAfterAxis(axisRoot, next))
- return NULL;
-
- // System.out.println("Found node via index: "+first);
- return next;
- }
- else if(axisHasBeenProcessed(axisRoot))
- break;
-
- nextNode();
- }
-
- return DTM.NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class DescendantTraverser extends IndexedDTMAxisTraverser
- {
- /**
- * Get the first potential identity that can be returned. This should
- * be overridded by classes that need to return the self node.
- *
- * @param identity The node identity of the root context of the traversal.
- *
- * @return The first potential node that can be in the traversal.
- */
- protected int getFirstPotential(int identity)
- {
- return identity + 1;
- }
-
- /**
- * Tell if the axis has been fully processed to tell if a the wait for
- * an arriving node should terminate.
- *
- * @param axisRoot The root identity of the axis.
- *
- * @return true if the axis has been fully processed.
- */
- protected boolean axisHasBeenProcessed(int axisRoot)
- {
- return !(m_nextsib.elementAt(axisRoot) == NOTPROCESSED);
- }
-
- /**
- * Get the subtree root identity from the handle that was passed in by
- * the caller. Derived classes may override this to change the root
- * context of the traversal.
- *
- * @param handle handle to the root context.
- * @return identity of the root of the subtree.
- */
- protected int getSubtreeRoot(int handle)
- {
- return makeNodeIdentity(handle);
- }
-
- /**
- * Tell if this node identity is a descendant. Assumes that
- * the node info for the element has already been obtained.
- *
- * %REVIEW% This is really parentFollowsRootInDocumentOrder ...
- * which fails if the parent starts after the root ends.
- * May be sufficient for this class's logic, but misleadingly named!
- *
- * @param subtreeRootIdentity The root context of the subtree in question.
- * @param identity The index number of the node in question.
- * @return true if the index is a descendant of _startNode.
- */
- protected boolean isDescendant(int subtreeRootIdentity, int identity)
- {
- return _parent(identity) >= subtreeRootIdentity;
- }
-
- /**
- * Tell if a node is outside the axis being traversed. This method must be
- * implemented by derived classes, and must be robust enough to handle any
- * node that occurs after the axis root.
- *
- * @param axisRoot The root identity of the axis.
- * @param identity The node in question.
- *
- * @return true if the given node falls outside the axis being traversed.
- */
- protected boolean isAfterAxis(int axisRoot, int identity)
- {
- // %REVIEW% Is there *any* cheaper way to do this?
- // Yes. In ID space, compare to axisRoot's successor
- // (next-sib or ancestor's-next-sib). Probably shallower search.
- do
- {
- if(identity == axisRoot)
- return false;
- identity = m_parent.elementAt(identity);
- }
- while(identity >= axisRoot);
-
- return true;
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. So to traverse
- * an axis, the first function must be used to get the first node.
- *
- * <p>This method needs to be overloaded only by those axis that process
- * the self node. <\p>
- *
- * @param context The context node of this traversal. This is the point
- * of origin for the traversal -- its "root node" or starting point.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
-
- if (isIndexed(expandedTypeID))
- {
- int identity = getSubtreeRoot(context);
- int firstPotential = getFirstPotential(identity);
-
- return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
- }
-
- return next(context, context, expandedTypeID);
- }
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
-
- int subtreeRootIdent = getSubtreeRoot(context);
-
- for (current = makeNodeIdentity(current) + 1; ; current++)
- {
- int type = _type(current); // may call nextNode()
-
- if (!isDescendant(subtreeRootIdent, current))
- return NULL;
-
- if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
-
- int subtreeRootIdent = getSubtreeRoot(context);
-
- current = makeNodeIdentity(current) + 1;
-
- if (isIndexed(expandedTypeID))
- {
- return makeNodeHandle(getNextIndexed(subtreeRootIdent, current, expandedTypeID));
- }
-
- for (; ; current++)
- {
- int exptype = _exptype(current); // may call nextNode()
-
- if (!isDescendant(subtreeRootIdent, current))
- return NULL;
-
- if (exptype != expandedTypeID)
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class DescendantOrSelfTraverser extends DescendantTraverser
- {
-
- /**
- * Get the first potential identity that can be returned, which is the
- * axis context, in this case.
- *
- * @param identity The node identity of the root context of the traversal.
- *
- * @return The axis context.
- */
- protected int getFirstPotential(int identity)
- {
- return identity;
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. To see if
- * the self node should be processed, use this function.
- *
- * @param context The context node of this traversal.
- *
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return context;
- }
- }
-
- /**
- * Implements traversal of the entire subtree, including the root node.
- */
- private class AllFromNodeTraverser extends DescendantOrSelfTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
-
- int subtreeRootIdent = makeNodeIdentity(context);
-
- for (current = makeNodeIdentity(current) + 1; ; current++)
- {
- // Trickological code: _exptype() has the side-effect of
- // running nextNode until the specified node has been loaded,
- // and thus can be used to ensure that incremental construction of
- // the DTM has gotten this far. Using it just for that side-effect
- // is quite a kluge...
- _exptype(current); // make sure it's here.
-
- if (!isDescendant(subtreeRootIdent, current))
- return NULL;
-
- return makeNodeHandle(current); // make handle.
- }
- }
- }
-
- /**
- * Implements traversal of the following access, in document order.
- */
- private class FollowingTraverser extends DescendantTraverser
- {
-
- /**
- * Get the first of the following.
- *
- * @param context The context node of this traversal. This is the point
- * that the traversal starts from.
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- // Compute in ID space
- context=makeNodeIdentity(context);
-
- int first;
- int type = _type(context);
-
- if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
- {
- context = _parent(context);
- first = _firstch(context);
-
- if (NULL != first)
- return makeNodeHandle(first);
- }
-
- do
- {
- first = _nextsib(context);
-
- if (NULL == first)
- context = _parent(context);
- }
- while (NULL == first && NULL != context);
-
- return makeNodeHandle(first);
- }
-
- /**
- * Get the first of the following.
- *
- * @param context The context node of this traversal. This is the point
- * of origin for the traversal -- its "root node" or starting point.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
- // %REVIEW% This looks like it might want shift into identity space
- // to avoid repeated conversion in the individual functions
- int first;
- int type = getNodeType(context);
-
- if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
- {
- context = getParent(context);
- first = getFirstChild(context);
-
- if (NULL != first)
- {
- if (getExpandedTypeID(first) == expandedTypeID)
- return first;
- else
- return next(context, first, expandedTypeID);
- }
- }
-
- do
- {
- first = getNextSibling(context);
-
- if (NULL == first)
- context = getParent(context);
- else
- {
- if (getExpandedTypeID(first) == expandedTypeID)
- return first;
- else
- return next(context, first, expandedTypeID);
- }
- }
- while (NULL == first && NULL != context);
-
- return first;
- }
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- // Compute in identity space
- current=makeNodeIdentity(current);
-
- while (true)
- {
- current++; // Only works on IDs, not handles.
-
- // %REVIEW% Are we using handles or indexes?
- int type = _type(current); // may call nextNode()
-
- if (NULL == type)
- return NULL;
-
- if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- // Compute in ID space
- current=makeNodeIdentity(current);
-
- while (true)
- {
- current++;
-
- int etype = _exptype(current); // may call nextNode()
-
- if (NULL == etype)
- return NULL;
-
- if (etype != expandedTypeID)
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class FollowingSiblingTraverser extends DTMAxisTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- return getNextSibling(current);
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
-
- while (DTM.NULL != (current = getNextSibling(current)))
- {
- if (getExpandedTypeID(current) == expandedTypeID)
- return current;
- }
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class NamespaceDeclsTraverser extends DTMAxisTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
-
- return (context == current)
- ? getFirstNamespaceNode(context, false)
- : getNextNamespaceNode(context, current, false);
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
-
- current = (context == current)
- ? getFirstNamespaceNode(context, false)
- : getNextNamespaceNode(context, current, false);
-
- do
- {
- if (getExpandedTypeID(current) == expandedTypeID)
- return current;
- }
- while (DTM.NULL
- != (current = getNextNamespaceNode(context, current, false)));
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class NamespaceTraverser extends DTMAxisTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
-
- return (context == current)
- ? getFirstNamespaceNode(context, true)
- : getNextNamespaceNode(context, current, true);
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
-
- current = (context == current)
- ? getFirstNamespaceNode(context, true)
- : getNextNamespaceNode(context, current, true);
-
- do
- {
- if (getExpandedTypeID(current) == expandedTypeID)
- return current;
- }
- while (DTM.NULL
- != (current = getNextNamespaceNode(context, current, true)));
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class ParentTraverser extends DTMAxisTraverser
- {
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. So to traverse
- * an axis, the first function must be used to get the first node.
- *
- * <p>This method needs to be overloaded only by those axis that process
- * the self node. <\p>
- *
- * @param context The context node of this traversal. This is the point
- * that the traversal starts from.
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return getParent(context);
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. So to traverse
- * an axis, the first function must be used to get the first node.
- *
- * <p>This method needs to be overloaded only by those axis that process
- * the self node. <\p>
- *
- * @param context The context node of this traversal. This is the point
- * of origin for the traversal -- its "root node" or starting point.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int current, int expandedTypeID)
- {
- // Compute in ID space
- current = makeNodeIdentity(current);
-
- while (NULL != (current = m_parent.elementAt(current)))
- {
- if (m_exptype.elementAt(current) == expandedTypeID)
- return makeNodeHandle(current);
- }
-
- return NULL;
- }
-
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
-
- return NULL;
- }
-
-
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class PrecedingTraverser extends DTMAxisTraverser
- {
-
- /**
- * Tell if the current identity is an ancestor of the context identity.
- * This is an expensive operation, made worse by the stateless traversal.
- * But the preceding axis is used fairly infrequently.
- *
- * @param contextIdent The context node of the axis traversal.
- * @param currentIdent The node in question.
- * @return true if the currentIdent node is an ancestor of contextIdent.
- */
- protected boolean isAncestor(int contextIdent, int currentIdent)
- {
- // %REVIEW% See comments in IsAfterAxis; using the "successor" of
- // contextIdent is probably more efficient.
- for (contextIdent = m_parent.elementAt(contextIdent); DTM.NULL != contextIdent;
- contextIdent = m_parent.elementAt(contextIdent))
- {
- if (contextIdent == currentIdent)
- return true;
- }
-
- return false;
- }
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- // compute in ID space
- int subtreeRootIdent = makeNodeIdentity(context);
-
- for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
- {
- short type = _type(current);
-
- if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type
- || isAncestor(subtreeRootIdent, current))
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
-
- return NULL;
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- // Compute in ID space
- int subtreeRootIdent = makeNodeIdentity(context);
-
- for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
- {
- int exptype = m_exptype.elementAt(current);
-
- if (exptype != expandedTypeID
- || isAncestor(subtreeRootIdent, current))
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor and the Preceding axis,
- * in reverse document order.
- */
- private class PrecedingAndAncestorTraverser extends DTMAxisTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- // Compute in ID space
- int subtreeRootIdent = makeNodeIdentity(context );
-
- for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
- {
- short type = _type(current);
-
- if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
-
- return NULL;
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- // Compute in ID space
- int subtreeRootIdent = makeNodeIdentity(context);
-
- for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
- {
- int exptype = m_exptype.elementAt(current);
-
- if (exptype != expandedTypeID)
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class PrecedingSiblingTraverser extends DTMAxisTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- return getPreviousSibling(current);
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
-
- while (DTM.NULL != (current = getPreviousSibling(current)))
- {
- if (getExpandedTypeID(current) == expandedTypeID)
- return current;
- }
-
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Self axis.
- */
- private class SelfTraverser extends DTMAxisTraverser
- {
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. To see if
- * the self node should be processed, use this function.
- *
- * @param context The context node of this traversal.
- *
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return context;
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. To see if
- * the self node should be processed, use this function. If the context
- * node does not match the expanded type ID, this function will return
- * false.
- *
- * @param context The context node of this traversal.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
- return (getExpandedTypeID(context) == expandedTypeID) ? context : NULL;
- }
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return Always return NULL for this axis.
- */
- public int next(int context, int current)
- {
- return NULL;
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- return NULL;
- }
- }
-
- /**
- * Implements traversal of the Ancestor access, in reverse document order.
- */
- private class AllFromRootTraverser extends AllFromNodeTraverser
- {
-
- /**
- * Return the root.
- *
- * @param context The context node of this traversal.
- *
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return getDocumentRoot(context);
- }
-
- /**
- * Return the root if it matches the expanded type ID.
- *
- * @param context The context node of this traversal.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
- return (getExpandedTypeID(getDocumentRoot(context)) == expandedTypeID)
- ? context : next(context, context, expandedTypeID);
- }
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current)
- {
- // Compute in ID space
- int subtreeRootIdent = makeNodeIdentity(context);
-
- for (current = makeNodeIdentity(current) + 1; ; current++)
- {
- // Kluge test: Just make sure +1 yielded a real node
- int type = _type(current); // may call nextNode()
- if (type == NULL)
- return NULL;
-
- return makeNodeHandle(current); // make handle.
- }
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- // Compute in ID space
- int subtreeRootIdent = makeNodeIdentity(context);
-
- for (current = makeNodeIdentity(current) + 1; ; current++)
- {
- int exptype = _exptype(current); // may call nextNode()
-
- if (exptype == NULL)
- return NULL;
-
- if (exptype != expandedTypeID)
- continue;
-
- return makeNodeHandle(current); // make handle.
- }
- }
- }
-
- /**
- * Implements traversal of the Self axis.
- */
- private class RootTraverser extends AllFromRootTraverser
- {
-
- /**
- * Traverse to the next node after the current node.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- *
- * @return Always return NULL for this axis.
- */
- public int next(int context, int current)
- {
- return NULL;
- }
-
- /**
- * Traverse to the next node after the current node that is matched
- * by the expanded type ID.
- *
- * @param context The context node of this iteration.
- * @param current The current node of the iteration.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the next node in the iteration, or DTM.NULL.
- */
- public int next(int context, int current, int expandedTypeID)
- {
- return NULL;
- }
- }
-
- /**
- * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
- * from and including the root.
- */
- private class DescendantOrSelfFromRootTraverser extends DescendantTraverser
- {
-
- /**
- * Get the first potential identity that can be returned, which is the axis
- * root context in this case.
- *
- * @param identity The node identity of the root context of the traversal.
- *
- * @return The identity argument.
- */
- protected int getFirstPotential(int identity)
- {
- return identity;
- }
-
- /**
- * Get the first potential identity that can be returned.
- * @param handle handle to the root context.
- * @return identity of the root of the subtree.
- */
- protected int getSubtreeRoot(int handle)
- {
- // %REVIEW% Shouldn't this always be 0?
- return makeNodeIdentity(getDocument());
- }
-
- /**
- * Return the root.
- *
- * @param context The context node of this traversal.
- *
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return getDocumentRoot(context);
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. So to traverse
- * an axis, the first function must be used to get the first node.
- *
- * <p>This method needs to be overloaded only by those axis that process
- * the self node. <\p>
- *
- * @param context The context node of this traversal. This is the point
- * of origin for the traversal -- its "root node" or starting point.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
- if (isIndexed(expandedTypeID))
- {
- int identity = 0;
- int firstPotential = getFirstPotential(identity);
-
- return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
- }
-
- int root = first(context);
- return next(root, root, expandedTypeID);
- }
- }
-
- /**
- * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
- * from but not including the root.
- */
- private class DescendantFromRootTraverser extends DescendantTraverser
- {
-
- /**
- * Get the first potential identity that can be returned, which is the axis
- * root context in this case.
- *
- * @param identity The node identity of the root context of the traversal.
- *
- * @return The identity argument.
- */
- protected int getFirstPotential(int identity)
- {
- return _firstch(0);
- }
-
- /**
- * Get the first potential identity that can be returned.
- * @param handle handle to the root context.
- * @return identity of the root of the subtree.
- */
- protected int getSubtreeRoot(int handle)
- {
- return 0;
- }
-
- /**
- * Return the root.
- *
- * @param context The context node of this traversal.
- *
- * @return the first node in the traversal.
- */
- public int first(int context)
- {
- return makeNodeHandle(_firstch(0));
- }
-
- /**
- * By the nature of the stateless traversal, the context node can not be
- * returned or the iteration will go into an infinate loop. So to traverse
- * an axis, the first function must be used to get the first node.
- *
- * <p>This method needs to be overloaded only by those axis that process
- * the self node. <\p>
- *
- * @param context The context node of this traversal. This is the point
- * of origin for the traversal -- its "root node" or starting point.
- * @param expandedTypeID The expanded type ID that must match.
- *
- * @return the first node in the traversal.
- */
- public int first(int context, int expandedTypeID)
- {
- if (isIndexed(expandedTypeID))
- {
- int identity = 0;
- int firstPotential = getFirstPotential(identity);
-
- return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
- }
-
- int root = getDocumentRoot(context);
- return next(root, root, expandedTypeID);
- }
-
- }
-
- }