001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: DupFilterIterator.java 468651 2006-10-28 07:04:25Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.dom; 023 024 import org.apache.xalan.xsltc.runtime.BasisLibrary; 025 import org.apache.xalan.xsltc.util.IntegerArray; 026 import org.apache.xml.dtm.DTMAxisIterator; 027 import org.apache.xml.dtm.ref.DTMAxisIteratorBase; 028 import org.apache.xml.dtm.ref.DTMDefaultBase; 029 030 /** 031 * Removes duplicates and sorts a source iterator. The nodes from the 032 * source are collected in an array upon calling setStartNode(). This 033 * array is later sorted and duplicates are ignored in next(). 034 * @author G. Todd Miller 035 */ 036 public final class DupFilterIterator extends DTMAxisIteratorBase { 037 038 /** 039 * Reference to source iterator. 040 */ 041 private DTMAxisIterator _source; 042 043 /** 044 * Array to cache all nodes from source. 045 */ 046 private IntegerArray _nodes = new IntegerArray(); 047 048 /** 049 * Index in _nodes array to current node. 050 */ 051 private int _current = 0; 052 053 /** 054 * Cardinality of _nodes array. 055 */ 056 private int _nodesSize = 0; 057 058 /** 059 * Last value returned by next(). 060 */ 061 private int _lastNext = END; 062 063 /** 064 * Temporary variable to store _lastNext. 065 */ 066 private int _markedLastNext = END; 067 068 public DupFilterIterator(DTMAxisIterator source) { 069 _source = source; 070 // System.out.println("DFI source = " + source + " this = " + this); 071 072 // Cache contents of id() or key() index right away. Necessary for 073 // union expressions containing multiple calls to the same index, and 074 // correct as well since start-node is irrelevant for id()/key() exrp. 075 if (source instanceof KeyIndex) { 076 setStartNode(DTMDefaultBase.ROOTNODE); 077 } 078 } 079 080 /** 081 * Set the start node for this iterator 082 * @param node The start node 083 * @return A reference to this node iterator 084 */ 085 public DTMAxisIterator setStartNode(int node) { 086 if (_isRestartable) { 087 // KeyIndex iterators are always relative to the root node, so there 088 // is never any point in re-reading the iterator (and we SHOULD NOT). 089 boolean sourceIsKeyIndex = _source instanceof KeyIndex; 090 091 if (sourceIsKeyIndex 092 && _startNode == DTMDefaultBase.ROOTNODE) { 093 return this; 094 } 095 096 if (node != _startNode) { 097 _source.setStartNode(_startNode = node); 098 099 _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 110 _nodesSize = _nodes.cardinality(); 111 _current = 0; 112 _lastNext = END; 113 resetPosition(); 114 } 115 } 116 return this; 117 } 118 119 public int next() { 120 while (_current < _nodesSize) { 121 final int next = _nodes.at(_current++); 122 if (next != _lastNext) { 123 return returnNode(_lastNext = next); 124 } 125 } 126 return END; 127 } 128 129 public DTMAxisIterator cloneIterator() { 130 try { 131 final DupFilterIterator clone = 132 (DupFilterIterator) super.clone(); 133 clone._nodes = (IntegerArray) _nodes.clone(); 134 clone._source = _source.cloneIterator(); 135 clone._isRestartable = false; 136 return clone.reset(); 137 } 138 catch (CloneNotSupportedException e) { 139 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 140 e.toString()); 141 return null; 142 } 143 } 144 145 public void setRestartable(boolean isRestartable) { 146 _isRestartable = isRestartable; 147 _source.setRestartable(isRestartable); 148 } 149 150 public void setMark() { 151 _markedNode = _current; 152 _markedLastNext = _lastNext; // Bugzilla 25924 153 } 154 155 public void gotoMark() { 156 _current = _markedNode; 157 _lastNext = _markedLastNext; // Bugzilla 25924 158 } 159 160 public DTMAxisIterator reset() { 161 _current = 0; 162 _lastNext = END; 163 return resetPosition(); 164 } 165 }