1. /*
  2. * Copyright 2001-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: DupFilterIterator.java,v 1.13 2004/02/16 22:54:59 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.xsltc.dom;
  20. import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
  21. import com.sun.org.apache.xalan.internal.xsltc.util.IntegerArray;
  22. import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
  23. import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase;
  24. import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
  25. /**
  26. * Removes duplicates and sorts a source iterator. The nodes from the
  27. * source are collected in an array upon calling setStartNode(). This
  28. * array is later sorted and duplicates are ignored in next().
  29. * @author G. Todd Miller
  30. */
  31. public final class DupFilterIterator extends DTMAxisIteratorBase {
  32. /**
  33. * Reference to source iterator.
  34. */
  35. private DTMAxisIterator _source;
  36. /**
  37. * Array to cache all nodes from source.
  38. */
  39. private IntegerArray _nodes = new IntegerArray();
  40. /**
  41. * Index in _nodes array to current node.
  42. */
  43. private int _current = 0;
  44. /**
  45. * Cardinality of _nodes array.
  46. */
  47. private int _nodesSize = 0;
  48. /**
  49. * Last value returned by next().
  50. */
  51. private int _lastNext = END;
  52. /**
  53. * Temporary variable to store _lastNext.
  54. */
  55. private int _markedLastNext = END;
  56. public DupFilterIterator(DTMAxisIterator source) {
  57. _source = source;
  58. // System.out.println("DFI source = " + source + " this = " + this);
  59. // Cache contents of id() or key() index right away. Necessary for
  60. // union expressions containing multiple calls to the same index, and
  61. // correct as well since start-node is irrelevant for id()/key() exrp.
  62. if (source instanceof KeyIndex) {
  63. setStartNode(DTMDefaultBase.ROOTNODE);
  64. }
  65. }
  66. /**
  67. * Set the start node for this iterator
  68. * @param node The start node
  69. * @return A reference to this node iterator
  70. */
  71. public DTMAxisIterator setStartNode(int node) {
  72. if (_isRestartable) {
  73. // KeyIndex iterators are always relative to the root node, so there
  74. // is never any point in re-reading the iterator (and we SHOULD NOT).
  75. if (_source instanceof KeyIndex
  76. && _startNode == DTMDefaultBase.ROOTNODE) {
  77. return this;
  78. }
  79. if (node != _startNode) {
  80. _source.setStartNode(_startNode = node);
  81. _nodes.clear();
  82. while ((node = _source.next()) != END) {
  83. _nodes.add(node);
  84. }
  85. _nodes.sort();
  86. _nodesSize = _nodes.cardinality();
  87. _current = 0;
  88. _lastNext = END;
  89. resetPosition();
  90. }
  91. }
  92. return this;
  93. }
  94. public int next() {
  95. while (_current < _nodesSize) {
  96. final int next = _nodes.at(_current++);
  97. if (next != _lastNext) {
  98. return returnNode(_lastNext = next);
  99. }
  100. }
  101. return END;
  102. }
  103. public DTMAxisIterator cloneIterator() {
  104. try {
  105. final DupFilterIterator clone =
  106. (DupFilterIterator) super.clone();
  107. clone._nodes = (IntegerArray) _nodes.clone();
  108. clone._source = _source.cloneIterator();
  109. clone._isRestartable = false;
  110. return clone.reset();
  111. }
  112. catch (CloneNotSupportedException e) {
  113. BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
  114. e.toString());
  115. return null;
  116. }
  117. }
  118. public void setRestartable(boolean isRestartable) {
  119. _isRestartable = isRestartable;
  120. _source.setRestartable(isRestartable);
  121. }
  122. public void setMark() {
  123. _markedNode = _current;
  124. _markedLastNext = _lastNext; // Bugzilla 25924
  125. }
  126. public void gotoMark() {
  127. _current = _markedNode;
  128. _lastNext = _markedLastNext; // Bugzilla 25924
  129. }
  130. public DTMAxisIterator reset() {
  131. _current = 0;
  132. _lastNext = END;
  133. return resetPosition();
  134. }
  135. }