1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xalan.internal.xsltc.dom; 23 24 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary; 25 import com.sun.org.apache.xalan.internal.xsltc.util.IntegerArray; 26 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 27 import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase; 28 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; 29 30 /** 31 * Removes duplicates and sorts a source iterator. The nodes from the 32 * source are collected in an array upon calling setStartNode(). This 33 * array is later sorted and duplicates are ignored in next(). 34 * @author G. Todd Miller 35 */ 36 public final class DupFilterIterator extends DTMAxisIteratorBase { 37 38 /** 39 * Reference to source iterator. 40 */ 41 private DTMAxisIterator _source; 42 43 /** 44 * Array to cache all nodes from source. 45 */ 46 private IntegerArray _nodes = new IntegerArray(); 47 48 /** 49 * Index in _nodes array to current node. 50 */ 51 private int _current = 0; 52 53 /** 54 * Cardinality of _nodes array. 55 */ 56 private int _nodesSize = 0; 57 58 /** 59 * Last value returned by next(). 60 */ 61 private int _lastNext = END; 62 63 /** 64 * Temporary variable to store _lastNext. 65 */ 66 private int _markedLastNext = END; 67 DupFilterIterator(DTMAxisIterator source)68 public DupFilterIterator(DTMAxisIterator source) { 69 _source = source; 70 // System.out.println("DFI source = " + source + " this = " + this); 71 72 // Cache contents of id() or key() index right away. Necessary for 73 // union expressions containing multiple calls to the same index, and 74 // correct as well since start-node is irrelevant for id()/key() exrp. 75 if (source instanceof KeyIndex) { 76 setStartNode(DTMDefaultBase.ROOTNODE); 77 } 78 } 79 80 /** 81 * Set the start node for this iterator 82 * @param node The start node 83 * @return A reference to this node iterator 84 */ setStartNode(int node)85 public DTMAxisIterator setStartNode(int node) { 86 if (_isRestartable) { 87 // KeyIndex iterators are always relative to the root node, so there 88 // is never any point in re-reading the iterator (and we SHOULD NOT). 89 boolean sourceIsKeyIndex = _source instanceof KeyIndex; 90 91 if (sourceIsKeyIndex 92 && _startNode == DTMDefaultBase.ROOTNODE) { 93 return this; 94 } 95 96 if (node != _startNode) { 97 _source.setStartNode(_startNode = node); 98 99 _nodes.clear(); 100 while ((node = _source.next()) != END) { 101 _nodes.add(node); 102 } 103 104 // Nodes produced by KeyIndex are known to be in document order. 105 // Take advantage of it. 106 if (!sourceIsKeyIndex) { 107 _nodes.sort(); 108 } 109 _nodesSize = _nodes.cardinality(); 110 _current = 0; 111 _lastNext = END; 112 resetPosition(); 113 } 114 } 115 return this; 116 } 117 next()118 public int next() { 119 while (_current < _nodesSize) { 120 final int next = _nodes.at(_current++); 121 if (next != _lastNext) { 122 return returnNode(_lastNext = next); 123 } 124 } 125 return END; 126 } 127 cloneIterator()128 public DTMAxisIterator cloneIterator() { 129 try { 130 final DupFilterIterator clone = 131 (DupFilterIterator) super.clone(); 132 clone._nodes = (IntegerArray) _nodes.clone(); 133 clone._source = _source.cloneIterator(); 134 clone._isRestartable = false; 135 return clone.reset(); 136 } 137 catch (CloneNotSupportedException e) { 138 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 139 e.toString()); 140 return null; 141 } 142 } 143 setRestartable(boolean isRestartable)144 public void setRestartable(boolean isRestartable) { 145 _isRestartable = isRestartable; 146 _source.setRestartable(isRestartable); 147 } 148 setMark()149 public void setMark() { 150 _markedNode = _current; 151 _markedLastNext = _lastNext; // Bugzilla 25924 152 } 153 gotoMark()154 public void gotoMark() { 155 _current = _markedNode; 156 _lastNext = _markedLastNext; // Bugzilla 25924 157 } 158 reset()159 public DTMAxisIterator reset() { 160 _current = 0; 161 _lastNext = END; 162 return resetPosition(); 163 } 164 } 165