1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. *
  5. * Copyright (c) 1999 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Xalan" and "Apache Software Foundation" must
  28. * not be used to endorse or promote products derived from this
  29. * software without prior written permission. For written
  30. * permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * nor may "Apache" appear in their name, without prior written
  34. * permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation and was
  52. * originally based on software copyright (c) 1999, Lotus
  53. * Development Corporation., http://www.lotus.com. For more
  54. * information on the Apache Software Foundation, please see
  55. * <http://www.apache.org/>.
  56. */
  57. package org.apache.xml.dtm.ref;
  58. import org.apache.xml.dtm.*;
  59. import javax.xml.transform.Source;
  60. import org.apache.xml.utils.XMLStringFactory;
  61. import org.apache.xalan.res.XSLTErrorResources;
  62. import org.apache.xalan.res.XSLMessages;
  63. /**
  64. * This class implements the traversers for DTMDefaultBase.
  65. *
  66. * PLEASE NOTE that the public interface for all traversers should be
  67. * in terms of DTM Node Handles... but they may use the internal node
  68. * identity indices within their logic, for efficiency's sake. Be very
  69. * careful to avoid confusing these when maintaining this code.
  70. * */
  71. public abstract class DTMDefaultBaseTraversers extends DTMDefaultBase
  72. {
  73. /**
  74. * Construct a DTMDefaultBaseTraversers object from a DOM node.
  75. *
  76. * @param mgr The DTMManager who owns this DTM.
  77. * @param domSource the DOM source that this DTM will wrap.
  78. * @param source The object that is used to specify the construction source.
  79. * @param dtmIdentity The DTM identity ID for this DTM.
  80. * @param whiteSpaceFilter The white space filter for this DTM, which may
  81. * be null.
  82. * @param xstringfactory The factory to use for creating XMLStrings.
  83. * @param doIndexing true if the caller considers it worth it to use
  84. * indexing schemes.
  85. */
  86. public DTMDefaultBaseTraversers(DTMManager mgr, Source source,
  87. int dtmIdentity,
  88. DTMWSFilter whiteSpaceFilter,
  89. XMLStringFactory xstringfactory,
  90. boolean doIndexing)
  91. {
  92. super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory,
  93. doIndexing);
  94. }
  95. /**
  96. * This returns a stateless "traverser", that can navigate
  97. * over an XPath axis, though perhaps not in document order.
  98. *
  99. * @param axis One of Axes.ANCESTORORSELF, etc.
  100. *
  101. * @return A DTMAxisTraverser, or null if the given axis isn't supported.
  102. */
  103. public DTMAxisTraverser getAxisTraverser(final int axis)
  104. {
  105. DTMAxisTraverser traverser;
  106. if (null == m_traversers) // Cache of stateless traversers for this DTM
  107. {
  108. m_traversers = new DTMAxisTraverser[Axis.names.length];
  109. traverser = null;
  110. }
  111. else
  112. {
  113. traverser = m_traversers[axis]; // Share/reuse existing traverser
  114. if (traverser != null)
  115. return traverser;
  116. }
  117. switch (axis) // Generate new traverser
  118. {
  119. case Axis.ANCESTOR :
  120. traverser = new AncestorTraverser();
  121. break;
  122. case Axis.ANCESTORORSELF :
  123. traverser = new AncestorOrSelfTraverser();
  124. break;
  125. case Axis.ATTRIBUTE :
  126. traverser = new AttributeTraverser();
  127. break;
  128. case Axis.CHILD :
  129. traverser = new ChildTraverser();
  130. break;
  131. case Axis.DESCENDANT :
  132. traverser = new DescendantTraverser();
  133. break;
  134. case Axis.DESCENDANTORSELF :
  135. traverser = new DescendantOrSelfTraverser();
  136. break;
  137. case Axis.FOLLOWING :
  138. traverser = new FollowingTraverser();
  139. break;
  140. case Axis.FOLLOWINGSIBLING :
  141. traverser = new FollowingSiblingTraverser();
  142. break;
  143. case Axis.NAMESPACE :
  144. traverser = new NamespaceTraverser();
  145. break;
  146. case Axis.NAMESPACEDECLS :
  147. traverser = new NamespaceDeclsTraverser();
  148. break;
  149. case Axis.PARENT :
  150. traverser = new ParentTraverser();
  151. break;
  152. case Axis.PRECEDING :
  153. traverser = new PrecedingTraverser();
  154. break;
  155. case Axis.PRECEDINGSIBLING :
  156. traverser = new PrecedingSiblingTraverser();
  157. break;
  158. case Axis.SELF :
  159. traverser = new SelfTraverser();
  160. break;
  161. case Axis.ALL :
  162. traverser = new AllFromRootTraverser();
  163. break;
  164. case Axis.ALLFROMNODE :
  165. traverser = new AllFromNodeTraverser();
  166. break;
  167. case Axis.PRECEDINGANDANCESTOR :
  168. traverser = new PrecedingAndAncestorTraverser();
  169. break;
  170. case Axis.DESCENDANTSFROMROOT :
  171. traverser = new DescendantFromRootTraverser();
  172. break;
  173. case Axis.DESCENDANTSORSELFFROMROOT :
  174. traverser = new DescendantOrSelfFromRootTraverser();
  175. break;
  176. case Axis.ROOT :
  177. traverser = new RootTraverser();
  178. break;
  179. case Axis.FILTEREDLIST :
  180. return null; // Don't want to throw an exception for this one.
  181. default :
  182. throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_UNKNOWN_AXIS_TYPE, new Object[]{Integer.toString(axis)})); //"Unknown axis traversal type: "+axis);
  183. }
  184. if (null == traverser)
  185. throw new DTMException(XSLMessages.createMessage(XSLTErrorResources.ER_AXIS_TRAVERSER_NOT_SUPPORTED, new Object[]{Axis.names[axis]}));
  186. // "Axis traverser not supported: "
  187. // + Axis.names[axis]);
  188. m_traversers[axis] = traverser;
  189. return traverser;
  190. }
  191. /**
  192. * Implements traversal of the Ancestor access, in reverse document order.
  193. */
  194. private class AncestorTraverser extends DTMAxisTraverser
  195. {
  196. /**
  197. * Traverse to the next node after the current node.
  198. *
  199. * @param context The context node if this iteration.
  200. * @param current The current node of the iteration.
  201. *
  202. * @return the next node in the iteration, or DTM.NULL.
  203. */
  204. public int next(int context, int current)
  205. {
  206. return getParent(current);
  207. }
  208. /**
  209. * Traverse to the next node after the current node that is matched
  210. * by the expanded type ID.
  211. *
  212. * @param context The context node of this iteration.
  213. * @param current The current node of the iteration.
  214. * @param expandedTypeID The expanded type ID that must match.
  215. *
  216. * @return the next node in the iteration, or DTM.NULL.
  217. */
  218. public int next(int context, int current, int expandedTypeID)
  219. {
  220. // Process using identities
  221. current = makeNodeIdentity(current);
  222. while (DTM.NULL != (current = m_parent.elementAt(current)))
  223. {
  224. if (m_exptype.elementAt(current) == expandedTypeID)
  225. return makeNodeHandle(current);
  226. }
  227. return NULL;
  228. }
  229. }
  230. /**
  231. * Implements traversal of the Ancestor access, in reverse document order.
  232. */
  233. private class AncestorOrSelfTraverser extends AncestorTraverser
  234. {
  235. /**
  236. * By the nature of the stateless traversal, the context node can not be
  237. * returned or the iteration will go into an infinate loop. To see if
  238. * the self node should be processed, use this function.
  239. *
  240. * @param context The context node of this traversal.
  241. *
  242. * @return the first node in the traversal.
  243. */
  244. public int first(int context)
  245. {
  246. return context;
  247. }
  248. /**
  249. * By the nature of the stateless traversal, the context node can not be
  250. * returned or the iteration will go into an infinate loop. To see if
  251. * the self node should be processed, use this function. If the context
  252. * node does not match the expanded type ID, this function will return
  253. * false.
  254. *
  255. * @param context The context node of this traversal.
  256. * @param expandedTypeID The expanded type ID that must match.
  257. *
  258. * @return the first node in the traversal.
  259. */
  260. public int first(int context, int expandedTypeID)
  261. {
  262. return (getExpandedTypeID(context) == expandedTypeID)
  263. ? context : next(context, context, expandedTypeID);
  264. }
  265. }
  266. /**
  267. * Implements traversal of the Attribute access
  268. */
  269. private class AttributeTraverser extends DTMAxisTraverser
  270. {
  271. /**
  272. * Traverse to the next node after the current node.
  273. *
  274. * @param context The context node of this iteration.
  275. * @param current The current node of the iteration.
  276. *
  277. * @return the next node in the iteration, or DTM.NULL.
  278. */
  279. public int next(int context, int current)
  280. {
  281. return (context == current)
  282. ? getFirstAttribute(context) : getNextAttribute(current);
  283. }
  284. /**
  285. * Traverse to the next node after the current node that is matched
  286. * by the expanded type ID.
  287. *
  288. * @param context The context node of this iteration.
  289. * @param current The current node of the iteration.
  290. * @param expandedTypeID The expanded type ID that must match.
  291. *
  292. * @return the next node in the iteration, or DTM.NULL.
  293. */
  294. public int next(int context, int current, int expandedTypeID)
  295. {
  296. current = (context == current)
  297. ? getFirstAttribute(context) : getNextAttribute(current);
  298. do
  299. {
  300. if (getExpandedTypeID(current) == expandedTypeID)
  301. return current;
  302. }
  303. while (DTM.NULL != (current = getNextAttribute(current)));
  304. return NULL;
  305. }
  306. }
  307. /**
  308. * Implements traversal of the Ancestor access, in reverse document order.
  309. */
  310. private class ChildTraverser extends DTMAxisTraverser
  311. {
  312. /**
  313. * Get the next indexed node that matches the expanded type ID. Before
  314. * calling this function, one should first call
  315. * {@link #isIndexed(int) isIndexed} to make sure that the index can
  316. * contain nodes that match the given expanded type ID.
  317. *
  318. * @param axisRoot The root identity of the axis.
  319. * @param nextPotential The node found must match or occur after this node.
  320. * @param expandedTypeID The expanded type ID for the request.
  321. *
  322. * @return The node ID or NULL if not found.
  323. */
  324. protected int getNextIndexed(int axisRoot, int nextPotential,
  325. int expandedTypeID)
  326. {
  327. int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
  328. int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
  329. for (; ; )
  330. {
  331. int nextID = findElementFromIndex(nsIndex, lnIndex, nextPotential);
  332. if (NOTPROCESSED != nextID)
  333. {
  334. int parentID = m_parent.elementAt(nextID);
  335. // Is it a child?
  336. if(parentID == axisRoot)
  337. return nextID;
  338. // If the parent occured before the subtree root, then
  339. // we know it is past the child axis.
  340. if(parentID < axisRoot)
  341. return NULL;
  342. // Otherwise, it could be a descendant below the subtree root
  343. // children, or it could be after the subtree root. So we have
  344. // to climb up until the parent is less than the subtree root, in
  345. // which case we return NULL, or until it is equal to the subtree
  346. // root, in which case we continue to look.
  347. do
  348. {
  349. parentID = m_parent.elementAt(parentID);
  350. if(parentID < axisRoot)
  351. return NULL;
  352. }
  353. while(parentID > axisRoot);
  354. // System.out.println("Found node via index: "+first);
  355. nextPotential = nextID+1;
  356. continue;
  357. }
  358. nextNode();
  359. if(!(m_nextsib.elementAt(axisRoot) == NOTPROCESSED))
  360. break;
  361. }
  362. return DTM.NULL;
  363. }
  364. /**
  365. * By the nature of the stateless traversal, the context node can not be
  366. * returned or the iteration will go into an infinate loop. So to traverse
  367. * an axis, the first function must be used to get the first node.
  368. *
  369. * <p>This method needs to be overloaded only by those axis that process
  370. * the self node. <\p>
  371. *
  372. * @param context The context node of this traversal. This is the point
  373. * that the traversal starts from.
  374. * @return the first node in the traversal.
  375. */
  376. public int first(int context)
  377. {
  378. return getFirstChild(context);
  379. }
  380. /**
  381. * By the nature of the stateless traversal, the context node can not be
  382. * returned or the iteration will go into an infinate loop. So to traverse
  383. * an axis, the first function must be used to get the first node.
  384. *
  385. * <p>This method needs to be overloaded only by those axis that process
  386. * the self node. <\p>
  387. *
  388. * @param context The context node of this traversal. This is the point
  389. * of origin for the traversal -- its "root node" or starting point.
  390. * @param expandedTypeID The expanded type ID that must match.
  391. *
  392. * @return the first node in the traversal.
  393. */
  394. public int first(int context, int expandedTypeID)
  395. {
  396. if(true)
  397. {
  398. int identity = makeNodeIdentity(context);
  399. int firstMatch = getNextIndexed(identity, _firstch(identity),
  400. expandedTypeID);
  401. return makeNodeHandle(firstMatch);
  402. }
  403. else
  404. {
  405. // %REVIEW% Dead code. Eliminate?
  406. for (int current = _firstch(makeNodeIdentity(context));
  407. DTM.NULL != current;
  408. current = _nextsib(current))
  409. {
  410. if (m_exptype.elementAt(current) == expandedTypeID)
  411. return makeNodeHandle(current);
  412. }
  413. return NULL;
  414. }
  415. }
  416. /**
  417. * Traverse to the next node after the current node.
  418. *
  419. * @param context The context node of this iteration.
  420. * @param current The current node of the iteration.
  421. *
  422. * @return the next node in the iteration, or DTM.NULL.
  423. */
  424. public int next(int context, int current)
  425. {
  426. return getNextSibling(current);
  427. }
  428. /**
  429. * Traverse to the next node after the current node that is matched
  430. * by the expanded type ID.
  431. *
  432. * @param context The context node of this iteration.
  433. * @param current The current node of the iteration.
  434. * @param expandedTypeID The expanded type ID that must match.
  435. *
  436. * @return the next node in the iteration, or DTM.NULL.
  437. */
  438. public int next(int context, int current, int expandedTypeID)
  439. {
  440. // Process in Identifier space
  441. for (current = _nextsib(makeNodeIdentity(current));
  442. DTM.NULL != current;
  443. current = _nextsib(current))
  444. {
  445. if (m_exptype.elementAt(current) == expandedTypeID)
  446. return makeNodeHandle(current);
  447. }
  448. return NULL;
  449. }
  450. }
  451. /**
  452. * Super class for derived classes that want a convenient way to access
  453. * the indexing mechanism.
  454. */
  455. private abstract class IndexedDTMAxisTraverser extends DTMAxisTraverser
  456. {
  457. /**
  458. * Tell if the indexing is on and the given expanded type ID matches
  459. * what is in the indexes. Derived classes should call this before
  460. * calling {@link #getNextIndexed(int, int, int) getNextIndexed} method.
  461. *
  462. * @param expandedTypeID The expanded type ID being requested.
  463. *
  464. * @return true if it is OK to call the
  465. * {@link #getNextIndexed(int, int, int) getNextIndexed} method.
  466. */
  467. protected final boolean isIndexed(int expandedTypeID)
  468. {
  469. return (m_indexing
  470. && ExpandedNameTable.ELEMENT
  471. == m_expandedNameTable.getType(expandedTypeID));
  472. }
  473. /**
  474. * Tell if a node is outside the axis being traversed. This method must be
  475. * implemented by derived classes, and must be robust enough to handle any
  476. * node that occurs after the axis root.
  477. *
  478. * @param axisRoot The root identity of the axis.
  479. * @param identity The node in question.
  480. *
  481. * @return true if the given node falls outside the axis being traversed.
  482. */
  483. protected abstract boolean isAfterAxis(int axisRoot, int identity);
  484. /**
  485. * Tell if the axis has been fully processed to tell if a the wait for
  486. * an arriving node should terminate. This method must be implemented
  487. * be a derived class.
  488. *
  489. * @param axisRoot The root identity of the axis.
  490. *
  491. * @return true if the axis has been fully processed.
  492. */
  493. protected abstract boolean axisHasBeenProcessed(int axisRoot);
  494. /**
  495. * Get the next indexed node that matches the expanded type ID. Before
  496. * calling this function, one should first call
  497. * {@link #isIndexed(int) isIndexed} to make sure that the index can
  498. * contain nodes that match the given expanded type ID.
  499. *
  500. * @param axisRoot The root identity of the axis.
  501. * @param nextPotential The node found must match or occur after this node.
  502. * @param expandedTypeID The expanded type ID for the request.
  503. *
  504. * @return The node ID or NULL if not found.
  505. */
  506. protected int getNextIndexed(int axisRoot, int nextPotential,
  507. int expandedTypeID)
  508. {
  509. int nsIndex = m_expandedNameTable.getNamespaceID(expandedTypeID);
  510. int lnIndex = m_expandedNameTable.getLocalNameID(expandedTypeID);
  511. while(true)
  512. {
  513. int next = findElementFromIndex(nsIndex, lnIndex, nextPotential);
  514. if (NOTPROCESSED != next)
  515. {
  516. if (isAfterAxis(axisRoot, next))
  517. return NULL;
  518. // System.out.println("Found node via index: "+first);
  519. return next;
  520. }
  521. else if(axisHasBeenProcessed(axisRoot))
  522. break;
  523. nextNode();
  524. }
  525. return DTM.NULL;
  526. }
  527. }
  528. /**
  529. * Implements traversal of the Ancestor access, in reverse document order.
  530. */
  531. private class DescendantTraverser extends IndexedDTMAxisTraverser
  532. {
  533. /**
  534. * Get the first potential identity that can be returned. This should
  535. * be overridded by classes that need to return the self node.
  536. *
  537. * @param identity The node identity of the root context of the traversal.
  538. *
  539. * @return The first potential node that can be in the traversal.
  540. */
  541. protected int getFirstPotential(int identity)
  542. {
  543. return identity + 1;
  544. }
  545. /**
  546. * Tell if the axis has been fully processed to tell if a the wait for
  547. * an arriving node should terminate.
  548. *
  549. * @param axisRoot The root identity of the axis.
  550. *
  551. * @return true if the axis has been fully processed.
  552. */
  553. protected boolean axisHasBeenProcessed(int axisRoot)
  554. {
  555. return !(m_nextsib.elementAt(axisRoot) == NOTPROCESSED);
  556. }
  557. /**
  558. * Get the subtree root identity from the handle that was passed in by
  559. * the caller. Derived classes may override this to change the root
  560. * context of the traversal.
  561. *
  562. * @param handle handle to the root context.
  563. * @return identity of the root of the subtree.
  564. */
  565. protected int getSubtreeRoot(int handle)
  566. {
  567. return makeNodeIdentity(handle);
  568. }
  569. /**
  570. * Tell if this node identity is a descendant. Assumes that
  571. * the node info for the element has already been obtained.
  572. *
  573. * %REVIEW% This is really parentFollowsRootInDocumentOrder ...
  574. * which fails if the parent starts after the root ends.
  575. * May be sufficient for this class's logic, but misleadingly named!
  576. *
  577. * @param subtreeRootIdentity The root context of the subtree in question.
  578. * @param identity The index number of the node in question.
  579. * @return true if the index is a descendant of _startNode.
  580. */
  581. protected boolean isDescendant(int subtreeRootIdentity, int identity)
  582. {
  583. return _parent(identity) >= subtreeRootIdentity;
  584. }
  585. /**
  586. * Tell if a node is outside the axis being traversed. This method must be
  587. * implemented by derived classes, and must be robust enough to handle any
  588. * node that occurs after the axis root.
  589. *
  590. * @param axisRoot The root identity of the axis.
  591. * @param identity The node in question.
  592. *
  593. * @return true if the given node falls outside the axis being traversed.
  594. */
  595. protected boolean isAfterAxis(int axisRoot, int identity)
  596. {
  597. // %REVIEW% Is there *any* cheaper way to do this?
  598. // Yes. In ID space, compare to axisRoot's successor
  599. // (next-sib or ancestor's-next-sib). Probably shallower search.
  600. do
  601. {
  602. if(identity == axisRoot)
  603. return false;
  604. identity = m_parent.elementAt(identity);
  605. }
  606. while(identity >= axisRoot);
  607. return true;
  608. }
  609. /**
  610. * By the nature of the stateless traversal, the context node can not be
  611. * returned or the iteration will go into an infinate loop. So to traverse
  612. * an axis, the first function must be used to get the first node.
  613. *
  614. * <p>This method needs to be overloaded only by those axis that process
  615. * the self node. <\p>
  616. *
  617. * @param context The context node of this traversal. This is the point
  618. * of origin for the traversal -- its "root node" or starting point.
  619. * @param expandedTypeID The expanded type ID that must match.
  620. *
  621. * @return the first node in the traversal.
  622. */
  623. public int first(int context, int expandedTypeID)
  624. {
  625. if (isIndexed(expandedTypeID))
  626. {
  627. int identity = getSubtreeRoot(context);
  628. int firstPotential = getFirstPotential(identity);
  629. return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
  630. }
  631. return next(context, context, expandedTypeID);
  632. }
  633. /**
  634. * Traverse to the next node after the current node.
  635. *
  636. * @param context The context node of this iteration.
  637. * @param current The current node of the iteration.
  638. *
  639. * @return the next node in the iteration, or DTM.NULL.
  640. */
  641. public int next(int context, int current)
  642. {
  643. int subtreeRootIdent = getSubtreeRoot(context);
  644. for (current = makeNodeIdentity(current) + 1; ; current++)
  645. {
  646. int type = _type(current); // may call nextNode()
  647. if (!isDescendant(subtreeRootIdent, current))
  648. return NULL;
  649. if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
  650. continue;
  651. return makeNodeHandle(current); // make handle.
  652. }
  653. }
  654. /**
  655. * Traverse to the next node after the current node that is matched
  656. * by the expanded type ID.
  657. *
  658. * @param context The context node of this iteration.
  659. * @param current The current node of the iteration.
  660. * @param expandedTypeID The expanded type ID that must match.
  661. *
  662. * @return the next node in the iteration, or DTM.NULL.
  663. */
  664. public int next(int context, int current, int expandedTypeID)
  665. {
  666. int subtreeRootIdent = getSubtreeRoot(context);
  667. current = makeNodeIdentity(current) + 1;
  668. if (isIndexed(expandedTypeID))
  669. {
  670. return makeNodeHandle(getNextIndexed(subtreeRootIdent, current, expandedTypeID));
  671. }
  672. for (; ; current++)
  673. {
  674. int exptype = _exptype(current); // may call nextNode()
  675. if (!isDescendant(subtreeRootIdent, current))
  676. return NULL;
  677. if (exptype != expandedTypeID)
  678. continue;
  679. return makeNodeHandle(current); // make handle.
  680. }
  681. }
  682. }
  683. /**
  684. * Implements traversal of the Ancestor access, in reverse document order.
  685. */
  686. private class DescendantOrSelfTraverser extends DescendantTraverser
  687. {
  688. /**
  689. * Get the first potential identity that can be returned, which is the
  690. * axis context, in this case.
  691. *
  692. * @param identity The node identity of the root context of the traversal.
  693. *
  694. * @return The axis context.
  695. */
  696. protected int getFirstPotential(int identity)
  697. {
  698. return identity;
  699. }
  700. /**
  701. * By the nature of the stateless traversal, the context node can not be
  702. * returned or the iteration will go into an infinate loop. To see if
  703. * the self node should be processed, use this function.
  704. *
  705. * @param context The context node of this traversal.
  706. *
  707. * @return the first node in the traversal.
  708. */
  709. public int first(int context)
  710. {
  711. return context;
  712. }
  713. }
  714. /**
  715. * Implements traversal of the entire subtree, including the root node.
  716. */
  717. private class AllFromNodeTraverser extends DescendantOrSelfTraverser
  718. {
  719. /**
  720. * Traverse to the next node after the current node.
  721. *
  722. * @param context The context node of this iteration.
  723. * @param current The current node of the iteration.
  724. *
  725. * @return the next node in the iteration, or DTM.NULL.
  726. */
  727. public int next(int context, int current)
  728. {
  729. int subtreeRootIdent = makeNodeIdentity(context);
  730. for (current = makeNodeIdentity(current) + 1; ; current++)
  731. {
  732. // Trickological code: _exptype() has the side-effect of
  733. // running nextNode until the specified node has been loaded,
  734. // and thus can be used to ensure that incremental construction of
  735. // the DTM has gotten this far. Using it just for that side-effect
  736. // is quite a kluge...
  737. _exptype(current); // make sure it's here.
  738. if (!isDescendant(subtreeRootIdent, current))
  739. return NULL;
  740. return makeNodeHandle(current); // make handle.
  741. }
  742. }
  743. }
  744. /**
  745. * Implements traversal of the following access, in document order.
  746. */
  747. private class FollowingTraverser extends DescendantTraverser
  748. {
  749. /**
  750. * Get the first of the following.
  751. *
  752. * @param context The context node of this traversal. This is the point
  753. * that the traversal starts from.
  754. * @return the first node in the traversal.
  755. */
  756. public int first(int context)
  757. {
  758. // Compute in ID space
  759. context=makeNodeIdentity(context);
  760. int first;
  761. int type = _type(context);
  762. if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
  763. {
  764. context = _parent(context);
  765. first = _firstch(context);
  766. if (NULL != first)
  767. return makeNodeHandle(first);
  768. }
  769. do
  770. {
  771. first = _nextsib(context);
  772. if (NULL == first)
  773. context = _parent(context);
  774. }
  775. while (NULL == first && NULL != context);
  776. return makeNodeHandle(first);
  777. }
  778. /**
  779. * Get the first of the following.
  780. *
  781. * @param context The context node of this traversal. This is the point
  782. * of origin for the traversal -- its "root node" or starting point.
  783. * @param expandedTypeID The expanded type ID that must match.
  784. *
  785. * @return the first node in the traversal.
  786. */
  787. public int first(int context, int expandedTypeID)
  788. {
  789. // %REVIEW% This looks like it might want shift into identity space
  790. // to avoid repeated conversion in the individual functions
  791. int first;
  792. int type = getNodeType(context);
  793. if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
  794. {
  795. context = getParent(context);
  796. first = getFirstChild(context);
  797. if (NULL != first)
  798. {
  799. if (getExpandedTypeID(first) == expandedTypeID)
  800. return first;
  801. else
  802. return next(context, first, expandedTypeID);
  803. }
  804. }
  805. do
  806. {
  807. first = getNextSibling(context);
  808. if (NULL == first)
  809. context = getParent(context);
  810. else
  811. {
  812. if (getExpandedTypeID(first) == expandedTypeID)
  813. return first;
  814. else
  815. return next(context, first, expandedTypeID);
  816. }
  817. }
  818. while (NULL == first && NULL != context);
  819. return first;
  820. }
  821. /**
  822. * Traverse to the next node after the current node.
  823. *
  824. * @param context The context node of this iteration.
  825. * @param current The current node of the iteration.
  826. *
  827. * @return the next node in the iteration, or DTM.NULL.
  828. */
  829. public int next(int context, int current)
  830. {
  831. // Compute in identity space
  832. current=makeNodeIdentity(current);
  833. while (true)
  834. {
  835. current++; // Only works on IDs, not handles.
  836. // %REVIEW% Are we using handles or indexes?
  837. int type = _type(current); // may call nextNode()
  838. if (NULL == type)
  839. return NULL;
  840. if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
  841. continue;
  842. return makeNodeHandle(current); // make handle.
  843. }
  844. }
  845. /**
  846. * Traverse to the next node after the current node that is matched
  847. * by the expanded type ID.
  848. *
  849. * @param context The context node of this iteration.
  850. * @param current The current node of the iteration.
  851. * @param expandedTypeID The expanded type ID that must match.
  852. *
  853. * @return the next node in the iteration, or DTM.NULL.
  854. */
  855. public int next(int context, int current, int expandedTypeID)
  856. {
  857. // Compute in ID space
  858. current=makeNodeIdentity(current);
  859. while (true)
  860. {
  861. current++;
  862. int etype = _exptype(current); // may call nextNode()
  863. if (NULL == etype)
  864. return NULL;
  865. if (etype != expandedTypeID)
  866. continue;
  867. return makeNodeHandle(current); // make handle.
  868. }
  869. }
  870. }
  871. /**
  872. * Implements traversal of the Ancestor access, in reverse document order.
  873. */
  874. private class FollowingSiblingTraverser extends DTMAxisTraverser
  875. {
  876. /**
  877. * Traverse to the next node after the current node.
  878. *
  879. * @param context The context node of this iteration.
  880. * @param current The current node of the iteration.
  881. *
  882. * @return the next node in the iteration, or DTM.NULL.
  883. */
  884. public int next(int context, int current)
  885. {
  886. return getNextSibling(current);
  887. }
  888. /**
  889. * Traverse to the next node after the current node that is matched
  890. * by the expanded type ID.
  891. *
  892. * @param context The context node of this iteration.
  893. * @param current The current node of the iteration.
  894. * @param expandedTypeID The expanded type ID that must match.
  895. *
  896. * @return the next node in the iteration, or DTM.NULL.
  897. */
  898. public int next(int context, int current, int expandedTypeID)
  899. {
  900. while (DTM.NULL != (current = getNextSibling(current)))
  901. {
  902. if (getExpandedTypeID(current) == expandedTypeID)
  903. return current;
  904. }
  905. return NULL;
  906. }
  907. }
  908. /**
  909. * Implements traversal of the Ancestor access, in reverse document order.
  910. */
  911. private class NamespaceDeclsTraverser extends DTMAxisTraverser
  912. {
  913. /**
  914. * Traverse to the next node after the current node.
  915. *
  916. * @param context The context node of this iteration.
  917. * @param current The current node of the iteration.
  918. *
  919. * @return the next node in the iteration, or DTM.NULL.
  920. */
  921. public int next(int context, int current)
  922. {
  923. return (context == current)
  924. ? getFirstNamespaceNode(context, false)
  925. : getNextNamespaceNode(context, current, false);
  926. }
  927. /**
  928. * Traverse to the next node after the current node that is matched
  929. * by the expanded type ID.
  930. *
  931. * @param context The context node of this iteration.
  932. * @param current The current node of the iteration.
  933. * @param expandedTypeID The expanded type ID that must match.
  934. *
  935. * @return the next node in the iteration, or DTM.NULL.
  936. */
  937. public int next(int context, int current, int expandedTypeID)
  938. {
  939. current = (context == current)
  940. ? getFirstNamespaceNode(context, false)
  941. : getNextNamespaceNode(context, current, false);
  942. do
  943. {
  944. if (getExpandedTypeID(current) == expandedTypeID)
  945. return current;
  946. }
  947. while (DTM.NULL
  948. != (current = getNextNamespaceNode(context, current, false)));
  949. return NULL;
  950. }
  951. }
  952. /**
  953. * Implements traversal of the Ancestor access, in reverse document order.
  954. */
  955. private class NamespaceTraverser extends DTMAxisTraverser
  956. {
  957. /**
  958. * Traverse to the next node after the current node.
  959. *
  960. * @param context The context node of this iteration.
  961. * @param current The current node of the iteration.
  962. *
  963. * @return the next node in the iteration, or DTM.NULL.
  964. */
  965. public int next(int context, int current)
  966. {
  967. return (context == current)
  968. ? getFirstNamespaceNode(context, true)
  969. : getNextNamespaceNode(context, current, true);
  970. }
  971. /**
  972. * Traverse to the next node after the current node that is matched
  973. * by the expanded type ID.
  974. *
  975. * @param context The context node of this iteration.
  976. * @param current The current node of the iteration.
  977. * @param expandedTypeID The expanded type ID that must match.
  978. *
  979. * @return the next node in the iteration, or DTM.NULL.
  980. */
  981. public int next(int context, int current, int expandedTypeID)
  982. {
  983. current = (context == current)
  984. ? getFirstNamespaceNode(context, true)
  985. : getNextNamespaceNode(context, current, true);
  986. do
  987. {
  988. if (getExpandedTypeID(current) == expandedTypeID)
  989. return current;
  990. }
  991. while (DTM.NULL
  992. != (current = getNextNamespaceNode(context, current, true)));
  993. return NULL;
  994. }
  995. }
  996. /**
  997. * Implements traversal of the Ancestor access, in reverse document order.
  998. */
  999. private class ParentTraverser extends DTMAxisTraverser
  1000. {
  1001. /**
  1002. * By the nature of the stateless traversal, the context node can not be
  1003. * returned or the iteration will go into an infinate loop. So to traverse
  1004. * an axis, the first function must be used to get the first node.
  1005. *
  1006. * <p>This method needs to be overloaded only by those axis that process
  1007. * the self node. <\p>
  1008. *
  1009. * @param context The context node of this traversal. This is the point
  1010. * that the traversal starts from.
  1011. * @return the first node in the traversal.
  1012. */
  1013. public int first(int context)
  1014. {
  1015. return getParent(context);
  1016. }
  1017. /**
  1018. * By the nature of the stateless traversal, the context node can not be
  1019. * returned or the iteration will go into an infinate loop. So to traverse
  1020. * an axis, the first function must be used to get the first node.
  1021. *
  1022. * <p>This method needs to be overloaded only by those axis that process
  1023. * the self node. <\p>
  1024. *
  1025. * @param context The context node of this traversal. This is the point
  1026. * of origin for the traversal -- its "root node" or starting point.
  1027. * @param expandedTypeID The expanded type ID that must match.
  1028. *
  1029. * @return the first node in the traversal.
  1030. */
  1031. public int first(int current, int expandedTypeID)
  1032. {
  1033. // Compute in ID space
  1034. current = makeNodeIdentity(current);
  1035. while (NULL != (current = m_parent.elementAt(current)))
  1036. {
  1037. if (m_exptype.elementAt(current) == expandedTypeID)
  1038. return makeNodeHandle(current);
  1039. }
  1040. return NULL;
  1041. }
  1042. /**
  1043. * Traverse to the next node after the current node.
  1044. *
  1045. * @param context The context node of this iteration.
  1046. * @param current The current node of the iteration.
  1047. *
  1048. * @return the next node in the iteration, or DTM.NULL.
  1049. */
  1050. public int next(int context, int current)
  1051. {
  1052. return NULL;
  1053. }
  1054. /**
  1055. * Traverse to the next node after the current node that is matched
  1056. * by the expanded type ID.
  1057. *
  1058. * @param context The context node of this iteration.
  1059. * @param current The current node of the iteration.
  1060. * @param expandedTypeID The expanded type ID that must match.
  1061. *
  1062. * @return the next node in the iteration, or DTM.NULL.
  1063. */
  1064. public int next(int context, int current, int expandedTypeID)
  1065. {
  1066. return NULL;
  1067. }
  1068. }
  1069. /**
  1070. * Implements traversal of the Ancestor access, in reverse document order.
  1071. */
  1072. private class PrecedingTraverser extends DTMAxisTraverser
  1073. {
  1074. /**
  1075. * Tell if the current identity is an ancestor of the context identity.
  1076. * This is an expensive operation, made worse by the stateless traversal.
  1077. * But the preceding axis is used fairly infrequently.
  1078. *
  1079. * @param contextIdent The context node of the axis traversal.
  1080. * @param currentIdent The node in question.
  1081. * @return true if the currentIdent node is an ancestor of contextIdent.
  1082. */
  1083. protected boolean isAncestor(int contextIdent, int currentIdent)
  1084. {
  1085. // %REVIEW% See comments in IsAfterAxis; using the "successor" of
  1086. // contextIdent is probably more efficient.
  1087. for (contextIdent = m_parent.elementAt(contextIdent); DTM.NULL != contextIdent;
  1088. contextIdent = m_parent.elementAt(contextIdent))
  1089. {
  1090. if (contextIdent == currentIdent)
  1091. return true;
  1092. }
  1093. return false;
  1094. }
  1095. /**
  1096. * Traverse to the next node after the current node.
  1097. *
  1098. * @param context The context node of this iteration.
  1099. * @param current The current node of the iteration.
  1100. *
  1101. * @return the next node in the iteration, or DTM.NULL.
  1102. */
  1103. public int next(int context, int current)
  1104. {
  1105. // compute in ID space
  1106. int subtreeRootIdent = makeNodeIdentity(context);
  1107. for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
  1108. {
  1109. short type = _type(current);
  1110. if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type
  1111. || isAncestor(subtreeRootIdent, current))
  1112. continue;
  1113. return makeNodeHandle(current); // make handle.
  1114. }
  1115. return NULL;
  1116. }
  1117. /**
  1118. * Traverse to the next node after the current node that is matched
  1119. * by the expanded type ID.
  1120. *
  1121. * @param context The context node of this iteration.
  1122. * @param current The current node of the iteration.
  1123. * @param expandedTypeID The expanded type ID that must match.
  1124. *
  1125. * @return the next node in the iteration, or DTM.NULL.
  1126. */
  1127. public int next(int context, int current, int expandedTypeID)
  1128. {
  1129. // Compute in ID space
  1130. int subtreeRootIdent = makeNodeIdentity(context);
  1131. for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
  1132. {
  1133. int exptype = m_exptype.elementAt(current);
  1134. if (exptype != expandedTypeID
  1135. || isAncestor(subtreeRootIdent, current))
  1136. continue;
  1137. return makeNodeHandle(current); // make handle.
  1138. }
  1139. return NULL;
  1140. }
  1141. }
  1142. /**
  1143. * Implements traversal of the Ancestor and the Preceding axis,
  1144. * in reverse document order.
  1145. */
  1146. private class PrecedingAndAncestorTraverser extends DTMAxisTraverser
  1147. {
  1148. /**
  1149. * Traverse to the next node after the current node.
  1150. *
  1151. * @param context The context node of this iteration.
  1152. * @param current The current node of the iteration.
  1153. *
  1154. * @return the next node in the iteration, or DTM.NULL.
  1155. */
  1156. public int next(int context, int current)
  1157. {
  1158. // Compute in ID space
  1159. int subtreeRootIdent = makeNodeIdentity(context );
  1160. for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
  1161. {
  1162. short type = _type(current);
  1163. if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
  1164. continue;
  1165. return makeNodeHandle(current); // make handle.
  1166. }
  1167. return NULL;
  1168. }
  1169. /**
  1170. * Traverse to the next node after the current node that is matched
  1171. * by the expanded type ID.
  1172. *
  1173. * @param context The context node of this iteration.
  1174. * @param current The current node of the iteration.
  1175. * @param expandedTypeID The expanded type ID that must match.
  1176. *
  1177. * @return the next node in the iteration, or DTM.NULL.
  1178. */
  1179. public int next(int context, int current, int expandedTypeID)
  1180. {
  1181. // Compute in ID space
  1182. int subtreeRootIdent = makeNodeIdentity(context);
  1183. for (current = makeNodeIdentity(current) - 1; current >= 0; current--)
  1184. {
  1185. int exptype = m_exptype.elementAt(current);
  1186. if (exptype != expandedTypeID)
  1187. continue;
  1188. return makeNodeHandle(current); // make handle.
  1189. }
  1190. return NULL;
  1191. }
  1192. }
  1193. /**
  1194. * Implements traversal of the Ancestor access, in reverse document order.
  1195. */
  1196. private class PrecedingSiblingTraverser extends DTMAxisTraverser
  1197. {
  1198. /**
  1199. * Traverse to the next node after the current node.
  1200. *
  1201. * @param context The context node of this iteration.
  1202. * @param current The current node of the iteration.
  1203. *
  1204. * @return the next node in the iteration, or DTM.NULL.
  1205. */
  1206. public int next(int context, int current)
  1207. {
  1208. return getPreviousSibling(current);
  1209. }
  1210. /**
  1211. * Traverse to the next node after the current node that is matched
  1212. * by the expanded type ID.
  1213. *
  1214. * @param context The context node of this iteration.
  1215. * @param current The current node of the iteration.
  1216. * @param expandedTypeID The expanded type ID that must match.
  1217. *
  1218. * @return the next node in the iteration, or DTM.NULL.
  1219. */
  1220. public int next(int context, int current, int expandedTypeID)
  1221. {
  1222. while (DTM.NULL != (current = getPreviousSibling(current)))
  1223. {
  1224. if (getExpandedTypeID(current) == expandedTypeID)
  1225. return current;
  1226. }
  1227. return NULL;
  1228. }
  1229. }
  1230. /**
  1231. * Implements traversal of the Self axis.
  1232. */
  1233. private class SelfTraverser extends DTMAxisTraverser
  1234. {
  1235. /**
  1236. * By the nature of the stateless traversal, the context node can not be
  1237. * returned or the iteration will go into an infinate loop. To see if
  1238. * the self node should be processed, use this function.
  1239. *
  1240. * @param context The context node of this traversal.
  1241. *
  1242. * @return the first node in the traversal.
  1243. */
  1244. public int first(int context)
  1245. {
  1246. return context;
  1247. }
  1248. /**
  1249. * By the nature of the stateless traversal, the context node can not be
  1250. * returned or the iteration will go into an infinate loop. To see if
  1251. * the self node should be processed, use this function. If the context
  1252. * node does not match the expanded type ID, this function will return
  1253. * false.
  1254. *
  1255. * @param context The context node of this traversal.
  1256. * @param expandedTypeID The expanded type ID that must match.
  1257. *
  1258. * @return the first node in the traversal.
  1259. */
  1260. public int first(int context, int expandedTypeID)
  1261. {
  1262. return (getExpandedTypeID(context) == expandedTypeID) ? context : NULL;
  1263. }
  1264. /**
  1265. * Traverse to the next node after the current node.
  1266. *
  1267. * @param context The context node of this iteration.
  1268. * @param current The current node of the iteration.
  1269. *
  1270. * @return Always return NULL for this axis.
  1271. */
  1272. public int next(int context, int current)
  1273. {
  1274. return NULL;
  1275. }
  1276. /**
  1277. * Traverse to the next node after the current node that is matched
  1278. * by the expanded type ID.
  1279. *
  1280. * @param context The context node of this iteration.
  1281. * @param current The current node of the iteration.
  1282. * @param expandedTypeID The expanded type ID that must match.
  1283. *
  1284. * @return the next node in the iteration, or DTM.NULL.
  1285. */
  1286. public int next(int context, int current, int expandedTypeID)
  1287. {
  1288. return NULL;
  1289. }
  1290. }
  1291. /**
  1292. * Implements traversal of the Ancestor access, in reverse document order.
  1293. */
  1294. private class AllFromRootTraverser extends AllFromNodeTraverser
  1295. {
  1296. /**
  1297. * Return the root.
  1298. *
  1299. * @param context The context node of this traversal.
  1300. *
  1301. * @return the first node in the traversal.
  1302. */
  1303. public int first(int context)
  1304. {
  1305. return getDocumentRoot(context);
  1306. }
  1307. /**
  1308. * Return the root if it matches the expanded type ID.
  1309. *
  1310. * @param context The context node of this traversal.
  1311. * @param expandedTypeID The expanded type ID that must match.
  1312. *
  1313. * @return the first node in the traversal.
  1314. */
  1315. public int first(int context, int expandedTypeID)
  1316. {
  1317. return (getExpandedTypeID(getDocumentRoot(context)) == expandedTypeID)
  1318. ? context : next(context, context, expandedTypeID);
  1319. }
  1320. /**
  1321. * Traverse to the next node after the current node.
  1322. *
  1323. * @param context The context node of this iteration.
  1324. * @param current The current node of the iteration.
  1325. *
  1326. * @return the next node in the iteration, or DTM.NULL.
  1327. */
  1328. public int next(int context, int current)
  1329. {
  1330. // Compute in ID space
  1331. int subtreeRootIdent = makeNodeIdentity(context);
  1332. for (current = makeNodeIdentity(current) + 1; ; current++)
  1333. {
  1334. // Kluge test: Just make sure +1 yielded a real node
  1335. int type = _type(current); // may call nextNode()
  1336. if (type == NULL)
  1337. return NULL;
  1338. return makeNodeHandle(current); // make handle.
  1339. }
  1340. }
  1341. /**
  1342. * Traverse to the next node after the current node that is matched
  1343. * by the expanded type ID.
  1344. *
  1345. * @param context The context node of this iteration.
  1346. * @param current The current node of the iteration.
  1347. * @param expandedTypeID The expanded type ID that must match.
  1348. *
  1349. * @return the next node in the iteration, or DTM.NULL.
  1350. */
  1351. public int next(int context, int current, int expandedTypeID)
  1352. {
  1353. // Compute in ID space
  1354. int subtreeRootIdent = makeNodeIdentity(context);
  1355. for (current = makeNodeIdentity(current) + 1; ; current++)
  1356. {
  1357. int exptype = _exptype(current); // may call nextNode()
  1358. if (exptype == NULL)
  1359. return NULL;
  1360. if (exptype != expandedTypeID)
  1361. continue;
  1362. return makeNodeHandle(current); // make handle.
  1363. }
  1364. }
  1365. }
  1366. /**
  1367. * Implements traversal of the Self axis.
  1368. */
  1369. private class RootTraverser extends AllFromRootTraverser
  1370. {
  1371. /**
  1372. * Traverse to the next node after the current node.
  1373. *
  1374. * @param context The context node of this iteration.
  1375. * @param current The current node of the iteration.
  1376. *
  1377. * @return Always return NULL for this axis.
  1378. */
  1379. public int next(int context, int current)
  1380. {
  1381. return NULL;
  1382. }
  1383. /**
  1384. * Traverse to the next node after the current node that is matched
  1385. * by the expanded type ID.
  1386. *
  1387. * @param context The context node of this iteration.
  1388. * @param current The current node of the iteration.
  1389. * @param expandedTypeID The expanded type ID that must match.
  1390. *
  1391. * @return the next node in the iteration, or DTM.NULL.
  1392. */
  1393. public int next(int context, int current, int expandedTypeID)
  1394. {
  1395. return NULL;
  1396. }
  1397. }
  1398. /**
  1399. * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
  1400. * from and including the root.
  1401. */
  1402. private class DescendantOrSelfFromRootTraverser extends DescendantTraverser
  1403. {
  1404. /**
  1405. * Get the first potential identity that can be returned, which is the axis
  1406. * root context in this case.
  1407. *
  1408. * @param identity The node identity of the root context of the traversal.
  1409. *
  1410. * @return The identity argument.
  1411. */
  1412. protected int getFirstPotential(int identity)
  1413. {
  1414. return identity;
  1415. }
  1416. /**
  1417. * Get the first potential identity that can be returned.
  1418. * @param handle handle to the root context.
  1419. * @return identity of the root of the subtree.
  1420. */
  1421. protected int getSubtreeRoot(int handle)
  1422. {
  1423. // %REVIEW% Shouldn't this always be 0?
  1424. return makeNodeIdentity(getDocument());
  1425. }
  1426. /**
  1427. * Return the root.
  1428. *
  1429. * @param context The context node of this traversal.
  1430. *
  1431. * @return the first node in the traversal.
  1432. */
  1433. public int first(int context)
  1434. {
  1435. return getDocumentRoot(context);
  1436. }
  1437. /**
  1438. * By the nature of the stateless traversal, the context node can not be
  1439. * returned or the iteration will go into an infinate loop. So to traverse
  1440. * an axis, the first function must be used to get the first node.
  1441. *
  1442. * <p>This method needs to be overloaded only by those axis that process
  1443. * the self node. <\p>
  1444. *
  1445. * @param context The context node of this traversal. This is the point
  1446. * of origin for the traversal -- its "root node" or starting point.
  1447. * @param expandedTypeID The expanded type ID that must match.
  1448. *
  1449. * @return the first node in the traversal.
  1450. */
  1451. public int first(int context, int expandedTypeID)
  1452. {
  1453. if (isIndexed(expandedTypeID))
  1454. {
  1455. int identity = 0;
  1456. int firstPotential = getFirstPotential(identity);
  1457. return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
  1458. }
  1459. int root = first(context);
  1460. return next(root, root, expandedTypeID);
  1461. }
  1462. }
  1463. /**
  1464. * A non-xpath axis, returns all nodes that aren't namespaces or attributes,
  1465. * from but not including the root.
  1466. */
  1467. private class DescendantFromRootTraverser extends DescendantTraverser
  1468. {
  1469. /**
  1470. * Get the first potential identity that can be returned, which is the axis
  1471. * root context in this case.
  1472. *
  1473. * @param identity The node identity of the root context of the traversal.
  1474. *
  1475. * @return The identity argument.
  1476. */
  1477. protected int getFirstPotential(int identity)
  1478. {
  1479. return _firstch(0);
  1480. }
  1481. /**
  1482. * Get the first potential identity that can be returned.
  1483. * @param handle handle to the root context.
  1484. * @return identity of the root of the subtree.
  1485. */
  1486. protected int getSubtreeRoot(int handle)
  1487. {
  1488. return 0;
  1489. }
  1490. /**
  1491. * Return the root.
  1492. *
  1493. * @param context The context node of this traversal.
  1494. *
  1495. * @return the first node in the traversal.
  1496. */
  1497. public int first(int context)
  1498. {
  1499. return makeNodeHandle(_firstch(0));
  1500. }
  1501. /**
  1502. * By the nature of the stateless traversal, the context node can not be
  1503. * returned or the iteration will go into an infinate loop. So to traverse
  1504. * an axis, the first function must be used to get the first node.
  1505. *
  1506. * <p>This method needs to be overloaded only by those axis that process
  1507. * the self node. <\p>
  1508. *
  1509. * @param context The context node of this traversal. This is the point
  1510. * of origin for the traversal -- its "root node" or starting point.
  1511. * @param expandedTypeID The expanded type ID that must match.
  1512. *
  1513. * @return the first node in the traversal.
  1514. */
  1515. public int first(int context, int expandedTypeID)
  1516. {
  1517. if (isIndexed(expandedTypeID))
  1518. {
  1519. int identity = 0;
  1520. int firstPotential = getFirstPotential(identity);
  1521. return makeNodeHandle(getNextIndexed(identity, firstPotential, expandedTypeID));
  1522. }
  1523. int root = getDocumentRoot(context);
  1524. return next(root, root, expandedTypeID);
  1525. }
  1526. }
  1527. }