1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: SAX2DTM2.java,v 1.10 2004/02/24 04:22:12 zongaro Exp $
  18. */
  19. package com.sun.org.apache.xml.internal.dtm.ref.sax2dtm;
  20. import com.sun.org.apache.xml.internal.dtm.*;
  21. import com.sun.org.apache.xml.internal.dtm.ref.*;
  22. import com.sun.org.apache.xml.internal.utils.FastStringBuffer;
  23. import com.sun.org.apache.xml.internal.utils.XMLString;
  24. import com.sun.org.apache.xml.internal.utils.XMLStringDefault;
  25. import com.sun.org.apache.xml.internal.utils.XMLStringFactory;
  26. import com.sun.org.apache.xml.internal.res.XMLMessages;
  27. import com.sun.org.apache.xml.internal.res.XMLErrorResources;
  28. import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
  29. import javax.xml.transform.Source;
  30. import java.util.Vector;
  31. import com.sun.org.apache.xml.internal.utils.IntStack;
  32. import org.xml.sax.*;
  33. /**
  34. * SAX2DTM2 is an optimized version of SAX2DTM which is used in non-incremental situation.
  35. * It is used as the super class of the XSLTC SAXImpl. Many of the interfaces in SAX2DTM
  36. * and DTMDefaultBase are overridden in SAX2DTM2 in order to allow fast, efficient
  37. * access to the DTM model. Some nested iterators in DTMDefaultBaseIterators
  38. * are also overridden in SAX2DTM2 for performance reasons.
  39. * <p>
  40. * Performance is the biggest consideration in the design of SAX2DTM2. To make the code most
  41. * efficient, the incremental support is dropped in SAX2DTM2, which means that you should not
  42. * use it in incremental situation. To reduce the overhead of pulling data from the DTM model,
  43. * a few core interfaces in SAX2DTM2 have direct access to the internal arrays of the
  44. * SuballocatedIntVectors.
  45. * <p>
  46. * The design of SAX2DTM2 may limit its extensibilty. If you have a reason to extend the
  47. * SAX2DTM model, please extend from SAX2DTM instead of this class.
  48. * <p>
  49. * TODO: This class is currently only used by XSLTC. We need to investigate the possibility
  50. * of also using it in Xalan-J Interpretive. Xalan's performance is likely to get an instant
  51. * boost if we use SAX2DTM2 instead of SAX2DTM in non-incremental case.
  52. * <p>
  53. * %MK% The code in this class is critical to the XSLTC_DTM performance. Be very careful
  54. * when making changes here!
  55. */
  56. public class SAX2DTM2 extends SAX2DTM
  57. {
  58. /****************************************************************
  59. * Optimized version of the nested iterators
  60. ****************************************************************/
  61. /**
  62. * Iterator that returns all immediate children of a given node
  63. */
  64. public final class ChildrenIterator extends InternalAxisIteratorBase
  65. {
  66. /**
  67. * Setting start to END should 'close' the iterator,
  68. * i.e. subsequent call to next() should return END.
  69. * <p>
  70. * If the iterator is not restartable, this has no effect.
  71. * %REVIEW% Should it return/throw something in that case,
  72. * or set current node to END, to indicate request-not-honored?
  73. *
  74. * @param node Sets the root of the iteration.
  75. *
  76. * @return A DTMAxisIterator set to the start of the iteration.
  77. */
  78. public DTMAxisIterator setStartNode(int node)
  79. {
  80. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  81. if (node == DTMDefaultBase.ROOTNODE)
  82. node = getDocument();
  83. if (_isRestartable)
  84. {
  85. _startNode = node;
  86. _currentNode = (node == DTM.NULL) ? DTM.NULL
  87. : _firstch2(makeNodeIdentity(node));
  88. return resetPosition();
  89. }
  90. return this;
  91. }
  92. /**
  93. * Get the next node in the iteration.
  94. *
  95. * @return The next node handle in the iteration, or END if no more
  96. * are available.
  97. */
  98. public int next()
  99. {
  100. if (_currentNode != NULL) {
  101. int node = _currentNode;
  102. _currentNode = _nextsib2(node);
  103. return returnNode(makeNodeHandle(node));
  104. }
  105. return END;
  106. }
  107. } // end of ChildrenIterator
  108. /**
  109. * Iterator that returns the parent of a given node. Note that
  110. * this delivers only a single node; if you want all the ancestors,
  111. * see AncestorIterator.
  112. */
  113. public final class ParentIterator extends InternalAxisIteratorBase
  114. {
  115. /** The extended type ID that was requested. */
  116. private int _nodeType = DTM.NULL;
  117. /**
  118. * Set start to END should 'close' the iterator,
  119. * i.e. subsequent call to next() should return END.
  120. *
  121. * @param node Sets the root of the iteration.
  122. *
  123. * @return A DTMAxisIterator set to the start of the iteration.
  124. */
  125. public DTMAxisIterator setStartNode(int node)
  126. {
  127. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  128. if (node == DTMDefaultBase.ROOTNODE)
  129. node = getDocument();
  130. if (_isRestartable)
  131. {
  132. _startNode = node;
  133. if (node != DTM.NULL)
  134. _currentNode = _parent2(makeNodeIdentity(node));
  135. else
  136. _currentNode = DTM.NULL;
  137. return resetPosition();
  138. }
  139. return this;
  140. }
  141. /**
  142. * Set the node type of the parent that we're looking for.
  143. * Note that this does _not_ mean "find the nearest ancestor of
  144. * this type", but "yield the parent if it is of this type".
  145. *
  146. *
  147. * @param type extended type ID.
  148. *
  149. * @return ParentIterator configured with the type filter set.
  150. */
  151. public DTMAxisIterator setNodeType(final int type)
  152. {
  153. _nodeType = type;
  154. return this;
  155. }
  156. /**
  157. * Get the next node in the iteration. In this case, we return
  158. * only the immediate parent, _if_ it matches the requested nodeType.
  159. *
  160. * @return The next node handle in the iteration, or END.
  161. */
  162. public int next()
  163. {
  164. int result = _currentNode;
  165. if (result == END)
  166. return DTM.NULL;
  167. // %OPT% The most common case is handled first.
  168. if (_nodeType == NULL) {
  169. _currentNode = END;
  170. return returnNode(makeNodeHandle(result));
  171. }
  172. else if (_nodeType >= DTM.NTYPES) {
  173. if (_nodeType == _exptype2(result)) {
  174. _currentNode = END;
  175. return returnNode(makeNodeHandle(result));
  176. }
  177. }
  178. else {
  179. if (_nodeType == _type2(result)) {
  180. _currentNode = END;
  181. return returnNode(makeNodeHandle(result));
  182. }
  183. }
  184. return DTM.NULL;
  185. }
  186. } // end of ParentIterator
  187. /**
  188. * Iterator that returns children of a given type for a given node.
  189. * The functionality chould be achieved by putting a filter on top
  190. * of a basic child iterator, but a specialised iterator is used
  191. * for efficiency (both speed and size of translet).
  192. */
  193. public final class TypedChildrenIterator extends InternalAxisIteratorBase
  194. {
  195. /** The extended type ID that was requested. */
  196. private final int _nodeType;
  197. /**
  198. * Constructor TypedChildrenIterator
  199. *
  200. *
  201. * @param nodeType The extended type ID being requested.
  202. */
  203. public TypedChildrenIterator(int nodeType)
  204. {
  205. _nodeType = nodeType;
  206. }
  207. /**
  208. * Set start to END should 'close' the iterator,
  209. * i.e. subsequent call to next() should return END.
  210. *
  211. * @param node Sets the root of the iteration.
  212. *
  213. * @return A DTMAxisIterator set to the start of the iteration.
  214. */
  215. public DTMAxisIterator setStartNode(int node)
  216. {
  217. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  218. if (node == DTMDefaultBase.ROOTNODE)
  219. node = getDocument();
  220. if (_isRestartable)
  221. {
  222. _startNode = node;
  223. _currentNode = (node == DTM.NULL)
  224. ? DTM.NULL
  225. : _firstch2(makeNodeIdentity(_startNode));
  226. return resetPosition();
  227. }
  228. return this;
  229. }
  230. /**
  231. * Get the next node in the iteration.
  232. *
  233. * @return The next node handle in the iteration, or END.
  234. */
  235. public int next()
  236. {
  237. int node = _currentNode;
  238. if (node == DTM.NULL)
  239. return DTM.NULL;
  240. final int nodeType = _nodeType;
  241. if (nodeType != DTM.ELEMENT_NODE) {
  242. while (node != DTM.NULL && _exptype2(node) != nodeType) {
  243. node = _nextsib2(node);
  244. }
  245. }
  246. // %OPT% If the nodeType is element (matching child::*), we only
  247. // need to compare the expType with DTM.NTYPES. A child node of
  248. // an element can be either an element, text, comment or
  249. // processing instruction node. Only element node has an extended
  250. // type greater than or equal to DTM.NTYPES.
  251. else {
  252. int eType;
  253. while (node != DTM.NULL) {
  254. eType = _exptype2(node);
  255. if (eType >= DTM.NTYPES)
  256. break;
  257. else
  258. node = _nextsib2(node);
  259. }
  260. }
  261. if (node == DTM.NULL) {
  262. _currentNode = DTM.NULL;
  263. return DTM.NULL;
  264. } else {
  265. _currentNode = _nextsib2(node);
  266. return returnNode(makeNodeHandle(node));
  267. }
  268. }
  269. /**
  270. * Return the node at the given position.
  271. */
  272. public int getNodeByPosition(int position)
  273. {
  274. if (position <= 0)
  275. return DTM.NULL;
  276. int node = _currentNode;
  277. int pos = 0;
  278. final int nodeType = _nodeType;
  279. if (nodeType != DTM.ELEMENT_NODE) {
  280. while (node != DTM.NULL) {
  281. if (_exptype2(node) == nodeType) {
  282. pos++;
  283. if (pos == position)
  284. return makeNodeHandle(node);
  285. }
  286. node = _nextsib2(node);
  287. }
  288. return NULL;
  289. }
  290. else {
  291. while (node != DTM.NULL) {
  292. if (_exptype2(node) >= DTM.NTYPES) {
  293. pos++;
  294. if (pos == position)
  295. return makeNodeHandle(node);
  296. }
  297. node = _nextsib2(node);
  298. }
  299. return NULL;
  300. }
  301. }
  302. } // end of TypedChildrenIterator
  303. /**
  304. * Iterator that returns the namespace nodes as defined by the XPath data model
  305. * for a given node, filtered by extended type ID.
  306. */
  307. public class TypedRootIterator extends RootIterator
  308. {
  309. /** The extended type ID that was requested. */
  310. private final int _nodeType;
  311. /**
  312. * Constructor TypedRootIterator
  313. *
  314. * @param nodeType The extended type ID being requested.
  315. */
  316. public TypedRootIterator(int nodeType)
  317. {
  318. super();
  319. _nodeType = nodeType;
  320. }
  321. /**
  322. * Get the next node in the iteration.
  323. *
  324. * @return The next node handle in the iteration, or END.
  325. */
  326. public int next()
  327. {
  328. if(_startNode == _currentNode)
  329. return NULL;
  330. final int node = _startNode;
  331. int expType = _exptype2(makeNodeIdentity(node));
  332. _currentNode = node;
  333. if (_nodeType >= DTM.NTYPES) {
  334. if (_nodeType == expType) {
  335. return returnNode(node);
  336. }
  337. }
  338. else {
  339. if (expType < DTM.NTYPES) {
  340. if (expType == _nodeType) {
  341. return returnNode(node);
  342. }
  343. }
  344. else {
  345. if (m_extendedTypes[expType].getNodeType() == _nodeType) {
  346. return returnNode(node);
  347. }
  348. }
  349. }
  350. return NULL;
  351. }
  352. } // end of TypedRootIterator
  353. /**
  354. * Iterator that returns all siblings of a given node.
  355. */
  356. public class FollowingSiblingIterator extends InternalAxisIteratorBase
  357. {
  358. /**
  359. * Set start to END should 'close' the iterator,
  360. * i.e. subsequent call to next() should return END.
  361. *
  362. * @param node Sets the root of the iteration.
  363. *
  364. * @return A DTMAxisIterator set to the start of the iteration.
  365. */
  366. public DTMAxisIterator setStartNode(int node)
  367. {
  368. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  369. if (node == DTMDefaultBase.ROOTNODE)
  370. node = getDocument();
  371. if (_isRestartable)
  372. {
  373. _startNode = node;
  374. _currentNode = makeNodeIdentity(node);
  375. return resetPosition();
  376. }
  377. return this;
  378. }
  379. /**
  380. * Get the next node in the iteration.
  381. *
  382. * @return The next node handle in the iteration, or END.
  383. */
  384. public int next()
  385. {
  386. _currentNode = (_currentNode == DTM.NULL) ? DTM.NULL
  387. : _nextsib2(_currentNode);
  388. return returnNode(makeNodeHandle(_currentNode));
  389. }
  390. } // end of FollowingSiblingIterator
  391. /**
  392. * Iterator that returns all following siblings of a given node.
  393. */
  394. public final class TypedFollowingSiblingIterator
  395. extends FollowingSiblingIterator
  396. {
  397. /** The extended type ID that was requested. */
  398. private final int _nodeType;
  399. /**
  400. * Constructor TypedFollowingSiblingIterator
  401. *
  402. *
  403. * @param type The extended type ID being requested.
  404. */
  405. public TypedFollowingSiblingIterator(int type)
  406. {
  407. _nodeType = type;
  408. }
  409. /**
  410. * Get the next node in the iteration.
  411. *
  412. * @return The next node handle in the iteration, or END.
  413. */
  414. public int next()
  415. {
  416. if (_currentNode == DTM.NULL) {
  417. return DTM.NULL;
  418. }
  419. int node = _currentNode;
  420. final int nodeType = _nodeType;
  421. if (nodeType != DTM.ELEMENT_NODE) {
  422. while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) != nodeType) {}
  423. }
  424. else {
  425. while ((node = _nextsib2(node)) != DTM.NULL && _exptype2(node) < DTM.NTYPES) {}
  426. }
  427. _currentNode = node;
  428. return (node == DTM.NULL)
  429. ? DTM.NULL
  430. : returnNode(makeNodeHandle(node));
  431. }
  432. } // end of TypedFollowingSiblingIterator
  433. /**
  434. * Iterator that returns attribute nodes (of what nodes?)
  435. */
  436. public final class AttributeIterator extends InternalAxisIteratorBase
  437. {
  438. // assumes caller will pass element nodes
  439. /**
  440. * Set start to END should 'close' the iterator,
  441. * i.e. subsequent call to next() should return END.
  442. *
  443. * @param node Sets the root of the iteration.
  444. *
  445. * @return A DTMAxisIterator set to the start of the iteration.
  446. */
  447. public DTMAxisIterator setStartNode(int node)
  448. {
  449. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  450. if (node == DTMDefaultBase.ROOTNODE)
  451. node = getDocument();
  452. if (_isRestartable)
  453. {
  454. _startNode = node;
  455. _currentNode = getFirstAttributeIdentity(makeNodeIdentity(node));
  456. return resetPosition();
  457. }
  458. return this;
  459. }
  460. /**
  461. * Get the next node in the iteration.
  462. *
  463. * @return The next node handle in the iteration, or END.
  464. */
  465. public int next()
  466. {
  467. final int node = _currentNode;
  468. if (node != NULL) {
  469. _currentNode = getNextAttributeIdentity(node);
  470. return returnNode(makeNodeHandle(node));
  471. }
  472. return NULL;
  473. }
  474. } // end of AttributeIterator
  475. /**
  476. * Iterator that returns attribute nodes of a given type
  477. */
  478. public final class TypedAttributeIterator extends InternalAxisIteratorBase
  479. {
  480. /** The extended type ID that was requested. */
  481. private final int _nodeType;
  482. /**
  483. * Constructor TypedAttributeIterator
  484. *
  485. *
  486. * @param nodeType The extended type ID that is requested.
  487. */
  488. public TypedAttributeIterator(int nodeType)
  489. {
  490. _nodeType = nodeType;
  491. }
  492. // assumes caller will pass element nodes
  493. /**
  494. * Set start to END should 'close' the iterator,
  495. * i.e. subsequent call to next() should return END.
  496. *
  497. * @param node Sets the root of the iteration.
  498. *
  499. * @return A DTMAxisIterator set to the start of the iteration.
  500. */
  501. public DTMAxisIterator setStartNode(int node)
  502. {
  503. if (_isRestartable)
  504. {
  505. _startNode = node;
  506. _currentNode = getTypedAttribute(node, _nodeType);
  507. return resetPosition();
  508. }
  509. return this;
  510. }
  511. /**
  512. * Get the next node in the iteration.
  513. *
  514. * @return The next node handle in the iteration, or END.
  515. */
  516. public int next()
  517. {
  518. final int node = _currentNode;
  519. // singleton iterator, since there can only be one attribute of
  520. // a given type.
  521. _currentNode = NULL;
  522. return returnNode(node);
  523. }
  524. } // end of TypedAttributeIterator
  525. /**
  526. * Iterator that returns preceding siblings of a given node
  527. */
  528. public class PrecedingSiblingIterator extends InternalAxisIteratorBase
  529. {
  530. /**
  531. * The node identity of _startNode for this iterator
  532. */
  533. protected int _startNodeID;
  534. /**
  535. * True if this iterator has a reversed axis.
  536. *
  537. * @return true.
  538. */
  539. public boolean isReverse()
  540. {
  541. return true;
  542. }
  543. /**
  544. * Set start to END should 'close' the iterator,
  545. * i.e. subsequent call to next() should return END.
  546. *
  547. * @param node Sets the root of the iteration.
  548. *
  549. * @return A DTMAxisIterator set to the start of the iteration.
  550. */
  551. public DTMAxisIterator setStartNode(int node)
  552. {
  553. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  554. if (node == DTMDefaultBase.ROOTNODE)
  555. node = getDocument();
  556. if (_isRestartable)
  557. {
  558. _startNode = node;
  559. node = _startNodeID = makeNodeIdentity(node);
  560. if(node == NULL)
  561. {
  562. _currentNode = node;
  563. return resetPosition();
  564. }
  565. int type = _type2(node);
  566. if(ExpandedNameTable.ATTRIBUTE == type
  567. || ExpandedNameTable.NAMESPACE == type )
  568. {
  569. _currentNode = node;
  570. }
  571. else
  572. {
  573. // Be careful to handle the Document node properly
  574. _currentNode = _parent2(node);
  575. if(NULL!=_currentNode)
  576. _currentNode = _firstch2(_currentNode);
  577. else
  578. _currentNode = node;
  579. }
  580. return resetPosition();
  581. }
  582. return this;
  583. }
  584. /**
  585. * Get the next node in the iteration.
  586. *
  587. * @return The next node handle in the iteration, or END.
  588. */
  589. public int next()
  590. {
  591. if (_currentNode == _startNodeID || _currentNode == DTM.NULL)
  592. {
  593. return NULL;
  594. }
  595. else
  596. {
  597. final int node = _currentNode;
  598. _currentNode = _nextsib2(node);
  599. return returnNode(makeNodeHandle(node));
  600. }
  601. }
  602. } // end of PrecedingSiblingIterator
  603. /**
  604. * Iterator that returns preceding siblings of a given type for
  605. * a given node
  606. */
  607. public final class TypedPrecedingSiblingIterator
  608. extends PrecedingSiblingIterator
  609. {
  610. /** The extended type ID that was requested. */
  611. private final int _nodeType;
  612. /**
  613. * Constructor TypedPrecedingSiblingIterator
  614. *
  615. *
  616. * @param type The extended type ID being requested.
  617. */
  618. public TypedPrecedingSiblingIterator(int type)
  619. {
  620. _nodeType = type;
  621. }
  622. /**
  623. * Get the next node in the iteration.
  624. *
  625. * @return The next node handle in the iteration, or END.
  626. */
  627. public int next()
  628. {
  629. int node = _currentNode;
  630. final int nodeType = _nodeType;
  631. final int startNodeID = _startNodeID;
  632. if (nodeType != DTM.ELEMENT_NODE) {
  633. while (node != NULL && node != startNodeID && _exptype2(node) != nodeType) {
  634. node = _nextsib2(node);
  635. }
  636. }
  637. else {
  638. while (node != NULL && node != startNodeID && _exptype2(node) < DTM.NTYPES) {
  639. node = _nextsib2(node);
  640. }
  641. }
  642. if (node == DTM.NULL || node == startNodeID) {
  643. _currentNode = NULL;
  644. return NULL;
  645. }
  646. else {
  647. _currentNode = _nextsib2(node);
  648. return returnNode(makeNodeHandle(node));
  649. }
  650. }
  651. /**
  652. * Return the index of the last node in this iterator.
  653. */
  654. public int getLast()
  655. {
  656. if (_last != -1)
  657. return _last;
  658. setMark();
  659. int node = _currentNode;
  660. final int nodeType = _nodeType;
  661. final int startNodeID = _startNodeID;
  662. int last = 0;
  663. if (nodeType != DTM.ELEMENT_NODE) {
  664. while (node != NULL && node != startNodeID) {
  665. if (_exptype2(node) == nodeType) {
  666. last++;
  667. }
  668. node = _nextsib2(node);
  669. }
  670. }
  671. else {
  672. while (node != NULL && node != startNodeID) {
  673. if (_exptype2(node) >= DTM.NTYPES) {
  674. last++;
  675. }
  676. node = _nextsib2(node);
  677. }
  678. }
  679. gotoMark();
  680. return (_last = last);
  681. }
  682. } // end of TypedPrecedingSiblingIterator
  683. /**
  684. * Iterator that returns preceding nodes of a given node.
  685. * This includes the node set {root+1, start-1}, but excludes
  686. * all ancestors, attributes, and namespace nodes.
  687. */
  688. public class PrecedingIterator extends InternalAxisIteratorBase
  689. {
  690. /** The max ancestors, but it can grow... */
  691. private final int _maxAncestors = 8;
  692. /**
  693. * The stack of start node + ancestors up to the root of the tree,
  694. * which we must avoid.
  695. */
  696. protected int[] _stack = new int[_maxAncestors];
  697. /** (not sure yet... -sb) */
  698. protected int _sp, _oldsp;
  699. protected int _markedsp, _markedNode, _markedDescendant;
  700. /* _currentNode precedes candidates. This is the identity, not the handle! */
  701. /**
  702. * True if this iterator has a reversed axis.
  703. *
  704. * @return true since this iterator is a reversed axis.
  705. */
  706. public boolean isReverse()
  707. {
  708. return true;
  709. }
  710. /**
  711. * Returns a deep copy of this iterator. The cloned iterator is not reset.
  712. *
  713. * @return a deep copy of this iterator.
  714. */
  715. public DTMAxisIterator cloneIterator()
  716. {
  717. _isRestartable = false;
  718. try
  719. {
  720. final PrecedingIterator clone = (PrecedingIterator) super.clone();
  721. final int[] stackCopy = new int[_stack.length];
  722. System.arraycopy(_stack, 0, stackCopy, 0, _stack.length);
  723. clone._stack = stackCopy;
  724. // return clone.reset();
  725. return clone;
  726. }
  727. catch (CloneNotSupportedException e)
  728. {
  729. throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
  730. }
  731. }
  732. /**
  733. * Set start to END should 'close' the iterator,
  734. * i.e. subsequent call to next() should return END.
  735. *
  736. * @param node Sets the root of the iteration.
  737. *
  738. * @return A DTMAxisIterator set to the start of the iteration.
  739. */
  740. public DTMAxisIterator setStartNode(int node)
  741. {
  742. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  743. if (node == DTMDefaultBase.ROOTNODE)
  744. node = getDocument();
  745. if (_isRestartable)
  746. {
  747. node = makeNodeIdentity(node);
  748. // iterator is not a clone
  749. int parent, index;
  750. if (_type2(node) == DTM.ATTRIBUTE_NODE)
  751. node = _parent2(node);
  752. _startNode = node;
  753. _stack[index = 0] = node;
  754. parent=node;
  755. while ((parent = _parent2(parent)) != NULL)
  756. {
  757. if (++index == _stack.length)
  758. {
  759. final int[] stack = new int[index*2];
  760. System.arraycopy(_stack, 0, stack, 0, index);
  761. _stack = stack;
  762. }
  763. _stack[index] = parent;
  764. }
  765. if(index>0)
  766. --index; // Pop actual root node (if not start) back off the stack
  767. _currentNode=_stack[index]; // Last parent before root node
  768. _oldsp = _sp = index;
  769. return resetPosition();
  770. }
  771. return this;
  772. }
  773. /**
  774. * Get the next node in the iteration.
  775. *
  776. * @return The next node handle in the iteration, or END.
  777. */
  778. public int next()
  779. {
  780. // Bugzilla 8324: We were forgetting to skip Attrs and NS nodes.
  781. // Also recoded the loop controls for clarity and to flatten out
  782. // the tail-recursion.
  783. for(++_currentNode; _sp>=0; ++_currentNode)
  784. {
  785. if(_currentNode < _stack[_sp])
  786. {
  787. int type = _type2(_currentNode);
  788. if(type != ATTRIBUTE_NODE && type != NAMESPACE_NODE)
  789. return returnNode(makeNodeHandle(_currentNode));
  790. }
  791. else
  792. --_sp;
  793. }
  794. return NULL;
  795. }
  796. // redefine DTMAxisIteratorBase's reset
  797. /**
  798. * Resets the iterator to the last start node.
  799. *
  800. * @return A DTMAxisIterator, which may or may not be the same as this
  801. * iterator.
  802. */
  803. public DTMAxisIterator reset()
  804. {
  805. _sp = _oldsp;
  806. return resetPosition();
  807. }
  808. public void setMark() {
  809. _markedsp = _sp;
  810. _markedNode = _currentNode;
  811. _markedDescendant = _stack[0];
  812. }
  813. public void gotoMark() {
  814. _sp = _markedsp;
  815. _currentNode = _markedNode;
  816. }
  817. } // end of PrecedingIterator
  818. /**
  819. * Iterator that returns preceding nodes of agiven type for a
  820. * given node. This includes the node set {root+1, start-1}, but
  821. * excludes all ancestors.
  822. */
  823. public final class TypedPrecedingIterator extends PrecedingIterator
  824. {
  825. /** The extended type ID that was requested. */
  826. private final int _nodeType;
  827. /**
  828. * Constructor TypedPrecedingIterator
  829. *
  830. *
  831. * @param type The extended type ID being requested.
  832. */
  833. public TypedPrecedingIterator(int type)
  834. {
  835. _nodeType = type;
  836. }
  837. /**
  838. * Get the next node in the iteration.
  839. *
  840. * @return The next node handle in the iteration, or END.
  841. */
  842. public int next()
  843. {
  844. int node = _currentNode;
  845. final int nodeType = _nodeType;
  846. if (nodeType >= DTM.NTYPES) {
  847. while (true) {
  848. node++;
  849. if (_sp < 0) {
  850. node = NULL;
  851. break;
  852. }
  853. else if (node >= _stack[_sp]) {
  854. if (--_sp < 0) {
  855. node = NULL;
  856. break;
  857. }
  858. }
  859. else if (_exptype2(node) == nodeType) {
  860. break;
  861. }
  862. }
  863. }
  864. else {
  865. int expType;
  866. while (true) {
  867. node++;
  868. if (_sp < 0) {
  869. node = NULL;
  870. break;
  871. }
  872. else if (node >= _stack[_sp]) {
  873. if (--_sp < 0) {
  874. node = NULL;
  875. break;
  876. }
  877. }
  878. else {
  879. expType = _exptype2(node);
  880. if (expType < DTM.NTYPES) {
  881. if (expType == nodeType) {
  882. break;
  883. }
  884. }
  885. else {
  886. if (m_extendedTypes[expType].getNodeType() == nodeType) {
  887. break;
  888. }
  889. }
  890. }
  891. }
  892. }
  893. _currentNode = node;
  894. return (node == NULL) ? NULL : returnNode(makeNodeHandle(node));
  895. }
  896. } // end of TypedPrecedingIterator
  897. /**
  898. * Iterator that returns following nodes of for a given node.
  899. */
  900. public class FollowingIterator extends InternalAxisIteratorBase
  901. {
  902. //DTMAxisTraverser m_traverser; // easier for now
  903. public FollowingIterator()
  904. {
  905. //m_traverser = getAxisTraverser(Axis.FOLLOWING);
  906. }
  907. /**
  908. * Set start to END should 'close' the iterator,
  909. * i.e. subsequent call to next() should return END.
  910. *
  911. * @param node Sets the root of the iteration.
  912. *
  913. * @return A DTMAxisIterator set to the start of the iteration.
  914. */
  915. public DTMAxisIterator setStartNode(int node)
  916. {
  917. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  918. if (node == DTMDefaultBase.ROOTNODE)
  919. node = getDocument();
  920. if (_isRestartable)
  921. {
  922. _startNode = node;
  923. //_currentNode = m_traverser.first(node);
  924. node = makeNodeIdentity(node);
  925. int first;
  926. int type = _type2(node);
  927. if ((DTM.ATTRIBUTE_NODE == type) || (DTM.NAMESPACE_NODE == type))
  928. {
  929. node = _parent2(node);
  930. first = _firstch2(node);
  931. if (NULL != first) {
  932. _currentNode = makeNodeHandle(first);
  933. return resetPosition();
  934. }
  935. }
  936. do
  937. {
  938. first = _nextsib2(node);
  939. if (NULL == first)
  940. node = _parent2(node);
  941. }
  942. while (NULL == first && NULL != node);
  943. _currentNode = makeNodeHandle(first);
  944. // _currentNode precedes possible following(node) nodes
  945. return resetPosition();
  946. }
  947. return this;
  948. }
  949. /**
  950. * Get the next node in the iteration.
  951. *
  952. * @return The next node handle in the iteration, or END.
  953. */
  954. public int next()
  955. {
  956. int node = _currentNode;
  957. //_currentNode = m_traverser.next(_startNode, _currentNode);
  958. int current = makeNodeIdentity(node);
  959. while (true)
  960. {
  961. current++;
  962. int type = _type2(current);
  963. if (NULL == type) {
  964. _currentNode = NULL;
  965. return returnNode(node);
  966. }
  967. if (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type)
  968. continue;
  969. _currentNode = makeNodeHandle(current);
  970. return returnNode(node);
  971. }
  972. }
  973. } // end of FollowingIterator
  974. /**
  975. * Iterator that returns following nodes of a given type for a given node.
  976. */
  977. public final class TypedFollowingIterator extends FollowingIterator
  978. {
  979. /** The extended type ID that was requested. */
  980. private final int _nodeType;
  981. /**
  982. * Constructor TypedFollowingIterator
  983. *
  984. *
  985. * @param type The extended type ID being requested.
  986. */
  987. public TypedFollowingIterator(int type)
  988. {
  989. _nodeType = type;
  990. }
  991. /**
  992. * Get the next node in the iteration.
  993. *
  994. * @return The next node handle in the iteration, or END.
  995. */
  996. public int next()
  997. {
  998. int current;
  999. int node;
  1000. int type;
  1001. final int nodeType = _nodeType;
  1002. int currentNodeID = makeNodeIdentity(_currentNode);
  1003. if (nodeType >= DTM.NTYPES) {
  1004. do {
  1005. node = currentNodeID;
  1006. current = node;
  1007. do {
  1008. current++;
  1009. type = _type2(current);
  1010. }
  1011. while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
  1012. currentNodeID = (type != NULL) ? current : NULL;
  1013. }
  1014. while (node != DTM.NULL && _exptype2(node) != nodeType);
  1015. }
  1016. else {
  1017. do {
  1018. node = currentNodeID;
  1019. current = node;
  1020. do {
  1021. current++;
  1022. type = _type2(current);
  1023. }
  1024. while (type != NULL && (ATTRIBUTE_NODE == type || NAMESPACE_NODE == type));
  1025. currentNodeID = (type != NULL) ? current : NULL;
  1026. }
  1027. while (node != DTM.NULL
  1028. && (_exptype2(node) != nodeType && _type2(node) != nodeType));
  1029. }
  1030. _currentNode = makeNodeHandle(currentNodeID);
  1031. return (node == DTM.NULL ? DTM.NULL :returnNode(makeNodeHandle(node)));
  1032. }
  1033. } // end of TypedFollowingIterator
  1034. /**
  1035. * Iterator that returns the ancestors of a given node in document
  1036. * order. (NOTE! This was changed from the XSLTC code!)
  1037. */
  1038. public class AncestorIterator extends InternalAxisIteratorBase
  1039. {
  1040. // The initial size of the ancestor array
  1041. private static final int m_blocksize = 32;
  1042. // The array for ancestor nodes. This array will grow dynamically.
  1043. int[] m_ancestors = new int[m_blocksize];
  1044. // Number of ancestor nodes in the array
  1045. int m_size = 0;
  1046. int m_ancestorsPos;
  1047. int m_markedPos;
  1048. /** The real start node for this axes, since _startNode will be adjusted. */
  1049. int m_realStartNode;
  1050. /**
  1051. * Get start to END should 'close' the iterator,
  1052. * i.e. subsequent call to next() should return END.
  1053. *
  1054. * @return The root node of the iteration.
  1055. */
  1056. public int getStartNode()
  1057. {
  1058. return m_realStartNode;
  1059. }
  1060. /**
  1061. * True if this iterator has a reversed axis.
  1062. *
  1063. * @return true since this iterator is a reversed axis.
  1064. */
  1065. public final boolean isReverse()
  1066. {
  1067. return true;
  1068. }
  1069. /**
  1070. * Returns a deep copy of this iterator. The cloned iterator is not reset.
  1071. *
  1072. * @return a deep copy of this iterator.
  1073. */
  1074. public DTMAxisIterator cloneIterator()
  1075. {
  1076. _isRestartable = false; // must set to false for any clone
  1077. try
  1078. {
  1079. final AncestorIterator clone = (AncestorIterator) super.clone();
  1080. clone._startNode = _startNode;
  1081. // return clone.reset();
  1082. return clone;
  1083. }
  1084. catch (CloneNotSupportedException e)
  1085. {
  1086. throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ITERATOR_CLONE_NOT_SUPPORTED, null)); //"Iterator clone not supported.");
  1087. }
  1088. }
  1089. /**
  1090. * Set start to END should 'close' the iterator,
  1091. * i.e. subsequent call to next() should return END.
  1092. *
  1093. * @param node Sets the root of the iteration.
  1094. *
  1095. * @return A DTMAxisIterator set to the start of the iteration.
  1096. */
  1097. public DTMAxisIterator setStartNode(int node)
  1098. {
  1099. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  1100. if (node == DTMDefaultBase.ROOTNODE)
  1101. node = getDocument();
  1102. m_realStartNode = node;
  1103. if (_isRestartable)
  1104. {
  1105. int nodeID = makeNodeIdentity(node);
  1106. m_size = 0;
  1107. if (nodeID == DTM.NULL) {
  1108. _currentNode = DTM.NULL;
  1109. m_ancestorsPos = 0;
  1110. return this;
  1111. }
  1112. // Start from the current node's parent if
  1113. // _includeSelf is false.
  1114. if (!_includeSelf) {
  1115. nodeID = _parent2(nodeID);
  1116. node = makeNodeHandle(nodeID);
  1117. }
  1118. _startNode = node;
  1119. while (nodeID != END) {
  1120. //m_ancestors.addElement(node);
  1121. if (m_size >= m_ancestors.length)
  1122. {
  1123. int[] newAncestors = new int[m_size * 2];
  1124. System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
  1125. m_ancestors = newAncestors;
  1126. }
  1127. m_ancestors[m_size++] = node;
  1128. nodeID = _parent2(nodeID);
  1129. node = makeNodeHandle(nodeID);
  1130. }
  1131. m_ancestorsPos = m_size - 1;
  1132. _currentNode = (m_ancestorsPos>=0)
  1133. ? m_ancestors[m_ancestorsPos]
  1134. : DTM.NULL;
  1135. return resetPosition();
  1136. }
  1137. return this;
  1138. }
  1139. /**
  1140. * Resets the iterator to the last start node.
  1141. *
  1142. * @return A DTMAxisIterator, which may or may not be the same as this
  1143. * iterator.
  1144. */
  1145. public DTMAxisIterator reset()
  1146. {
  1147. m_ancestorsPos = m_size - 1;
  1148. _currentNode = (m_ancestorsPos >= 0) ? m_ancestors[m_ancestorsPos]
  1149. : DTM.NULL;
  1150. return resetPosition();
  1151. }
  1152. /**
  1153. * Get the next node in the iteration.
  1154. *
  1155. * @return The next node handle in the iteration, or END.
  1156. */
  1157. public int next()
  1158. {
  1159. int next = _currentNode;
  1160. int pos = --m_ancestorsPos;
  1161. _currentNode = (pos >= 0) ? m_ancestors[m_ancestorsPos]
  1162. : DTM.NULL;
  1163. return returnNode(next);
  1164. }
  1165. public void setMark() {
  1166. m_markedPos = m_ancestorsPos;
  1167. }
  1168. public void gotoMark() {
  1169. m_ancestorsPos = m_markedPos;
  1170. _currentNode = m_ancestorsPos>=0 ? m_ancestors[m_ancestorsPos]
  1171. : DTM.NULL;
  1172. }
  1173. } // end of AncestorIterator
  1174. /**
  1175. * Typed iterator that returns the ancestors of a given node.
  1176. */
  1177. public final class TypedAncestorIterator extends AncestorIterator
  1178. {
  1179. /** The extended type ID that was requested. */
  1180. private final int _nodeType;
  1181. /**
  1182. * Constructor TypedAncestorIterator
  1183. *
  1184. *
  1185. * @param type The extended type ID being requested.
  1186. */
  1187. public TypedAncestorIterator(int type)
  1188. {
  1189. _nodeType = type;
  1190. }
  1191. /**
  1192. * Set start to END should 'close' the iterator,
  1193. * i.e. subsequent call to next() should return END.
  1194. *
  1195. * @param node Sets the root of the iteration.
  1196. *
  1197. * @return A DTMAxisIterator set to the start of the iteration.
  1198. */
  1199. public DTMAxisIterator setStartNode(int node)
  1200. {
  1201. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  1202. if (node == DTMDefaultBase.ROOTNODE)
  1203. node = getDocument();
  1204. m_realStartNode = node;
  1205. if (_isRestartable)
  1206. {
  1207. int nodeID = makeNodeIdentity(node);
  1208. m_size = 0;
  1209. if (nodeID == DTM.NULL) {
  1210. _currentNode = DTM.NULL;
  1211. m_ancestorsPos = 0;
  1212. return this;
  1213. }
  1214. final int nodeType = _nodeType;
  1215. if (!_includeSelf) {
  1216. nodeID = _parent2(nodeID);
  1217. node = makeNodeHandle(nodeID);
  1218. }
  1219. _startNode = node;
  1220. if (nodeType >= DTM.NTYPES) {
  1221. while (nodeID != END) {
  1222. int eType = _exptype2(nodeID);
  1223. if (eType == nodeType) {
  1224. if (m_size >= m_ancestors.length)
  1225. {
  1226. int[] newAncestors = new int[m_size * 2];
  1227. System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
  1228. m_ancestors = newAncestors;
  1229. }
  1230. m_ancestors[m_size++] = makeNodeHandle(nodeID);
  1231. }
  1232. nodeID = _parent2(nodeID);
  1233. }
  1234. }
  1235. else {
  1236. while (nodeID != END) {
  1237. int eType = _exptype2(nodeID);
  1238. if ((eType < DTM.NTYPES && eType == nodeType)
  1239. || (eType >= DTM.NTYPES
  1240. && m_extendedTypes[eType].getNodeType() == nodeType)) {
  1241. if (m_size >= m_ancestors.length)
  1242. {
  1243. int[] newAncestors = new int[m_size * 2];
  1244. System.arraycopy(m_ancestors, 0, newAncestors, 0, m_ancestors.length);
  1245. m_ancestors = newAncestors;
  1246. }
  1247. m_ancestors[m_size++] = makeNodeHandle(nodeID);
  1248. }
  1249. nodeID = _parent2(nodeID);
  1250. }
  1251. }
  1252. m_ancestorsPos = m_size - 1;
  1253. _currentNode = (m_ancestorsPos>=0)
  1254. ? m_ancestors[m_ancestorsPos]
  1255. : DTM.NULL;
  1256. return resetPosition();
  1257. }
  1258. return this;
  1259. }
  1260. /**
  1261. * Return the node at the given position.
  1262. */
  1263. public int getNodeByPosition(int position)
  1264. {
  1265. if (position > 0 && position <= m_size) {
  1266. return m_ancestors[position-1];
  1267. }
  1268. else
  1269. return DTM.NULL;
  1270. }
  1271. /**
  1272. * Returns the position of the last node within the iteration, as
  1273. * defined by XPath.
  1274. */
  1275. public int getLast() {
  1276. return m_size;
  1277. }
  1278. } // end of TypedAncestorIterator
  1279. /**
  1280. * Iterator that returns the descendants of a given node.
  1281. */
  1282. public class DescendantIterator extends InternalAxisIteratorBase
  1283. {
  1284. /**
  1285. * Set start to END should 'close' the iterator,
  1286. * i.e. subsequent call to next() should return END.
  1287. *
  1288. * @param node Sets the root of the iteration.
  1289. *
  1290. * @return A DTMAxisIterator set to the start of the iteration.
  1291. */
  1292. public DTMAxisIterator setStartNode(int node)
  1293. {
  1294. //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily
  1295. if (node == DTMDefaultBase.ROOTNODE)
  1296. node = getDocument();
  1297. if (_isRestartable)
  1298. {
  1299. node = makeNodeIdentity(node);
  1300. _startNode = node;
  1301. if (_includeSelf)
  1302. node--;
  1303. _currentNode = node;
  1304. return resetPosition();
  1305. }
  1306. return this;
  1307. }
  1308. /**
  1309. * Tell if this node identity is a descendant. Assumes that
  1310. * the node info for the element has already been obtained.
  1311. *
  1312. * This one-sided test works only if the parent has been
  1313. * previously tested and is known to be a descendent. It fails if
  1314. * the parent is the _startNode's next sibling, or indeed any node
  1315. * that follows _startNode in document order. That may suffice
  1316. * for this iterator, but it's not really an isDescendent() test.
  1317. * %REVIEW% rename?
  1318. *
  1319. * @param identity The index number of the node in question.
  1320. * @return true if the index is a descendant of _startNode.
  1321. */
  1322. protected final boolean isDescendant(int identity)
  1323. {
  1324. return (_parent2(identity) >= _startNode) || (_startNode == identity);
  1325. }
  1326. /**
  1327. * Get the next node in the iteration.
  1328. *
  1329. * @return The next node handle in the iteration, or END.
  1330. */
  1331. public int next()
  1332. {
  1333. final int startNode = _startNode;
  1334. if (startNode == NULL) {
  1335. return NULL;
  1336. }
  1337. if (_includeSelf && (_currentNode + 1) == startNode)
  1338. return returnNode(makeNodeHandle(++_currentNode)); // | m_dtmIdent);
  1339. int node = _currentNode;
  1340. int type;
  1341. // %OPT% If the startNode is the root node, do not need
  1342. // to do the isDescendant() check.
  1343. if (startNode == ROOTNODE) {
  1344. int eType;
  1345. do {
  1346. node++;
  1347. eType = _exptype2(node);
  1348. if (NULL == eType) {
  1349. _currentNode = NULL;
  1350. return END;
  1351. }
  1352. } while (eType == TEXT_NODE
  1353. || (type = m_extendedTypes[eType].getNodeType()) == ATTRIBUTE_NODE
  1354. || type == NAMESPACE_NODE);
  1355. }
  1356. else {
  1357. do {
  1358. node++;
  1359. type = _type2(node);
  1360. if (NULL == type ||!isDescendant(node)) {
  1361. _currentNode = NULL;
  1362. return END;
  1363. }
  1364. } while(ATTRIBUTE_NODE == type || TEXT_NODE == type
  1365. || NAMESPACE_NODE == type);
  1366. }
  1367. _currentNode = node;
  1368. return returnNode(makeNodeHandle(node)); // make handle.
  1369. }
  1370. /**
  1371. * Reset.
  1372. *
  1373. */
  1374. public DTMAxisIterator reset()
  1375. {
  1376. final boolean temp = _isRestartable;
  1377. _isRestartable = true;
  1378. setStartNode(makeNodeHandle(_startNode));
  1379. _isRestartable = temp;
  1380. return this;
  1381. }
  1382. } // end of DescendantIterator
  1383. /**
  1384. * Typed iterator that returns the descendants of a given node.
  1385. */
  1386. public final class TypedDescendantIterator extends DescendantIterator
  1387. {
  1388. /** The extended type ID that was requested. */
  1389. private final int _nodeType;
  1390. /**
  1391. * Constructor TypedDescendantIterator
  1392. *
  1393. *
  1394. * @param nodeType Extended type ID being requested.
  1395. */
  1396. public TypedDescendantIterator(int nodeType)
  1397. {
  1398. _nodeType = nodeType;
  1399. }
  1400. /**
  1401. * Get the next node in the iteration.
  1402. *
  1403. * @return The next node handle in the iteration, or END.
  1404. */
  1405. public int next()
  1406. {
  1407. final int startNode = _startNode;
  1408. if (_startNode == NULL) {
  1409. return NULL;
  1410. }
  1411. int node = _currentNode;
  1412. int expType;
  1413. final int nodeType = _nodeType;
  1414. if (nodeType != DTM.ELEMENT_NODE)
  1415. {
  1416. do
  1417. {
  1418. node++;
  1419. expType = _exptype2(node);
  1420. if (NULL == expType || _parent2(node) < startNode && startNode != node) {
  1421. _currentNode = NULL;
  1422. return END;
  1423. }
  1424. }
  1425. while (expType != nodeType);
  1426. }
  1427. // %OPT% If the start node is root (e.g. in the case of //node),
  1428. // we can save the isDescendant() check, because all nodes are
  1429. // descendants of root.
  1430. else if (startNode == DTMDefaultBase.ROOTNODE)
  1431. {
  1432. do
  1433. {
  1434. node++;
  1435. expType = _exptype2(node);
  1436. if (NULL == expType) {
  1437. _currentNode = NULL;
  1438. return END;
  1439. }
  1440. } while (expType < DTM.NTYPES
  1441. || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
  1442. }
  1443. else
  1444. {
  1445. do
  1446. {
  1447. node++;
  1448. expType = _exptype2(node);
  1449. if (NULL == expType || _parent2(node) < startNode && startNode != node) {
  1450. _currentNode = NULL;
  1451. return END;
  1452. }
  1453. }
  1454. while (expType < DTM.NTYPES
  1455. || m_extendedTypes[expType].getNodeType() != DTM.ELEMENT_NODE);
  1456. }
  1457. _currentNode = node;
  1458. return returnNode(makeNodeHandle(node));
  1459. }
  1460. } // end of TypedDescendantIterator
  1461. /**
  1462. * Iterator that returns a given node only if it is of a given type.
  1463. */
  1464. public final class TypedSingletonIterator extends SingletonIterator
  1465. {
  1466. /** The extended type ID that was requested. */
  1467. private final int _nodeType;
  1468. /**
  1469. * Constructor TypedSingletonIterator
  1470. *
  1471. *
  1472. * @param nodeType The extended type ID being requested.
  1473. */
  1474. public TypedSingletonIterator(int nodeType)
  1475. {
  1476. _nodeType = nodeType;
  1477. }
  1478. /**
  1479. * Get the next node in the iteration.
  1480. *
  1481. * @return The next node handle in the iteration, or END.
  1482. */
  1483. public int next()
  1484. {
  1485. final int result = _currentNode;
  1486. if (result == END)
  1487. return DTM.NULL;
  1488. _currentNode = END;
  1489. if (_nodeType >= DTM.NTYPES) {
  1490. if (_exptype2(makeNodeIdentity(result)) == _nodeType) {
  1491. return returnNode(result);
  1492. }
  1493. }
  1494. else {
  1495. if (_type2(makeNodeIdentity(result)) == _nodeType) {
  1496. return returnNode(result);
  1497. }
  1498. }
  1499. return NULL;
  1500. }
  1501. } // end of TypedSingletonIterator
  1502. /*******************************************************************
  1503. * End of nested iterators
  1504. *******************************************************************/
  1505. // %OPT% Array references which are used to cache the map0 arrays in
  1506. // SuballocatedIntVectors. Using the cached arrays reduces the level
  1507. // of indirection and results in better performance than just calling
  1508. // SuballocatedIntVector.elementAt().
  1509. private int[] m_exptype_map0;
  1510. private int[] m_nextsib_map0;
  1511. private int[] m_firstch_map0;
  1512. private int[] m_parent_map0;
  1513. // Double array references to the map arrays in SuballocatedIntVectors.
  1514. private int[][] m_exptype_map;
  1515. private int[][] m_nextsib_map;
  1516. private int[][] m_firstch_map;
  1517. private int[][] m_parent_map;
  1518. // %OPT% Cache the array of extended types in this class
  1519. protected ExtendedType[] m_extendedTypes;
  1520. // A Vector which is used to store the values of attribute, namespace,
  1521. // comment and PI nodes.
  1522. //
  1523. // %OPT% These values are unlikely to be equal. Storing
  1524. // them in a plain Vector is more efficient than storing in the
  1525. // DTMStringPool because we can save the cost for hash calculation.
  1526. //
  1527. // %REVISIT% Do we need a custom class (e.g. StringVector) here?
  1528. protected Vector m_values;
  1529. // The current index into the m_values Vector.
  1530. private int m_valueIndex = 0;
  1531. // The maximum value of the current node index.
  1532. private int m_maxNodeIndex;
  1533. // Cache the shift and mask values for the SuballocatedIntVectors.
  1534. protected int m_SHIFT;
  1535. protected int m_MASK;
  1536. protected int m_blocksize;
  1537. /** %OPT% If the offset and length of a Text node are within certain limits,
  1538. * we store a bitwise encoded value into an int, using 10 bits (max. 1024)
  1539. * for length and 21 bits for offset. We can save two SuballocatedIntVector
  1540. * calls for each getStringValueX() and dispatchCharacterEvents() call by
  1541. * doing this.
  1542. */
  1543. // The number of bits for the length of a Text node.
  1544. protected final static int TEXT_LENGTH_BITS = 10;
  1545. // The number of bits for the offset of a Text node.
  1546. protected final static int TEXT_OFFSET_BITS = 21;
  1547. // The maximum length value
  1548. protected final static int TEXT_LENGTH_MAX = (1<<TEXT_LENGTH_BITS) - 1;
  1549. // The maximum offset value
  1550. protected final static int TEXT_OFFSET_MAX = (1<<TEXT_OFFSET_BITS) - 1;
  1551. // True if we want to build the ID index table.
  1552. protected boolean m_buildIdIndex = true;
  1553. // Constant for empty String
  1554. private static final String EMPTY_STR = "";
  1555. // Constant for empty XMLString
  1556. private static final XMLString EMPTY_XML_STR = new XMLStringDefault("");
  1557. /**
  1558. * Construct a SAX2DTM2 object using the default block size.
  1559. */
  1560. public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
  1561. DTMWSFilter whiteSpaceFilter,
  1562. XMLStringFactory xstringfactory,
  1563. boolean doIndexing)
  1564. {
  1565. this(mgr, source, dtmIdentity, whiteSpaceFilter,
  1566. xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, true, false);
  1567. }
  1568. /**
  1569. * Construct a SAX2DTM2 object using the given block size.
  1570. */
  1571. public SAX2DTM2(DTMManager mgr, Source source, int dtmIdentity,
  1572. DTMWSFilter whiteSpaceFilter,
  1573. XMLStringFactory xstringfactory,
  1574. boolean doIndexing,
  1575. int blocksize,
  1576. boolean usePrevsib,
  1577. boolean buildIdIndex,
  1578. boolean newNameTable)
  1579. {
  1580. super(mgr, source, dtmIdentity, whiteSpaceFilter,
  1581. xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable);
  1582. // Initialize the values of m_SHIFT and m_MASK.
  1583. int shift;
  1584. for(shift=0; (blocksize>>>=1) != 0; ++shift);
  1585. m_blocksize = 1<<shift;
  1586. m_SHIFT = shift;
  1587. m_MASK = m_blocksize - 1;
  1588. m_buildIdIndex = buildIdIndex;
  1589. // Some documents do not have attribute nodes. That is why
  1590. // we set the initial size of this Vector to be small and set
  1591. // the increment to a bigger number.
  1592. m_values = new Vector(32, 512);
  1593. m_maxNodeIndex = 1 << DTMManager.IDENT_DTM_NODE_BITS;
  1594. // Set the map0 values in the constructor.
  1595. m_exptype_map0 = m_exptype.getMap0();
  1596. m_nextsib_map0 = m_nextsib.getMap0();
  1597. m_firstch_map0 = m_firstch.getMap0();
  1598. m_parent_map0 = m_parent.getMap0();
  1599. }
  1600. /**
  1601. * Override DTMDefaultBase._exptype() by dropping the incremental code.
  1602. *
  1603. * <p>This one is less efficient than _exptype2. It is only used during
  1604. * DTM building. _exptype2 is used after the document is fully built.
  1605. */
  1606. public final int _exptype(int identity)
  1607. {
  1608. return m_exptype.elementAt(identity);
  1609. }
  1610. /************************************************************************
  1611. * DTM base accessor interfaces
  1612. *
  1613. * %OPT% The code in the following interfaces (e.g. _exptype2, etc.) are
  1614. * very important to the DTM performance. To have the best performace,
  1615. * these several interfaces have direct access to the internal arrays of
  1616. * the SuballocatedIntVectors. The final modifier also has a noticeable
  1617. * impact on performance.
  1618. ***********************************************************************/
  1619. /**
  1620. * The optimized version of DTMDefaultBase._exptype().
  1621. *
  1622. * @param identity A node identity, which <em>must not</em> be equal to
  1623. * <code>DTM.NULL</code>
  1624. */
  1625. public final int _exptype2(int identity)
  1626. {
  1627. //return m_exptype.elementAt(identity);
  1628. if (identity < m_blocksize)
  1629. return m_exptype_map0[identity];
  1630. else
  1631. return m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
  1632. }
  1633. /**
  1634. * The optimized version of DTMDefaultBase._nextsib().
  1635. *
  1636. * @param identity A node identity, which <em>must not</em> be equal to
  1637. * <code>DTM.NULL</code>
  1638. */
  1639. public final int _nextsib2(int identity)
  1640. {
  1641. //return m_nextsib.elementAt(identity);
  1642. if (identity < m_blocksize)
  1643. return m_nextsib_map0[identity];
  1644. else
  1645. return m_nextsib_map[identity>>>m_SHIFT][identity&m_MASK];
  1646. }
  1647. /**
  1648. * The optimized version of DTMDefaultBase._firstch().
  1649. *
  1650. * @param identity A node identity, which <em>must not</em> be equal to
  1651. * <code>DTM.NULL</code>
  1652. */
  1653. public final int _firstch2(int identity)
  1654. {
  1655. //return m_firstch.elementAt(identity);
  1656. if (identity < m_blocksize)
  1657. return m_firstch_map0[identity];
  1658. else
  1659. return m_firstch_map[identity>>>m_SHIFT][identity&m_MASK];
  1660. }
  1661. /**
  1662. * The optimized version of DTMDefaultBase._parent().
  1663. *
  1664. * @param identity A node identity, which <em>must not</em> be equal to
  1665. * <code>DTM.NULL</code>
  1666. */
  1667. public final int _parent2(int identity)
  1668. {
  1669. //return m_parent.elementAt(identity);
  1670. if (identity < m_blocksize)
  1671. return m_parent_map0[identity];
  1672. else
  1673. return m_parent_map[identity>>>m_SHIFT][identity&m_MASK];
  1674. }
  1675. /**
  1676. * The optimized version of DTMDefaultBase._type().
  1677. *
  1678. * @param identity A node identity, which <em>must not</em> be equal to
  1679. * <code>DTM.NULL</code>
  1680. */
  1681. public final int _type2(int identity)
  1682. {
  1683. //int eType = _exptype2(identity);
  1684. int eType;
  1685. if (identity < m_blocksize)
  1686. eType = m_exptype_map0[identity];
  1687. else
  1688. eType = m_exptype_map[identity>>>m_SHIFT][identity&m_MASK];
  1689. if (NULL != eType)
  1690. return m_extendedTypes[eType].getNodeType();
  1691. else
  1692. return NULL;
  1693. }
  1694. /**
  1695. * The optimized version of DTMDefaultBase.getExpandedTypeID(int).
  1696. *
  1697. * <p>This one is only used by DOMAdapter.getExpandedTypeID(int), which
  1698. * is mostly called from the compiled translets.
  1699. */
  1700. public final int getExpandedTypeID2(int nodeHandle)
  1701. {
  1702. int nodeID = makeNodeIdentity(nodeHandle);
  1703. //return (nodeID != NULL) ? _exptype2(nodeID) : NULL;
  1704. if (nodeID != NULL) {
  1705. if (nodeID < m_blocksize)
  1706. return m_exptype_map0[nodeID];
  1707. else
  1708. return m_exptype_map[nodeID>>>m_SHIFT][nodeID&m_MASK];
  1709. }
  1710. else
  1711. return NULL;
  1712. }
  1713. /*************************************************************************
  1714. * END of DTM base accessor interfaces
  1715. *************************************************************************/
  1716. /**
  1717. * Return the node type from the expanded type
  1718. */
  1719. public final int _exptype2Type(int exptype)
  1720. {
  1721. if (NULL != exptype)
  1722. return m_extendedTypes[exptype].getNodeType();
  1723. else
  1724. return NULL;
  1725. }
  1726. /**
  1727. * Get a prefix either from the uri mapping, or just make
  1728. * one up!
  1729. *
  1730. * @param uri The namespace URI, which may be null.
  1731. *
  1732. * @return The prefix if there is one, or null.
  1733. */
  1734. public int getIdForNamespace(String uri)
  1735. {
  1736. int index = m_values.indexOf(uri);
  1737. if (index < 0)
  1738. {
  1739. m_values.addElement(uri);
  1740. return m_valueIndex++;
  1741. }
  1742. else
  1743. return index;
  1744. }
  1745. /**
  1746. * Override SAX2DTM.startElement()
  1747. *
  1748. * <p>Receive notification of the start of an element.
  1749. *
  1750. * <p>By default, do nothing. Application writers may override this
  1751. * method in a subclass to take specific actions at the start of
  1752. * each element (such as allocating a new tree node or writing
  1753. * output to a file).</p>
  1754. *
  1755. * @param name The element type name.
  1756. *
  1757. * @param uri The Namespace URI, or the empty string if the
  1758. * element has no Namespace URI or if Namespace
  1759. * processing is not being performed.
  1760. * @param localName The local name (without prefix), or the
  1761. * empty string if Namespace processing is not being
  1762. * performed.
  1763. * @param qName The qualified name (with prefix), or the
  1764. * empty string if qualified names are not available.
  1765. * @param attributes The specified or defaulted attributes.
  1766. * @throws SAXException Any SAX exception, possibly
  1767. * wrapping another exception.
  1768. * @see org.xml.sax.ContentHandler#startElement
  1769. */
  1770. public void startElement(String uri, String localName, String qName, Attributes attributes)
  1771. throws SAXException
  1772. {
  1773. charactersFlush();
  1774. int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE);
  1775. int prefixIndex = (qName.length() != localName.length())
  1776. ? m_valuesOrPrefixes.stringToIndex(qName) : 0;
  1777. int elemNode = addNode(DTM.ELEMENT_NODE, exName,
  1778. m_parents.peek(), m_previous, prefixIndex, true);
  1779. if(m_indexing)
  1780. indexNode(exName, elemNode);
  1781. m_parents.push(elemNode);
  1782. int startDecls = m_contextIndexes.peek();
  1783. int nDecls = m_prefixMappings.size();
  1784. String prefix;
  1785. if(!m_pastFirstElement)
  1786. {
  1787. // SPECIAL CASE: Implied declaration at root element
  1788. prefix="xml";
  1789. String declURL = "http://www.w3.org/XML/1998/namespace";
  1790. exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
  1791. m_values.addElement(declURL);
  1792. int val = m_valueIndex++;
  1793. addNode(DTM.NAMESPACE_NODE, exName, elemNode,
  1794. DTM.NULL, val, false);
  1795. m_pastFirstElement=true;
  1796. }
  1797. for (int i = startDecls; i < nDecls; i += 2)
  1798. {
  1799. prefix = (String) m_prefixMappings.elementAt(i);
  1800. if (prefix == null)
  1801. continue;
  1802. String declURL = (String) m_prefixMappings.elementAt(i + 1);
  1803. exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
  1804. m_values.addElement(declURL);
  1805. int val = m_valueIndex++;
  1806. addNode(DTM.NAMESPACE_NODE, exName, elemNode, DTM.NULL, val, false);
  1807. }
  1808. int n = attributes.getLength();
  1809. for (int i = 0; i < n; i++)
  1810. {
  1811. String attrUri = attributes.getURI(i);
  1812. String attrQName = attributes.getQName(i);
  1813. String valString = attributes.getValue(i);
  1814. int nodeType;
  1815. String attrLocalName = attributes.getLocalName(i);
  1816. if ((null != attrQName)
  1817. && (attrQName.equals("xmlns")
  1818. || attrQName.startsWith("xmlns:")))
  1819. {
  1820. prefix = getPrefix(attrQName, attrUri);
  1821. if (declAlreadyDeclared(prefix))
  1822. continue; // go to the next attribute.
  1823. nodeType = DTM.NAMESPACE_NODE;
  1824. }
  1825. else
  1826. {
  1827. nodeType = DTM.ATTRIBUTE_NODE;
  1828. if (m_buildIdIndex && attributes.getType(i).equalsIgnoreCase("ID"))
  1829. setIDAttribute(valString, elemNode);
  1830. }
  1831. // Bit of a hack... if somehow valString is null, stringToIndex will
  1832. // return -1, which will make things very unhappy.
  1833. if(null == valString)
  1834. valString = "";
  1835. m_values.addElement(valString);
  1836. int val = m_valueIndex++;
  1837. if (attrLocalName.length() != attrQName.length())
  1838. {
  1839. prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName);
  1840. int dataIndex = m_data.size();
  1841. m_data.addElement(prefixIndex);
  1842. m_data.addElement(val);
  1843. val = -dataIndex;
  1844. }
  1845. exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType);
  1846. addNode(nodeType, exName, elemNode, DTM.NULL, val,
  1847. false);
  1848. }
  1849. if (null != m_wsfilter)
  1850. {
  1851. short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this);
  1852. boolean shouldStrip = (DTMWSFilter.INHERIT == wsv)
  1853. ? getShouldStripWhitespace()
  1854. : (DTMWSFilter.STRIP == wsv);
  1855. pushShouldStripWhitespace(shouldStrip);
  1856. }
  1857. m_previous = DTM.NULL;
  1858. m_contextIndexes.push(m_prefixMappings.size()); // for the children.
  1859. }
  1860. /**
  1861. * Receive notification of the end of an element.
  1862. *
  1863. * <p>By default, do nothing. Application writers may override this
  1864. * method in a subclass to take specific actions at the end of
  1865. * each element (such as finalising a tree node or writing
  1866. * output to a file).</p>
  1867. *
  1868. * @param name The element type name.
  1869. * @param attributes The specified or defaulted attributes.
  1870. *
  1871. * @param uri The Namespace URI, or the empty string if the
  1872. * element has no Namespace URI or if Namespace
  1873. * processing is not being performed.
  1874. * @param localName The local name (without prefix), or the
  1875. * empty string if Namespace processing is not being
  1876. * performed.
  1877. * @param qName The qualified XML 1.0 name (with prefix), or the
  1878. * empty string if qualified names are not available.
  1879. * @throws SAXException Any SAX exception, possibly
  1880. * wrapping another exception.
  1881. * @see org.xml.sax.ContentHandler#endElement
  1882. */
  1883. public void endElement(String uri, String localName, String qName)
  1884. throws SAXException
  1885. {
  1886. charactersFlush();
  1887. // If no one noticed, startPrefixMapping is a drag.
  1888. // Pop the context for the last child (the one pushed by startElement)
  1889. m_contextIndexes.quickPop(1);
  1890. // Do it again for this one (the one pushed by the last endElement).
  1891. int topContextIndex = m_contextIndexes.peek();
  1892. if (topContextIndex != m_prefixMappings.size()) {
  1893. m_prefixMappings.setSize(topContextIndex);
  1894. }
  1895. m_previous = m_parents.pop();
  1896. popShouldStripWhitespace();
  1897. }
  1898. /**
  1899. * Report an XML comment anywhere in the document.
  1900. *
  1901. * <p>This callback will be used for comments inside or outside the
  1902. * document element, including comments in the external DTD
  1903. * subset (if read).</p>
  1904. *
  1905. * @param ch An array holding the characters in the comment.
  1906. * @param start The starting position in the array.
  1907. * @param length The number of characters to use from the array.
  1908. * @throws SAXException The application may raise an exception.
  1909. */
  1910. public void comment(char ch[], int start, int length) throws SAXException
  1911. {
  1912. if (m_insideDTD) // ignore comments if we're inside the DTD
  1913. return;
  1914. charactersFlush();
  1915. // %OPT% Saving the comment string in a Vector has a lower cost than
  1916. // saving it in DTMStringPool.
  1917. m_values.addElement(new String(ch, start, length));
  1918. int dataIndex = m_valueIndex++;
  1919. m_previous = addNode(DTM.COMMENT_NODE, DTM.COMMENT_NODE,
  1920. m_parents.peek(), m_previous, dataIndex, false);
  1921. }
  1922. /**
  1923. * Receive notification of the beginning of the document.
  1924. *
  1925. * @throws SAXException Any SAX exception, possibly
  1926. * wrapping another exception.
  1927. * @see org.xml.sax.ContentHandler#startDocument
  1928. */
  1929. public void startDocument() throws SAXException
  1930. {
  1931. int doc = addNode(DTM.DOCUMENT_NODE,
  1932. DTM.DOCUMENT_NODE,
  1933. DTM.NULL, DTM.NULL, 0, true);
  1934. m_parents.push(doc);
  1935. m_previous = DTM.NULL;
  1936. m_contextIndexes.push(m_prefixMappings.size()); // for the next element.
  1937. }
  1938. /**
  1939. * Receive notification of the end of the document.
  1940. *
  1941. * @throws SAXException Any SAX exception, possibly
  1942. * wrapping another exception.
  1943. * @see org.xml.sax.ContentHandler#endDocument
  1944. */
  1945. public void endDocument() throws SAXException
  1946. {
  1947. super.endDocument();
  1948. // Add a NULL entry to the end of the node arrays as
  1949. // the end indication.
  1950. m_exptype.addElement(NULL);
  1951. m_parent.addElement(NULL);
  1952. m_nextsib.addElement(NULL);
  1953. m_firstch.addElement(NULL);
  1954. // Set the cached references after the document is built.
  1955. m_extendedTypes = m_expandedNameTable.getExtendedTypes();
  1956. m_exptype_map = m_exptype.getMap();
  1957. m_nextsib_map = m_nextsib.getMap();
  1958. m_firstch_map = m_firstch.getMap();
  1959. m_parent_map = m_parent.getMap();
  1960. }
  1961. /**
  1962. * Construct the node map from the node.
  1963. *
  1964. * @param type raw type ID, one of DTM.XXX_NODE.
  1965. * @param expandedTypeID The expended type ID.
  1966. * @param parentIndex The current parent index.
  1967. * @param previousSibling The previous sibling index.
  1968. * @param dataOrPrefix index into m_data table, or string handle.
  1969. * @param canHaveFirstChild true if the node can have a first child, false
  1970. * if it is atomic.
  1971. *
  1972. * @return The index identity of the node that was added.
  1973. */
  1974. protected final int addNode(int type, int expandedTypeID,
  1975. int parentIndex, int previousSibling,
  1976. int dataOrPrefix, boolean canHaveFirstChild)
  1977. {
  1978. // Common to all nodes:
  1979. int nodeIndex = m_size++;
  1980. // Have we overflowed a DTM Identity's addressing range?
  1981. //if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
  1982. if (nodeIndex == m_maxNodeIndex)
  1983. {
  1984. addNewDTMID(nodeIndex);
  1985. m_maxNodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
  1986. }
  1987. m_firstch.addElement(DTM.NULL);
  1988. m_nextsib.addElement(DTM.NULL);
  1989. m_parent.addElement(parentIndex);
  1990. m_exptype.addElement(expandedTypeID);
  1991. m_dataOrQName.addElement(dataOrPrefix);
  1992. if (m_prevsib != null) {
  1993. m_prevsib.addElement(previousSibling);
  1994. }
  1995. if (m_locator != null && m_useSourceLocationProperty) {
  1996. setSourceLocation();
  1997. }
  1998. // Note that nextSibling is not processed until charactersFlush()
  1999. // is called, to handle successive characters() events.
  2000. // Special handling by type: Declare namespaces, attach first child
  2001. switch(type)
  2002. {
  2003. case DTM.NAMESPACE_NODE:
  2004. declareNamespaceInContext(parentIndex,nodeIndex);
  2005. break;
  2006. case DTM.ATTRIBUTE_NODE:
  2007. break;
  2008. default:
  2009. if (DTM.NULL != previousSibling) {
  2010. m_nextsib.setElementAt(nodeIndex,previousSibling);
  2011. }
  2012. else if (DTM.NULL != parentIndex) {
  2013. m_firstch.setElementAt(nodeIndex,parentIndex);
  2014. }
  2015. break;
  2016. }
  2017. return nodeIndex;
  2018. }
  2019. /**
  2020. * Check whether accumulated text should be stripped; if not,
  2021. * append the appropriate flavor of text/cdata node.
  2022. */
  2023. protected final void charactersFlush()
  2024. {
  2025. if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress
  2026. {
  2027. int length = m_chars.size() - m_textPendingStart;
  2028. boolean doStrip = false;
  2029. if (getShouldStripWhitespace())
  2030. {
  2031. doStrip = m_chars.isWhitespace(m_textPendingStart, length);
  2032. }
  2033. if (doStrip)
  2034. m_chars.setLength(m_textPendingStart); // Discard accumulated text
  2035. else
  2036. {
  2037. // If the offset and length do not exceed the given limits
  2038. // (offset < 2^21 and length < 2^10), then save both the offset
  2039. // and length in a bitwise encoded value.
  2040. if (length <= TEXT_LENGTH_MAX && m_textPendingStart <= TEXT_OFFSET_MAX)
  2041. {
  2042. m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
  2043. m_parents.peek(), m_previous,
  2044. length + (m_textPendingStart << TEXT_LENGTH_BITS),
  2045. false);
  2046. }
  2047. else
  2048. {
  2049. // Store the offset and length in the m_data array if one of them
  2050. // exceeds the given limits. Use a negative dataIndex as an indication.
  2051. int dataIndex = m_data.size();
  2052. m_previous = addNode(m_coalescedTextType, DTM.TEXT_NODE,
  2053. m_parents.peek(), m_previous, -dataIndex, false);
  2054. m_data.addElement(m_textPendingStart);
  2055. m_data.addElement(length);
  2056. }
  2057. }
  2058. // Reset for next text block
  2059. m_textPendingStart = -1;
  2060. m_textType = m_coalescedTextType = DTM.TEXT_NODE;
  2061. }
  2062. }
  2063. /**
  2064. * Override the processingInstruction() interface in SAX2DTM2.
  2065. * <p>
  2066. * %OPT% This one is different from SAX2DTM.processingInstruction()
  2067. * in that we do not use extended types for PI nodes. The name of
  2068. * the PI is saved in the DTMStringPool.
  2069. *
  2070. * Receive notification of a processing instruction.
  2071. *
  2072. * @param target The processing instruction target.
  2073. * @param data The processing instruction data, or null if
  2074. * none is supplied.
  2075. * @throws SAXException Any SAX exception, possibly
  2076. * wrapping another exception.
  2077. * @see org.xml.sax.ContentHandler#processingInstruction
  2078. */
  2079. public void processingInstruction(String target, String data)
  2080. throws SAXException
  2081. {
  2082. charactersFlush();
  2083. int dataIndex = m_data.size();
  2084. m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE,
  2085. DTM.PROCESSING_INSTRUCTION_NODE,
  2086. m_parents.peek(), m_previous,
  2087. -dataIndex, false);
  2088. m_data.addElement(m_valuesOrPrefixes.stringToIndex(target));
  2089. m_values.addElement(data);
  2090. m_data.addElement(m_valueIndex++);
  2091. }
  2092. /**
  2093. * The optimized version of DTMDefaultBase.getFirstAttribute().
  2094. * <p>
  2095. * Given a node handle, get the index of the node's first attribute.
  2096. *
  2097. * @param nodeHandle int Handle of the node.
  2098. * @return Handle of first attribute, or DTM.NULL to indicate none exists.
  2099. */
  2100. public final int getFirstAttribute(int nodeHandle)
  2101. {
  2102. int nodeID = makeNodeIdentity(nodeHandle);
  2103. if (nodeID == DTM.NULL)
  2104. return DTM.NULL;
  2105. int type = _type2(nodeID);
  2106. if (DTM.ELEMENT_NODE == type)
  2107. {
  2108. // Assume that attributes and namespaces immediately follow the element.
  2109. while (true)
  2110. {
  2111. nodeID++;
  2112. // Assume this can not be null.
  2113. type = _type2(nodeID);
  2114. if (type == DTM.ATTRIBUTE_NODE)
  2115. {
  2116. return makeNodeHandle(nodeID);
  2117. }
  2118. else if (DTM.NAMESPACE_NODE != type)
  2119. {
  2120. break;
  2121. }
  2122. }
  2123. }
  2124. return DTM.NULL;
  2125. }
  2126. /**
  2127. * The optimized version of DTMDefaultBase.getFirstAttributeIdentity(int).
  2128. * <p>
  2129. * Given a node identity, get the index of the node's first attribute.
  2130. *
  2131. * @param identity int identity of the node.
  2132. * @return Identity of first attribute, or DTM.NULL to indicate none exists.
  2133. */
  2134. protected int getFirstAttributeIdentity(int identity) {
  2135. if (identity == NULL) {
  2136. return NULL;
  2137. }
  2138. int type = _type2(identity);
  2139. if (DTM.ELEMENT_NODE == type)
  2140. {
  2141. // Assume that attributes and namespaces immediately follow the element.
  2142. while (true)
  2143. {
  2144. identity++;
  2145. // Assume this can not be null.
  2146. type = _type2(identity);
  2147. if (type == DTM.ATTRIBUTE_NODE)
  2148. {
  2149. return identity;
  2150. }
  2151. else if (DTM.NAMESPACE_NODE != type)
  2152. {
  2153. break;
  2154. }
  2155. }
  2156. }
  2157. return DTM.NULL;
  2158. }
  2159. /**
  2160. * The optimized version of DTMDefaultBase.getNextAttributeIdentity(int).
  2161. * <p>
  2162. * Given a node identity for an attribute, advance to the next attribute.
  2163. *
  2164. * @param identity int identity of the attribute node. This
  2165. * <strong>must</strong> be an attribute node.
  2166. *
  2167. * @return int DTM node-identity of the resolved attr,
  2168. * or DTM.NULL to indicate none exists.
  2169. *
  2170. */
  2171. protected int getNextAttributeIdentity(int identity) {
  2172. // Assume that attributes and namespace nodes immediately follow the element
  2173. while (true) {
  2174. identity++;
  2175. int type = _type2(identity);
  2176. if (type == DTM.ATTRIBUTE_NODE) {
  2177. return identity;
  2178. } else if (type != DTM.NAMESPACE_NODE) {
  2179. break;
  2180. }
  2181. }
  2182. return DTM.NULL;
  2183. }
  2184. /**
  2185. * The optimized version of DTMDefaultBase.getTypedAttribute(int, int).
  2186. * <p>
  2187. * Given a node handle and an expanded type ID, get the index of the node's
  2188. * attribute of that type, if any.
  2189. *
  2190. * @param nodeHandle int Handle of the node.
  2191. * @param attType int expanded type ID of the required attribute.
  2192. * @return Handle of attribute of the required type, or DTM.NULL to indicate
  2193. * none exists.
  2194. */
  2195. protected final int getTypedAttribute(int nodeHandle, int attType)
  2196. {
  2197. int nodeID = makeNodeIdentity(nodeHandle);
  2198. if (nodeID == DTM.NULL)
  2199. return DTM.NULL;
  2200. int type = _type2(nodeID);
  2201. if (DTM.ELEMENT_NODE == type)
  2202. {
  2203. int expType;
  2204. while (true)
  2205. {
  2206. nodeID++;
  2207. expType = _exptype2(nodeID);
  2208. if (expType != DTM.NULL)
  2209. type = m_extendedTypes[expType].getNodeType();
  2210. else
  2211. return DTM.NULL;
  2212. if (type == DTM.ATTRIBUTE_NODE)
  2213. {
  2214. if (expType == attType) return makeNodeHandle(nodeID);
  2215. }
  2216. else if (DTM.NAMESPACE_NODE != type)
  2217. {
  2218. break;
  2219. }
  2220. }
  2221. }
  2222. return DTM.NULL;
  2223. }
  2224. /**
  2225. * Override SAX2DTM.getLocalName() in SAX2DTM2.
  2226. * <p>Processing for PIs is different.
  2227. *
  2228. * Given a node handle, return its XPath- style localname. (As defined in
  2229. * Namespaces, this is the portion of the name after any colon character).
  2230. *
  2231. * @param nodeHandle the id of the node.
  2232. * @return String Local name of this node.
  2233. */
  2234. public String getLocalName(int nodeHandle)
  2235. {
  2236. int expType = _exptype(makeNodeIdentity(nodeHandle));
  2237. if (expType == DTM.PROCESSING_INSTRUCTION_NODE)
  2238. {
  2239. int dataIndex = _dataOrQName(makeNodeIdentity(nodeHandle));
  2240. dataIndex = m_data.elementAt(-dataIndex);
  2241. return m_valuesOrPrefixes.indexToString(dataIndex);
  2242. }
  2243. else
  2244. return m_expandedNameTable.getLocalName(expType);
  2245. }
  2246. /**
  2247. * The optimized version of SAX2DTM.getNodeNameX().
  2248. * <p>
  2249. * Given a node handle, return the XPath node name. This should be the name
  2250. * as described by the XPath data model, NOT the DOM- style name.
  2251. *
  2252. * @param nodeHandle the id of the node.
  2253. * @return String Name of this node, which may be an empty string.
  2254. */
  2255. public final String getNodeNameX(int nodeHandle)
  2256. {
  2257. int nodeID = makeNodeIdentity(nodeHandle);
  2258. int eType = _exptype2(nodeID);
  2259. if (eType == DTM.PROCESSING_INSTRUCTION_NODE)
  2260. {
  2261. int dataIndex = _dataOrQName(nodeID);
  2262. dataIndex = m_data.elementAt(-dataIndex);
  2263. return m_valuesOrPrefixes.indexToString(dataIndex);
  2264. }
  2265. final ExtendedType extType = m_extendedTypes[eType];
  2266. if (extType.getNamespace().length() == 0)
  2267. {
  2268. return extType.getLocalName();
  2269. }
  2270. else
  2271. {
  2272. int qnameIndex = m_dataOrQName.elementAt(nodeID);
  2273. if (qnameIndex == 0)
  2274. return extType.getLocalName();
  2275. if (qnameIndex < 0)
  2276. {
  2277. qnameIndex = -qnameIndex;
  2278. qnameIndex = m_data.elementAt(qnameIndex);
  2279. }
  2280. return m_valuesOrPrefixes.indexToString(qnameIndex);
  2281. }
  2282. }
  2283. /**
  2284. * The optimized version of SAX2DTM.getNodeName().
  2285. * <p>
  2286. * Given a node handle, return its DOM-style node name. This will include
  2287. * names such as #text or #document.
  2288. *
  2289. * @param nodeHandle the id of the node.
  2290. * @return String Name of this node, which may be an empty string.
  2291. * %REVIEW% Document when empty string is possible...
  2292. * %REVIEW-COMMENT% It should never be empty, should it?
  2293. */
  2294. public String getNodeName(int nodeHandle)
  2295. {
  2296. int nodeID = makeNodeIdentity(nodeHandle);
  2297. int eType = _exptype2(nodeID);
  2298. final ExtendedType extType = m_extendedTypes[eType];
  2299. if (extType.getNamespace().length() == 0)
  2300. {
  2301. int type = extType.getNodeType();
  2302. String localName = extType.getLocalName();
  2303. if (type == DTM.NAMESPACE_NODE)
  2304. {
  2305. if (localName.length() == 0)
  2306. return "xmlns";
  2307. else
  2308. return "xmlns:" + localName;
  2309. }
  2310. else if (type == DTM.PROCESSING_INSTRUCTION_NODE)
  2311. {
  2312. int dataIndex = _dataOrQName(nodeID);
  2313. dataIndex = m_data.elementAt(-dataIndex);
  2314. return m_valuesOrPrefixes.indexToString(dataIndex);
  2315. }
  2316. else if (localName.length() == 0)
  2317. {
  2318. return m_fixednames[type];
  2319. }
  2320. else
  2321. return localName;
  2322. }
  2323. else
  2324. {
  2325. int qnameIndex = m_dataOrQName.elementAt(nodeID);
  2326. if (qnameIndex == 0)
  2327. return extType.getLocalName();
  2328. if (qnameIndex < 0)
  2329. {
  2330. qnameIndex = -qnameIndex;
  2331. qnameIndex = m_data.elementAt(qnameIndex);
  2332. }
  2333. return m_valuesOrPrefixes.indexToString(qnameIndex);
  2334. }
  2335. }
  2336. /**
  2337. * Override SAX2DTM.getStringValue(int)
  2338. * <p>
  2339. * This method is only used by Xalan-J Interpretive. It is not used by XSLTC.
  2340. * <p>
  2341. * If the caller supplies an XMLStringFactory, the getStringValue() interface
  2342. * in SAX2DTM will be called. Otherwise just calls getStringValueX() and
  2343. * wraps the returned String in an XMLString.
  2344. *
  2345. * Get the string-value of a node as a String object
  2346. * (see http://www.w3.org/TR/xpath#data-model
  2347. * for the definition of a node's string-value).
  2348. *
  2349. * @param nodeHandle The node ID.
  2350. *
  2351. * @return A string object that represents the string-value of the given node.
  2352. */
  2353. public XMLString getStringValue(int nodeHandle)
  2354. {
  2355. int identity = makeNodeIdentity(nodeHandle);
  2356. if (identity == DTM.NULL)
  2357. return EMPTY_XML_STR;
  2358. int type= _type2(identity);
  2359. if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
  2360. {
  2361. int startNode = identity;
  2362. identity = _firstch2(identity);
  2363. if (DTM.NULL != identity)
  2364. {
  2365. int offset = -1;
  2366. int length = 0;
  2367. do
  2368. {
  2369. type = _exptype2(identity);
  2370. if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
  2371. {
  2372. int dataIndex = m_dataOrQName.elementAt(identity);
  2373. if (dataIndex > 0)
  2374. {
  2375. if (-1 == offset)
  2376. {
  2377. offset = dataIndex >>> TEXT_LENGTH_BITS;
  2378. }
  2379. length += dataIndex & TEXT_LENGTH_MAX;
  2380. }
  2381. else
  2382. {
  2383. if (-1 == offset)
  2384. {
  2385. offset = m_data.elementAt(-dataIndex);
  2386. }
  2387. length += m_data.elementAt(-dataIndex + 1);
  2388. }
  2389. }
  2390. identity++;
  2391. } while (_parent2(identity) >= startNode);
  2392. if (length > 0)
  2393. {
  2394. if (m_xstrf != null)
  2395. return m_xstrf.newstr(m_chars, offset, length);
  2396. else
  2397. return new XMLStringDefault(m_chars.getString(offset, length));
  2398. }
  2399. else
  2400. return EMPTY_XML_STR;
  2401. }
  2402. else
  2403. return EMPTY_XML_STR;
  2404. }
  2405. else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
  2406. {
  2407. int dataIndex = m_dataOrQName.elementAt(identity);
  2408. if (dataIndex > 0)
  2409. {
  2410. if (m_xstrf != null)
  2411. return m_xstrf.newstr(m_chars, dataIndex >>> TEXT_LENGTH_BITS,
  2412. dataIndex & TEXT_LENGTH_MAX);
  2413. else
  2414. return new XMLStringDefault(m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
  2415. dataIndex & TEXT_LENGTH_MAX));
  2416. }
  2417. else
  2418. {
  2419. if (m_xstrf != null)
  2420. return m_xstrf.newstr(m_chars, m_data.elementAt(-dataIndex),
  2421. m_data.elementAt(-dataIndex+1));
  2422. else
  2423. return new XMLStringDefault(m_chars.getString(m_data.elementAt(-dataIndex),
  2424. m_data.elementAt(-dataIndex+1)));
  2425. }
  2426. }
  2427. else
  2428. {
  2429. int dataIndex = m_dataOrQName.elementAt(identity);
  2430. if (dataIndex < 0)
  2431. {
  2432. dataIndex = -dataIndex;
  2433. dataIndex = m_data.elementAt(dataIndex + 1);
  2434. }
  2435. if (m_xstrf != null)
  2436. return m_xstrf.newstr((String)m_values.elementAt(dataIndex));
  2437. else
  2438. return new XMLStringDefault((String)m_values.elementAt(dataIndex));
  2439. }
  2440. }
  2441. /**
  2442. * The optimized version of SAX2DTM.getStringValue(int).
  2443. * <p>
  2444. * %OPT% This is one of the most often used interfaces. Performance is
  2445. * critical here. This one is different from SAX2DTM.getStringValue(int) in
  2446. * that it returns a String instead of a XMLString.
  2447. *
  2448. * Get the string- value of a node as a String object (see http: //www. w3.
  2449. * org/TR/xpath#data- model for the definition of a node's string- value).
  2450. *
  2451. * @param nodeHandle The node ID.
  2452. *
  2453. * @return A string object that represents the string-value of the given node.
  2454. */
  2455. public final String getStringValueX(final int nodeHandle)
  2456. {
  2457. int identity = makeNodeIdentity(nodeHandle);
  2458. if (identity == DTM.NULL)
  2459. return EMPTY_STR;
  2460. int type= _type2(identity);
  2461. if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
  2462. {
  2463. int startNode = identity;
  2464. identity = _firstch2(identity);
  2465. if (DTM.NULL != identity)
  2466. {
  2467. int offset = -1;
  2468. int length = 0;
  2469. do
  2470. {
  2471. type = _exptype2(identity);
  2472. if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
  2473. {
  2474. int dataIndex = m_dataOrQName.elementAt(identity);
  2475. if (dataIndex > 0)
  2476. {
  2477. if (-1 == offset)
  2478. {
  2479. offset = dataIndex >>> TEXT_LENGTH_BITS;
  2480. }
  2481. length += dataIndex & TEXT_LENGTH_MAX;
  2482. }
  2483. else
  2484. {
  2485. if (-1 == offset)
  2486. {
  2487. offset = m_data.elementAt(-dataIndex);
  2488. }
  2489. length += m_data.elementAt(-dataIndex + 1);
  2490. }
  2491. }
  2492. identity++;
  2493. } while (_parent2(identity) >= startNode);
  2494. if (length > 0)
  2495. {
  2496. return m_chars.getString(offset, length);
  2497. }
  2498. else
  2499. return EMPTY_STR;
  2500. }
  2501. else
  2502. return EMPTY_STR;
  2503. }
  2504. else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
  2505. {
  2506. int dataIndex = m_dataOrQName.elementAt(identity);
  2507. if (dataIndex > 0)
  2508. {
  2509. return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
  2510. dataIndex & TEXT_LENGTH_MAX);
  2511. }
  2512. else
  2513. {
  2514. return m_chars.getString(m_data.elementAt(-dataIndex),
  2515. m_data.elementAt(-dataIndex+1));
  2516. }
  2517. }
  2518. else
  2519. {
  2520. int dataIndex = m_dataOrQName.elementAt(identity);
  2521. if (dataIndex < 0)
  2522. {
  2523. dataIndex = -dataIndex;
  2524. dataIndex = m_data.elementAt(dataIndex + 1);
  2525. }
  2526. return (String)m_values.elementAt(dataIndex);
  2527. }
  2528. }
  2529. /**
  2530. * Returns the string value of the entire tree
  2531. */
  2532. public String getStringValue()
  2533. {
  2534. int child = _firstch2(ROOTNODE);
  2535. if (child == DTM.NULL) return EMPTY_STR;
  2536. // optimization: only create StringBuffer if > 1 child
  2537. if ((_exptype2(child) == DTM.TEXT_NODE) && (_nextsib2(child) == DTM.NULL))
  2538. {
  2539. int dataIndex = m_dataOrQName.elementAt(child);
  2540. if (dataIndex > 0)
  2541. return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS, dataIndex & TEXT_LENGTH_MAX);
  2542. else
  2543. return m_chars.getString(m_data.elementAt(-dataIndex),
  2544. m_data.elementAt(-dataIndex + 1));
  2545. }
  2546. else
  2547. return getStringValueX(getDocument());
  2548. }
  2549. /**
  2550. * The optimized version of SAX2DTM.dispatchCharactersEvents(int, ContentHandler, boolean).
  2551. * <p>
  2552. * Directly call the
  2553. * characters method on the passed ContentHandler for the
  2554. * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
  2555. * for the definition of a node's string-value). Multiple calls to the
  2556. * ContentHandler's characters methods may well occur for a single call to
  2557. * this method.
  2558. *
  2559. * @param nodeHandle The node ID.
  2560. * @param ch A non-null reference to a ContentHandler.
  2561. * @param normalize true if the content should be normalized according to
  2562. * the rules for the XPath
  2563. * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
  2564. * function.
  2565. *
  2566. * @throws SAXException
  2567. */
  2568. public final void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
  2569. boolean normalize)
  2570. throws SAXException
  2571. {
  2572. int identity = makeNodeIdentity(nodeHandle);
  2573. if (identity == DTM.NULL)
  2574. return;
  2575. int type = _type2(identity);
  2576. if (type == DTM.ELEMENT_NODE || type == DTM.DOCUMENT_NODE)
  2577. {
  2578. int startNode = identity;
  2579. identity = _firstch2(identity);
  2580. if (DTM.NULL != identity)
  2581. {
  2582. int offset = -1;
  2583. int length = 0;
  2584. do
  2585. {
  2586. type = _exptype2(identity);
  2587. if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
  2588. {
  2589. int dataIndex = m_dataOrQName.elementAt(identity);
  2590. if (dataIndex > 0)
  2591. {
  2592. if (-1 == offset)
  2593. {
  2594. offset = dataIndex >>> TEXT_LENGTH_BITS;
  2595. }
  2596. length += dataIndex & TEXT_LENGTH_MAX;
  2597. }
  2598. else
  2599. {
  2600. if (-1 == offset)
  2601. {
  2602. offset = m_data.elementAt(-dataIndex);
  2603. }
  2604. length += m_data.elementAt(-dataIndex + 1);
  2605. }
  2606. }
  2607. identity++;
  2608. } while (_parent2(identity) >= startNode);
  2609. if (length > 0)
  2610. {
  2611. if(normalize)
  2612. m_chars.sendNormalizedSAXcharacters(ch, offset, length);
  2613. else
  2614. m_chars.sendSAXcharacters(ch, offset, length);
  2615. }
  2616. }
  2617. }
  2618. else if (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type)
  2619. {
  2620. int dataIndex = m_dataOrQName.elementAt(identity);
  2621. if (dataIndex > 0)
  2622. {
  2623. if (normalize)
  2624. m_chars.sendNormalizedSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
  2625. dataIndex & TEXT_LENGTH_MAX);
  2626. else
  2627. m_chars.sendSAXcharacters(ch, dataIndex >>> TEXT_LENGTH_BITS,
  2628. dataIndex & TEXT_LENGTH_MAX);
  2629. }
  2630. else
  2631. {
  2632. if (normalize)
  2633. m_chars.sendNormalizedSAXcharacters(ch, m_data.elementAt(-dataIndex),
  2634. m_data.elementAt(-dataIndex+1));
  2635. else
  2636. m_chars.sendSAXcharacters(ch, m_data.elementAt(-dataIndex),
  2637. m_data.elementAt(-dataIndex+1));
  2638. }
  2639. }
  2640. else
  2641. {
  2642. int dataIndex = m_dataOrQName.elementAt(identity);
  2643. if (dataIndex < 0)
  2644. {
  2645. dataIndex = -dataIndex;
  2646. dataIndex = m_data.elementAt(dataIndex + 1);
  2647. }
  2648. String str = (String)m_values.elementAt(dataIndex);
  2649. if(normalize)
  2650. FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(),
  2651. 0, str.length(), ch);
  2652. else
  2653. ch.characters(str.toCharArray(), 0, str.length());
  2654. }
  2655. }
  2656. /**
  2657. * Given a node handle, return its node value. This is mostly
  2658. * as defined by the DOM, but may ignore some conveniences.
  2659. * <p>
  2660. *
  2661. * @param nodeHandle The node id.
  2662. * @return String Value of this node, or null if not
  2663. * meaningful for this node type.
  2664. */
  2665. public String getNodeValue(int nodeHandle)
  2666. {
  2667. int identity = makeNodeIdentity(nodeHandle);
  2668. int type = _type2(identity);
  2669. if (type == DTM.TEXT_NODE || type == DTM.CDATA_SECTION_NODE)
  2670. {
  2671. int dataIndex = _dataOrQName(identity);
  2672. if (dataIndex > 0)
  2673. {
  2674. return m_chars.getString(dataIndex >>> TEXT_LENGTH_BITS,
  2675. dataIndex & TEXT_LENGTH_MAX);
  2676. }
  2677. else
  2678. {
  2679. return m_chars.getString(m_data.elementAt(-dataIndex),
  2680. m_data.elementAt(-dataIndex+1));
  2681. }
  2682. }
  2683. else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
  2684. || DTM.DOCUMENT_NODE == type)
  2685. {
  2686. return null;
  2687. }
  2688. else
  2689. {
  2690. int dataIndex = m_dataOrQName.elementAt(identity);
  2691. if (dataIndex < 0)
  2692. {
  2693. dataIndex = -dataIndex;
  2694. dataIndex = m_data.elementAt(dataIndex + 1);
  2695. }
  2696. return (String)m_values.elementAt(dataIndex);
  2697. }
  2698. }
  2699. /**
  2700. * Copy the String value of a Text node to a SerializationHandler
  2701. */
  2702. protected final void copyTextNode(final int nodeID, SerializationHandler handler)
  2703. throws SAXException
  2704. {
  2705. if (nodeID != DTM.NULL) {
  2706. int dataIndex = m_dataOrQName.elementAt(nodeID);
  2707. if (dataIndex > 0) {
  2708. m_chars.sendSAXcharacters(handler,
  2709. dataIndex >>> TEXT_LENGTH_BITS,
  2710. dataIndex & TEXT_LENGTH_MAX);
  2711. } else {
  2712. m_chars.sendSAXcharacters(handler, m_data.elementAt(-dataIndex),
  2713. m_data.elementAt(-dataIndex+1));
  2714. }
  2715. }
  2716. }
  2717. /**
  2718. * Copy an Element node to a SerializationHandler.
  2719. *
  2720. * @param nodeID The node identity
  2721. * @param exptype The expanded type of the Element node
  2722. * @param handler The SerializationHandler
  2723. * @return The qualified name of the Element node.
  2724. */
  2725. protected final String copyElement(int nodeID, int exptype,
  2726. SerializationHandler handler)
  2727. throws SAXException
  2728. {
  2729. final ExtendedType extType = m_extendedTypes[exptype];
  2730. String uri = extType.getNamespace();
  2731. String name = extType.getLocalName();
  2732. if (uri.length() == 0) {
  2733. handler.startElement(name);
  2734. return name;
  2735. }
  2736. else {
  2737. int qnameIndex = m_dataOrQName.elementAt(nodeID);
  2738. if (qnameIndex == 0) {
  2739. handler.startElement(name);
  2740. handler.namespaceAfterStartElement(EMPTY_STR, uri);
  2741. return name;
  2742. }
  2743. if (qnameIndex < 0) {
  2744. qnameIndex = -qnameIndex;
  2745. qnameIndex = m_data.elementAt(qnameIndex);
  2746. }
  2747. String qName = m_valuesOrPrefixes.indexToString(qnameIndex);
  2748. handler.startElement(qName);
  2749. int prefixIndex = qName.indexOf(':');
  2750. String prefix;
  2751. if (prefixIndex > 0) {
  2752. prefix = qName.substring(0, prefixIndex);
  2753. }
  2754. else {
  2755. prefix = null;
  2756. }
  2757. handler.namespaceAfterStartElement(prefix, uri);
  2758. return qName;
  2759. }
  2760. }
  2761. /**
  2762. * Copy namespace nodes.
  2763. *
  2764. * @param nodeID The Element node identity
  2765. * @param handler The SerializationHandler
  2766. * @param inScope true if all namespaces in scope should be copied,
  2767. * false if only the namespace declarations should be copied.
  2768. */
  2769. protected final void copyNS(final int nodeID, SerializationHandler handler, boolean inScope)
  2770. throws SAXException{
  2771. final int node = makeNodeHandle(nodeID);
  2772. for(int current = getFirstNamespaceNode(node, inScope); current != DTM.NULL;
  2773. current = getNextNamespaceNode(node, current, inScope)){
  2774. handler.namespaceAfterStartElement(getNodeNameX(current), getNodeValue(current));
  2775. }
  2776. }
  2777. /**
  2778. * Copy attribute nodes from an element .
  2779. *
  2780. * @param nodeID The Element node identity
  2781. * @param handler The SerializationHandler
  2782. */
  2783. protected final void copyAttributes(final int nodeID, SerializationHandler handler)
  2784. throws SAXException{
  2785. for(int current = getFirstAttributeIdentity(nodeID); current != DTM.NULL; current = getNextAttributeIdentity(current)){
  2786. int eType = _exptype2(current);
  2787. copyAttribute(current, eType, handler);
  2788. }
  2789. }
  2790. /**
  2791. * Copy an Attribute node to a SerializationHandler
  2792. *
  2793. * @param nodeID The node identity
  2794. * @param exptype The expanded type of the Element node
  2795. * @param handler The SerializationHandler
  2796. */
  2797. protected final void copyAttribute(int nodeID, int exptype,
  2798. SerializationHandler handler)
  2799. throws SAXException
  2800. {
  2801. /*
  2802. final String uri = getNamespaceName(node);
  2803. if (uri.length() != 0) {
  2804. final String prefix = getPrefix(node);
  2805. handler.namespaceAfterStartElement(prefix, uri);
  2806. }
  2807. handler.addAttribute(getNodeName(node), getNodeValue(node));
  2808. */
  2809. final ExtendedType extType = m_extendedTypes[exptype];
  2810. final String uri = extType.getNamespace();
  2811. final String localName = extType.getLocalName();
  2812. String prefix = null;
  2813. String qname = null;
  2814. int dataIndex = _dataOrQName(nodeID);
  2815. int valueIndex = dataIndex;
  2816. if (uri.length() != 0) {
  2817. if (dataIndex <= 0) {
  2818. int prefixIndex = m_data.elementAt(-dataIndex);
  2819. valueIndex = m_data.elementAt(-dataIndex+1);
  2820. qname = m_valuesOrPrefixes.indexToString(prefixIndex);
  2821. int colonIndex = qname.indexOf(':');
  2822. if (colonIndex > 0) {
  2823. prefix = qname.substring(0, colonIndex);
  2824. }
  2825. }
  2826. handler.namespaceAfterStartElement(prefix, uri);
  2827. }
  2828. String nodeName = (prefix != null) ? qname : localName;
  2829. String nodeValue = (String)m_values.elementAt(valueIndex);
  2830. handler.addAttribute(nodeName, nodeValue);
  2831. }
  2832. }