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.xpath;
  58. import org.w3c.dom.Node;
  59. import org.w3c.dom.NodeList;
  60. //import org.w3c.dom.NamedNodeMap;
  61. import org.w3c.dom.traversal.NodeIterator;
  62. //import org.w3c.dom.traversal.NodeFilter;
  63. //import org.w3c.dom.DOMException;
  64. import org.apache.xml.dtm.DTM;
  65. import org.apache.xml.dtm.DTMFilter;
  66. import org.apache.xml.dtm.DTMIterator;
  67. import org.apache.xml.dtm.DTMManager;
  68. import org.apache.xml.utils.NodeVector;
  69. import org.apache.xpath.axes.ContextNodeList;
  70. import org.apache.xpath.res.XPATHErrorResources;
  71. import org.apache.xalan.res.XSLMessages;
  72. /**
  73. * <meta name="usage" content="advanced"/>
  74. * <p>The NodeSetDTM class can act as either a NodeVector,
  75. * NodeList, or NodeIterator. However, in order for it to
  76. * act as a NodeVector or NodeList, it's required that
  77. * setShouldCacheNodes(true) be called before the first
  78. * nextNode() is called, in order that nodes can be added
  79. * as they are fetched. Derived classes that implement iterators
  80. * must override runTo(int index), in order that they may
  81. * run the iteration to the given index. </p>
  82. *
  83. * <p>Note that we directly implement the DOM's NodeIterator
  84. * interface. We do not emulate all the behavior of the
  85. * standard NodeIterator. In particular, we do not guarantee
  86. * to present a "live view" of the document ... but in XSLT,
  87. * the source document should never be mutated, so this should
  88. * never be an issue.</p>
  89. *
  90. * <p>Thought: Should NodeSetDTM really implement NodeList and NodeIterator,
  91. * or should there be specific subclasses of it which do so? The
  92. * advantage of doing it all here is that all NodeSetDTMs will respond
  93. * to the same calls; the disadvantage is that some of them may return
  94. * less-than-enlightening results when you do so.</p>
  95. */
  96. public class NodeSetDTM extends NodeVector
  97. implements /* NodeList, NodeIterator, */ DTMIterator,
  98. Cloneable
  99. {
  100. /**
  101. * Create an empty nodelist.
  102. */
  103. public NodeSetDTM(DTMManager dtmManager)
  104. {
  105. super();
  106. m_manager = dtmManager;
  107. }
  108. /**
  109. * Create an empty, using the given block size.
  110. *
  111. * @param blocksize Size of blocks to allocate
  112. * @param dummy pass zero for right now...
  113. */
  114. public NodeSetDTM(int blocksize, int dummy, DTMManager dtmManager)
  115. {
  116. super(blocksize);
  117. m_manager = dtmManager;
  118. }
  119. // %TBD%
  120. // /**
  121. // * Create a NodeSetDTM, and copy the members of the
  122. // * given nodelist into it.
  123. // *
  124. // * @param nodelist List of Nodes to be made members of the new set.
  125. // */
  126. // public NodeSetDTM(NodeList nodelist)
  127. // {
  128. //
  129. // super();
  130. //
  131. // addNodes(nodelist);
  132. // }
  133. /**
  134. * Create a NodeSetDTM, and copy the members of the
  135. * given NodeSetDTM into it.
  136. *
  137. * @param nodelist Set of Nodes to be made members of the new set.
  138. */
  139. public NodeSetDTM(NodeSetDTM nodelist)
  140. {
  141. super();
  142. m_manager = nodelist.getDTMManager();
  143. m_root = nodelist.getRoot();
  144. addNodes((DTMIterator) nodelist);
  145. }
  146. /**
  147. * Create a NodeSetDTM, and copy the members of the
  148. * given DTMIterator into it.
  149. *
  150. * @param ni Iterator which yields Nodes to be made members of the new set.
  151. */
  152. public NodeSetDTM(DTMIterator ni)
  153. {
  154. super();
  155. m_manager = ni.getDTMManager();
  156. m_root = ni.getRoot();
  157. addNodes(ni);
  158. }
  159. /**
  160. * Create a NodeSetDTM, and copy the members of the
  161. * given DTMIterator into it.
  162. *
  163. * @param ni Iterator which yields Nodes to be made members of the new set.
  164. */
  165. public NodeSetDTM(NodeIterator iterator, XPathContext xctxt)
  166. {
  167. super();
  168. Node node;
  169. m_manager = xctxt.getDTMManager();
  170. while (null != (node = iterator.nextNode()))
  171. {
  172. int handle = xctxt.getDTMHandleFromNode(node);
  173. addNodeInDocOrder(handle, xctxt);
  174. }
  175. }
  176. /**
  177. * Create a NodeSetDTM, and copy the members of the
  178. * given DTMIterator into it.
  179. *
  180. * @param ni Iterator which yields Nodes to be made members of the new set.
  181. */
  182. public NodeSetDTM(NodeList nodeList, XPathContext xctxt)
  183. {
  184. super();
  185. m_manager = xctxt.getDTMManager();
  186. int n = nodeList.getLength();
  187. for (int i = 0; i < n; i++)
  188. {
  189. Node node = nodeList.item(i);
  190. int handle = xctxt.getDTMHandleFromNode(node);
  191. // Do not reorder or strip duplicate nodes from the given DOM nodelist
  192. addNode(handle); // addNodeInDocOrder(handle, xctxt);
  193. }
  194. }
  195. /**
  196. * Create a NodeSetDTM which contains the given Node.
  197. *
  198. * @param node Single node to be added to the new set.
  199. */
  200. public NodeSetDTM(int node, DTMManager dtmManager)
  201. {
  202. super();
  203. m_manager = dtmManager;
  204. addNode(node);
  205. }
  206. /**
  207. * Set the environment in which this iterator operates, which should provide:
  208. * a node (the context node... same value as "root" defined below)
  209. * a pair of non-zero positive integers (the context position and the context size)
  210. * a set of variable bindings
  211. * a function library
  212. * the set of namespace declarations in scope for the expression.
  213. *
  214. * <p>At this time the exact implementation of this environment is application
  215. * dependent. Probably a proper interface will be created fairly soon.</p>
  216. *
  217. * @param environment The environment object.
  218. */
  219. public void setEnvironment(Object environment)
  220. {
  221. // no-op
  222. }
  223. /**
  224. * @return The root node of the Iterator, as specified when it was created.
  225. * For non-Iterator NodeSetDTMs, this will be null.
  226. */
  227. public int getRoot()
  228. {
  229. if(DTM.NULL == m_root)
  230. {
  231. if(size() > 0)
  232. return item(0);
  233. else
  234. return DTM.NULL;
  235. }
  236. else
  237. return m_root;
  238. }
  239. /**
  240. * Initialize the context values for this expression
  241. * after it is cloned.
  242. *
  243. * @param execContext The XPath runtime context for this
  244. * transformation.
  245. */
  246. public void setRoot(int context, Object environment)
  247. {
  248. // no-op, I guess... (-sb)
  249. }
  250. /**
  251. * Clone this NodeSetDTM.
  252. * At this time, we only expect this to be used with LocPathIterators;
  253. * it may not work with other kinds of NodeSetDTMs.
  254. *
  255. * @return a new NodeSetDTM of the same type, having the same state...
  256. * though unless overridden in the subclasses, it may not copy all
  257. * the state information.
  258. *
  259. * @throws CloneNotSupportedException if this subclass of NodeSetDTM
  260. * does not support the clone() operation.
  261. */
  262. public Object clone() throws CloneNotSupportedException
  263. {
  264. NodeSetDTM clone = (NodeSetDTM) super.clone();
  265. return clone;
  266. }
  267. /**
  268. * Get a cloned Iterator, and reset its state to the beginning of the
  269. * iteration.
  270. *
  271. * @return a new NodeSetDTM of the same type, having the same state...
  272. * except that the reset() operation has been called.
  273. *
  274. * @throws CloneNotSupportedException if this subclass of NodeSetDTM
  275. * does not support the clone() operation.
  276. */
  277. public DTMIterator cloneWithReset() throws CloneNotSupportedException
  278. {
  279. NodeSetDTM clone = (NodeSetDTM) clone();
  280. clone.reset();
  281. return clone;
  282. }
  283. /**
  284. * Reset the iterator. May have no effect on non-iterator Nodesets.
  285. */
  286. public void reset()
  287. {
  288. m_next = 0;
  289. }
  290. /**
  291. * This attribute determines which node types are presented via the
  292. * iterator. The available set of constants is defined in the
  293. * <code>DTMFilter</code> interface. For NodeSetDTMs, the mask has been
  294. * hardcoded to show all nodes except EntityReference nodes, which have
  295. * no equivalent in the XPath data model.
  296. *
  297. * @return integer used as a bit-array, containing flags defined in
  298. * the DOM's DTMFilter class. The value will be
  299. * <code>SHOW_ALL & ~SHOW_ENTITY_REFERENCE</code>, meaning that
  300. * only entity references are suppressed.
  301. */
  302. public int getWhatToShow()
  303. {
  304. return DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE;
  305. }
  306. /**
  307. * The filter object used to screen nodes. Filters are applied to
  308. * further reduce (and restructure) the DTMIterator's view of the
  309. * document. In our case, we will be using hardcoded filters built
  310. * into our iterators... but getFilter() is part of the DOM's
  311. * DTMIterator interface, so we have to support it.
  312. *
  313. * @return null, which is slightly misleading. True, there is no
  314. * user-written filter object, but in fact we are doing some very
  315. * sophisticated custom filtering. A DOM purist might suggest
  316. * returning a placeholder object just to indicate that this is
  317. * not going to return all nodes selected by whatToShow.
  318. */
  319. public DTMFilter getFilter()
  320. {
  321. return null;
  322. }
  323. /**
  324. * The value of this flag determines whether the children of entity
  325. * reference nodes are visible to the iterator. If false, they will be
  326. * skipped over.
  327. * <br> To produce a view of the document that has entity references
  328. * expanded and does not expose the entity reference node itself, use the
  329. * whatToShow flags to hide the entity reference node and set
  330. * expandEntityReferences to true when creating the iterator. To produce
  331. * a view of the document that has entity reference nodes but no entity
  332. * expansion, use the whatToShow flags to show the entity reference node
  333. * and set expandEntityReferences to false.
  334. *
  335. * @return true for all iterators based on NodeSetDTM, meaning that the
  336. * contents of EntityRefrence nodes may be returned (though whatToShow
  337. * says that the EntityReferences themselves are not shown.)
  338. */
  339. public boolean getExpandEntityReferences()
  340. {
  341. return true;
  342. }
  343. /**
  344. * Get an instance of a DTM that "owns" a node handle. Since a node
  345. * iterator may be passed without a DTMManager, this allows the
  346. * caller to easily get the DTM using just the iterator.
  347. *
  348. * @param nodeHandle the nodeHandle.
  349. *
  350. * @return a non-null DTM reference.
  351. */
  352. public DTM getDTM(int nodeHandle)
  353. {
  354. return m_manager.getDTM(nodeHandle);
  355. }
  356. /* An instance of the DTMManager. */
  357. DTMManager m_manager;
  358. /**
  359. * Get an instance of the DTMManager. Since a node
  360. * iterator may be passed without a DTMManager, this allows the
  361. * caller to easily get the DTMManager using just the iterator.
  362. *
  363. * @return a non-null DTMManager reference.
  364. */
  365. public DTMManager getDTMManager()
  366. {
  367. return m_manager;
  368. }
  369. /**
  370. * Returns the next node in the set and advances the position of the
  371. * iterator in the set. After a DTMIterator is created, the first call
  372. * to nextNode() returns the first node in the set.
  373. * @return The next <code>Node</code> in the set being iterated over, or
  374. * <code>null</code> if there are no more members in that set.
  375. * @throws DOMException
  376. * INVALID_STATE_ERR: Raised if this method is called after the
  377. * <code>detach</code> method was invoked.
  378. */
  379. public int nextNode()
  380. {
  381. if ((m_next) < this.size())
  382. {
  383. int next = this.elementAt(m_next);
  384. m_next++;
  385. return next;
  386. }
  387. else
  388. return DTM.NULL;
  389. }
  390. /**
  391. * Returns the previous node in the set and moves the position of the
  392. * iterator backwards in the set.
  393. * @return The previous <code>Node</code> in the set being iterated over,
  394. * or<code>null</code> if there are no more members in that set.
  395. * @throws DOMException
  396. * INVALID_STATE_ERR: Raised if this method is called after the
  397. * <code>detach</code> method was invoked.
  398. * @throws RuntimeException thrown if this NodeSetDTM is not of
  399. * a cached type, and hence doesn't know what the previous node was.
  400. */
  401. public int previousNode()
  402. {
  403. if (!m_cacheNodes)
  404. throw new RuntimeException(
  405. XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_ITERATE, null)); //"This NodeSetDTM can not iterate to a previous node!");
  406. if ((m_next - 1) > 0)
  407. {
  408. m_next--;
  409. return this.elementAt(m_next);
  410. }
  411. else
  412. return DTM.NULL;
  413. }
  414. /**
  415. * Detaches the iterator from the set which it iterated over, releasing
  416. * any computational resources and placing the iterator in the INVALID
  417. * state. After<code>detach</code> has been invoked, calls to
  418. * <code>nextNode</code> or<code>previousNode</code> will raise the
  419. * exception INVALID_STATE_ERR.
  420. * <p>
  421. * This operation is a no-op in NodeSetDTM, and will not cause
  422. * INVALID_STATE_ERR to be raised by later operations.
  423. * </p>
  424. */
  425. public void detach(){}
  426. /**
  427. * Specify if it's OK for detach to release the iterator for reuse.
  428. *
  429. * @param allowRelease true if it is OK for detach to release this iterator
  430. * for pooling.
  431. */
  432. public void allowDetachToRelease(boolean allowRelease)
  433. {
  434. // no action for right now.
  435. }
  436. /**
  437. * Tells if this NodeSetDTM is "fresh", in other words, if
  438. * the first nextNode() that is called will return the
  439. * first node in the set.
  440. *
  441. * @return true if nextNode() would return the first node in the set,
  442. * false if it would return a later one.
  443. */
  444. public boolean isFresh()
  445. {
  446. return (m_next == 0);
  447. }
  448. /**
  449. * If an index is requested, NodeSetDTM will call this method
  450. * to run the iterator to the index. By default this sets
  451. * m_next to the index. If the index argument is -1, this
  452. * signals that the iterator should be run to the end.
  453. *
  454. * @param index Position to advance (or retreat) to, with
  455. * 0 requesting the reset ("fresh") position and -1 (or indeed
  456. * any out-of-bounds value) requesting the final position.
  457. * @throws RuntimeException thrown if this NodeSetDTM is not
  458. * one of the types which supports indexing/counting.
  459. */
  460. public void runTo(int index)
  461. {
  462. if (!m_cacheNodes)
  463. throw new RuntimeException(
  464. XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_INDEX, null)); //"This NodeSetDTM can not do indexing or counting functions!");
  465. if ((index >= 0) && (m_next < m_firstFree))
  466. m_next = index;
  467. else
  468. m_next = m_firstFree - 1;
  469. }
  470. /**
  471. * Returns the <code>index</code>th item in the collection. If
  472. * <code>index</code> is greater than or equal to the number of nodes in
  473. * the list, this returns <code>null</code>.
  474. *
  475. * TODO: What happens if index is out of range?
  476. *
  477. * @param index Index into the collection.
  478. * @return The node at the <code>index</code>th position in the
  479. * <code>NodeList</code>, or <code>null</code> if that is not a valid
  480. * index.
  481. */
  482. public int item(int index)
  483. {
  484. runTo(index);
  485. return this.elementAt(index);
  486. }
  487. /**
  488. * The number of nodes in the list. The range of valid child node indices is
  489. * 0 to <code>length-1</code> inclusive. Note that this operation requires
  490. * finding all the matching nodes, which may defeat attempts to defer
  491. * that work.
  492. *
  493. * @return integer indicating how many nodes are represented by this list.
  494. */
  495. public int getLength()
  496. {
  497. runTo(-1);
  498. return this.size();
  499. }
  500. /**
  501. * Add a node to the NodeSetDTM. Not all types of NodeSetDTMs support this
  502. * operation
  503. *
  504. * @param n Node to be added
  505. * @throws RuntimeException thrown if this NodeSetDTM is not of
  506. * a mutable type.
  507. */
  508. public void addNode(int n)
  509. {
  510. if (!m_mutable)
  511. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  512. this.addElement(n);
  513. }
  514. /**
  515. * Insert a node at a given position.
  516. *
  517. * @param n Node to be added
  518. * @param pos Offset at which the node is to be inserted,
  519. * with 0 being the first position.
  520. * @throws RuntimeException thrown if this NodeSetDTM is not of
  521. * a mutable type.
  522. */
  523. public void insertNode(int n, int pos)
  524. {
  525. if (!m_mutable)
  526. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  527. insertElementAt(n, pos);
  528. }
  529. /**
  530. * Remove a node.
  531. *
  532. * @param n Node to be added
  533. * @throws RuntimeException thrown if this NodeSetDTM is not of
  534. * a mutable type.
  535. */
  536. public void removeNode(int n)
  537. {
  538. if (!m_mutable)
  539. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  540. this.removeElement(n);
  541. }
  542. // %TBD%
  543. // /**
  544. // * Copy NodeList members into this nodelist, adding in
  545. // * document order. If a node is null, don't add it.
  546. // *
  547. // * @param nodelist List of nodes which should now be referenced by
  548. // * this NodeSetDTM.
  549. // * @throws RuntimeException thrown if this NodeSetDTM is not of
  550. // * a mutable type.
  551. // */
  552. // public void addNodes(NodeList nodelist)
  553. // {
  554. //
  555. // if (!m_mutable)
  556. // throw new RuntimeException("This NodeSetDTM is not mutable!");
  557. //
  558. // if (null != nodelist) // defensive to fix a bug that Sanjiva reported.
  559. // {
  560. // int nChildren = nodelist.getLength();
  561. //
  562. // for (int i = 0; i < nChildren; i++)
  563. // {
  564. // int obj = nodelist.item(i);
  565. //
  566. // if (null != obj)
  567. // {
  568. // addElement(obj);
  569. // }
  570. // }
  571. // }
  572. //
  573. // // checkDups();
  574. // }
  575. // %TBD%
  576. // /**
  577. // * <p>Copy NodeList members into this nodelist, adding in
  578. // * document order. Only genuine node references will be copied;
  579. // * nulls appearing in the source NodeSetDTM will
  580. // * not be added to this one. </p>
  581. // *
  582. // * <p> In case you're wondering why this function is needed: NodeSetDTM
  583. // * implements both DTMIterator and NodeList. If this method isn't
  584. // * provided, Java can't decide which of those to use when addNodes()
  585. // * is invoked. Providing the more-explicit match avoids that
  586. // * ambiguity.)</p>
  587. // *
  588. // * @param ns NodeSetDTM whose members should be merged into this NodeSetDTM.
  589. // * @throws RuntimeException thrown if this NodeSetDTM is not of
  590. // * a mutable type.
  591. // */
  592. // public void addNodes(NodeSetDTM ns)
  593. // {
  594. //
  595. // if (!m_mutable)
  596. // throw new RuntimeException("This NodeSetDTM is not mutable!");
  597. //
  598. // addNodes((DTMIterator) ns);
  599. // }
  600. /**
  601. * Copy NodeList members into this nodelist, adding in
  602. * document order. Null references are not added.
  603. *
  604. * @param iterator DTMIterator which yields the nodes to be added.
  605. * @throws RuntimeException thrown if this NodeSetDTM is not of
  606. * a mutable type.
  607. */
  608. public void addNodes(DTMIterator iterator)
  609. {
  610. if (!m_mutable)
  611. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  612. if (null != iterator) // defensive to fix a bug that Sanjiva reported.
  613. {
  614. int obj;
  615. while (DTM.NULL != (obj = iterator.nextNode()))
  616. {
  617. addElement(obj);
  618. }
  619. }
  620. // checkDups();
  621. }
  622. // %TBD%
  623. // /**
  624. // * Copy NodeList members into this nodelist, adding in
  625. // * document order. If a node is null, don't add it.
  626. // *
  627. // * @param nodelist List of nodes to be added
  628. // * @param support The XPath runtime context.
  629. // * @throws RuntimeException thrown if this NodeSetDTM is not of
  630. // * a mutable type.
  631. // */
  632. // public void addNodesInDocOrder(NodeList nodelist, XPathContext support)
  633. // {
  634. //
  635. // if (!m_mutable)
  636. // throw new RuntimeException("This NodeSetDTM is not mutable!");
  637. //
  638. // int nChildren = nodelist.getLength();
  639. //
  640. // for (int i = 0; i < nChildren; i++)
  641. // {
  642. // int node = nodelist.item(i);
  643. //
  644. // if (null != node)
  645. // {
  646. // addNodeInDocOrder(node, support);
  647. // }
  648. // }
  649. // }
  650. /**
  651. * Copy NodeList members into this nodelist, adding in
  652. * document order. If a node is null, don't add it.
  653. *
  654. * @param iterator DTMIterator which yields the nodes to be added.
  655. * @param support The XPath runtime context.
  656. * @throws RuntimeException thrown if this NodeSetDTM is not of
  657. * a mutable type.
  658. */
  659. public void addNodesInDocOrder(DTMIterator iterator, XPathContext support)
  660. {
  661. if (!m_mutable)
  662. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  663. int node;
  664. while (DTM.NULL != (node = iterator.nextNode()))
  665. {
  666. addNodeInDocOrder(node, support);
  667. }
  668. }
  669. // %TBD%
  670. // /**
  671. // * Add the node list to this node set in document order.
  672. // *
  673. // * @param start index.
  674. // * @param end index.
  675. // * @param testIndex index.
  676. // * @param nodelist The nodelist to add.
  677. // * @param support The XPath runtime context.
  678. // *
  679. // * @return false always.
  680. // * @throws RuntimeException thrown if this NodeSetDTM is not of
  681. // * a mutable type.
  682. // */
  683. // private boolean addNodesInDocOrder(int start, int end, int testIndex,
  684. // NodeList nodelist, XPathContext support)
  685. // {
  686. //
  687. // if (!m_mutable)
  688. // throw new RuntimeException("This NodeSetDTM is not mutable!");
  689. //
  690. // boolean foundit = false;
  691. // int i;
  692. // int node = nodelist.item(testIndex);
  693. //
  694. // for (i = end; i >= start; i--)
  695. // {
  696. // int child = elementAt(i);
  697. //
  698. // if (child == node)
  699. // {
  700. // i = -2; // Duplicate, suppress insert
  701. //
  702. // break;
  703. // }
  704. //
  705. // if (!support.getDOMHelper().isNodeAfter(node, child))
  706. // {
  707. // insertElementAt(node, i + 1);
  708. //
  709. // testIndex--;
  710. //
  711. // if (testIndex > 0)
  712. // {
  713. // boolean foundPrev = addNodesInDocOrder(0, i, testIndex, nodelist,
  714. // support);
  715. //
  716. // if (!foundPrev)
  717. // {
  718. // addNodesInDocOrder(i, size() - 1, testIndex, nodelist, support);
  719. // }
  720. // }
  721. //
  722. // break;
  723. // }
  724. // }
  725. //
  726. // if (i == -1)
  727. // {
  728. // insertElementAt(node, 0);
  729. // }
  730. //
  731. // return foundit;
  732. // }
  733. /**
  734. * Add the node into a vector of nodes where it should occur in
  735. * document order.
  736. * @param v Vector of nodes, presumably containing Nodes
  737. * @param obj Node object.
  738. *
  739. * @param node The node to be added.
  740. * @param test true if we should test for doc order
  741. * @param support The XPath runtime context.
  742. * @return insertIndex.
  743. * @throws RuntimeException thrown if this NodeSetDTM is not of
  744. * a mutable type.
  745. */
  746. public int addNodeInDocOrder(int node, boolean test, XPathContext support)
  747. {
  748. if (!m_mutable)
  749. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  750. int insertIndex = -1;
  751. if (test)
  752. {
  753. // This needs to do a binary search, but a binary search
  754. // is somewhat tough because the sequence test involves
  755. // two nodes.
  756. int size = size(), i;
  757. for (i = size - 1; i >= 0; i--)
  758. {
  759. int child = elementAt(i);
  760. if (child == node)
  761. {
  762. i = -2; // Duplicate, suppress insert
  763. break;
  764. }
  765. DTM dtm = support.getDTM(node);
  766. if (!dtm.isNodeAfter(node, child))
  767. {
  768. break;
  769. }
  770. }
  771. if (i != -2)
  772. {
  773. insertIndex = i + 1;
  774. insertElementAt(node, insertIndex);
  775. }
  776. }
  777. else
  778. {
  779. insertIndex = this.size();
  780. boolean foundit = false;
  781. for (int i = 0; i < insertIndex; i++)
  782. {
  783. if (i == node)
  784. {
  785. foundit = true;
  786. break;
  787. }
  788. }
  789. if (!foundit)
  790. addElement(node);
  791. }
  792. // checkDups();
  793. return insertIndex;
  794. } // end addNodeInDocOrder(Vector v, Object obj)
  795. /**
  796. * Add the node into a vector of nodes where it should occur in
  797. * document order.
  798. * @param v Vector of nodes, presumably containing Nodes
  799. * @param obj Node object.
  800. *
  801. * @param node The node to be added.
  802. * @param support The XPath runtime context.
  803. *
  804. * @return The index where it was inserted.
  805. * @throws RuntimeException thrown if this NodeSetDTM is not of
  806. * a mutable type.
  807. */
  808. public int addNodeInDocOrder(int node, XPathContext support)
  809. {
  810. if (!m_mutable)
  811. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  812. return addNodeInDocOrder(node, true, support);
  813. } // end addNodeInDocOrder(Vector v, Object obj)
  814. /**
  815. * Get the length of the list.
  816. *
  817. * @return The size of this node set.
  818. */
  819. public int size()
  820. {
  821. return super.size();
  822. }
  823. /**
  824. * Append a Node onto the vector.
  825. *
  826. * @param value The node to be added.
  827. * @throws RuntimeException thrown if this NodeSetDTM is not of
  828. * a mutable type.
  829. */
  830. public void addElement(int value)
  831. {
  832. if (!m_mutable)
  833. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  834. super.addElement(value);
  835. }
  836. /**
  837. * Inserts the specified node in this vector at the specified index.
  838. * Each component in this vector with an index greater or equal to
  839. * the specified index is shifted upward to have an index one greater
  840. * than the value it had previously.
  841. *
  842. * @param value The node to be inserted.
  843. * @param at The index where the insert should occur.
  844. * @throws RuntimeException thrown if this NodeSetDTM is not of
  845. * a mutable type.
  846. */
  847. public void insertElementAt(int value, int at)
  848. {
  849. if (!m_mutable)
  850. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  851. super.insertElementAt(value, at);
  852. }
  853. /**
  854. * Append the nodes to the list.
  855. *
  856. * @param nodes The nodes to be appended to this node set.
  857. * @throws RuntimeException thrown if this NodeSetDTM is not of
  858. * a mutable type.
  859. */
  860. public void appendNodes(NodeVector nodes)
  861. {
  862. if (!m_mutable)
  863. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  864. super.appendNodes(nodes);
  865. }
  866. /**
  867. * Inserts the specified node in this vector at the specified index.
  868. * Each component in this vector with an index greater or equal to
  869. * the specified index is shifted upward to have an index one greater
  870. * than the value it had previously.
  871. * @throws RuntimeException thrown if this NodeSetDTM is not of
  872. * a mutable type.
  873. */
  874. public void removeAllElements()
  875. {
  876. if (!m_mutable)
  877. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  878. super.removeAllElements();
  879. }
  880. /**
  881. * Removes the first occurrence of the argument from this vector.
  882. * If the object is found in this vector, each component in the vector
  883. * with an index greater or equal to the object's index is shifted
  884. * downward to have an index one smaller than the value it had
  885. * previously.
  886. *
  887. * @param s The node to be removed.
  888. *
  889. * @return True if the node was successfully removed
  890. * @throws RuntimeException thrown if this NodeSetDTM is not of
  891. * a mutable type.
  892. */
  893. public boolean removeElement(int s)
  894. {
  895. if (!m_mutable)
  896. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  897. return super.removeElement(s);
  898. }
  899. /**
  900. * Deletes the component at the specified index. Each component in
  901. * this vector with an index greater or equal to the specified
  902. * index is shifted downward to have an index one smaller than
  903. * the value it had previously.
  904. *
  905. * @param i The index of the node to be removed.
  906. * @throws RuntimeException thrown if this NodeSetDTM is not of
  907. * a mutable type.
  908. */
  909. public void removeElementAt(int i)
  910. {
  911. if (!m_mutable)
  912. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  913. super.removeElementAt(i);
  914. }
  915. /**
  916. * Sets the component at the specified index of this vector to be the
  917. * specified object. The previous component at that position is discarded.
  918. *
  919. * The index must be a value greater than or equal to 0 and less
  920. * than the current size of the vector.
  921. *
  922. * @param node The node to be set.
  923. * @param index The index of the node to be replaced.
  924. * @throws RuntimeException thrown if this NodeSetDTM is not of
  925. * a mutable type.
  926. */
  927. public void setElementAt(int node, int index)
  928. {
  929. if (!m_mutable)
  930. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  931. super.setElementAt(node, index);
  932. }
  933. /**
  934. * Same as setElementAt.
  935. *
  936. * @param node The node to be set.
  937. * @param index The index of the node to be replaced.
  938. * @throws RuntimeException thrown if this NodeSetDTM is not of
  939. * a mutable type.
  940. */
  941. public void setItem(int node, int index)
  942. {
  943. if (!m_mutable)
  944. throw new RuntimeException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_NOT_MUTABLE, null)); //"This NodeSetDTM is not mutable!");
  945. super.setElementAt(node, index);
  946. }
  947. /**
  948. * Get the nth element.
  949. *
  950. * @param i The index of the requested node.
  951. *
  952. * @return Node at specified index.
  953. */
  954. public int elementAt(int i)
  955. {
  956. runTo(i);
  957. return super.elementAt(i);
  958. }
  959. /**
  960. * Tell if the table contains the given node.
  961. *
  962. * @param s Node to look for
  963. *
  964. * @return True if the given node was found.
  965. */
  966. public boolean contains(int s)
  967. {
  968. runTo(-1);
  969. return super.contains(s);
  970. }
  971. /**
  972. * Searches for the first occurence of the given argument,
  973. * beginning the search at index, and testing for equality
  974. * using the equals method.
  975. *
  976. * @param elem Node to look for
  977. * @param index Index of where to start the search
  978. * @return the index of the first occurrence of the object
  979. * argument in this vector at position index or later in the
  980. * vector; returns -1 if the object is not found.
  981. */
  982. public int indexOf(int elem, int index)
  983. {
  984. runTo(-1);
  985. return super.indexOf(elem, index);
  986. }
  987. /**
  988. * Searches for the first occurence of the given argument,
  989. * beginning the search at index, and testing for equality
  990. * using the equals method.
  991. *
  992. * @param elem Node to look for
  993. * @return the index of the first occurrence of the object
  994. * argument in this vector at position index or later in the
  995. * vector; returns -1 if the object is not found.
  996. */
  997. public int indexOf(int elem)
  998. {
  999. runTo(-1);
  1000. return super.indexOf(elem);
  1001. }
  1002. /** If this node is being used as an iterator, the next index that nextNode()
  1003. * will return. */
  1004. transient protected int m_next = 0;
  1005. /**
  1006. * Get the current position, which is one less than
  1007. * the next nextNode() call will retrieve. i.e. if
  1008. * you call getCurrentPos() and the return is 0, the next
  1009. * fetch will take place at index 1.
  1010. *
  1011. * @return The the current position index.
  1012. */
  1013. public int getCurrentPos()
  1014. {
  1015. return m_next;
  1016. }
  1017. /**
  1018. * Set the current position in the node set.
  1019. * @param i Must be a valid index.
  1020. * @throws RuntimeException thrown if this NodeSetDTM is not of
  1021. * a cached type, and thus doesn't permit indexed access.
  1022. */
  1023. public void setCurrentPos(int i)
  1024. {
  1025. if (!m_cacheNodes)
  1026. throw new RuntimeException(
  1027. XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_INDEX, null)); //"This NodeSetDTM can not do indexing or counting functions!");
  1028. m_next = i;
  1029. }
  1030. /**
  1031. * Return the last fetched node. Needed to support the UnionPathIterator.
  1032. *
  1033. * @return the last fetched node.
  1034. * @throws RuntimeException thrown if this NodeSetDTM is not of
  1035. * a cached type, and thus doesn't permit indexed access.
  1036. */
  1037. public int getCurrentNode()
  1038. {
  1039. if (!m_cacheNodes)
  1040. throw new RuntimeException(
  1041. "This NodeSetDTM can not do indexing or counting functions!");
  1042. int saved = m_next;
  1043. // because nextNode always increments
  1044. // But watch out for copy29, where the root iterator didn't
  1045. // have nextNode called on it.
  1046. int current = (m_next > 0) ? m_next-1 : m_next;
  1047. int n = (current < m_firstFree) ? elementAt(current) : DTM.NULL;
  1048. m_next = saved; // HACK: I think this is a bit of a hack. -sb
  1049. return n;
  1050. }
  1051. /** True if this list can be mutated. */
  1052. transient protected boolean m_mutable = true;
  1053. /** True if this list is cached.
  1054. * @serial */
  1055. transient protected boolean m_cacheNodes = true;
  1056. /** The root of the iteration, if available. */
  1057. protected int m_root = DTM.NULL;
  1058. /**
  1059. * Get whether or not this is a cached node set.
  1060. *
  1061. *
  1062. * @return True if this list is cached.
  1063. */
  1064. public boolean getShouldCacheNodes()
  1065. {
  1066. return m_cacheNodes;
  1067. }
  1068. /**
  1069. * If setShouldCacheNodes(true) is called, then nodes will
  1070. * be cached. They are not cached by default. This switch must
  1071. * be set before the first call to nextNode is made, to ensure
  1072. * that all nodes are cached.
  1073. *
  1074. * @param b true if this node set should be cached.
  1075. * @throws RuntimeException thrown if an attempt is made to
  1076. * request caching after we've already begun stepping through the
  1077. * nodes in this set.
  1078. */
  1079. public void setShouldCacheNodes(boolean b)
  1080. {
  1081. if (!isFresh())
  1082. throw new RuntimeException(
  1083. XSLMessages.createXPATHMessage(XPATHErrorResources.ER_CANNOT_CALL_SETSHOULDCACHENODE, null)); //"Can not call setShouldCacheNodes after nextNode has been called!");
  1084. m_cacheNodes = b;
  1085. m_mutable = true;
  1086. }
  1087. /**
  1088. * Tells if this iterator can have nodes added to it or set via
  1089. * the <code>setItem(int node, int index)</code> method.
  1090. *
  1091. * @return True if the nodelist can be mutated.
  1092. */
  1093. public boolean isMutable()
  1094. {
  1095. return m_mutable;
  1096. }
  1097. transient private int m_last = 0;
  1098. public int getLast()
  1099. {
  1100. return m_last;
  1101. }
  1102. public void setLast(int last)
  1103. {
  1104. m_last = last;
  1105. }
  1106. /**
  1107. * Returns true if all the nodes in the iteration well be returned in document
  1108. * order.
  1109. *
  1110. * @return true as a default.
  1111. */
  1112. public boolean isDocOrdered()
  1113. {
  1114. return true;
  1115. }
  1116. /**
  1117. * Returns the axis being iterated, if it is known.
  1118. *
  1119. * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
  1120. * types.
  1121. */
  1122. public int getAxis()
  1123. {
  1124. return -1;
  1125. }
  1126. }