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: CurrentNodeListIterator.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.AbstractTranslet;
025 import org.apache.xalan.xsltc.runtime.BasisLibrary;
026 import org.apache.xalan.xsltc.util.IntegerArray;
027 import org.apache.xml.dtm.DTMAxisIterator;
028 import org.apache.xml.dtm.ref.DTMAxisIteratorBase;
029
030 /**
031 * Iterators of this kind use a CurrentNodeListFilter to filter a subset of
032 * nodes from a source iterator. For each node from the source, the boolean
033 * method CurrentNodeListFilter.test() is called.
034 *
035 * All nodes from the source are read into an array upon calling setStartNode()
036 * (this is needed to determine the value of last, a parameter to
037 * CurrentNodeListFilter.test()). The method getLast() returns the last element
038 * after applying the filter.
039 * @author Jacek Ambroziak
040 * @author Santiago Pericas-Geertsen
041 * @author Morten Jorgensen
042 */
043
044 public final class CurrentNodeListIterator extends DTMAxisIteratorBase {
045 /**
046 * A flag indicating if nodes are returned in document order.
047 */
048 private boolean _docOrder;
049
050 /**
051 * The source for this iterator.
052 */
053 private DTMAxisIterator _source;
054
055 /**
056 * A reference to a filter object.
057 */
058 private final CurrentNodeListFilter _filter;
059
060 /**
061 * An integer array to store nodes from source iterator.
062 */
063 private IntegerArray _nodes = new IntegerArray();
064
065 /**
066 * Index in _nodes of the next node to filter.
067 */
068 private int _currentIndex;
069
070 /**
071 * The current node in the stylesheet at the time of evaluation.
072 */
073 private final int _currentNode;
074
075 /**
076 * A reference to the translet.
077 */
078 private AbstractTranslet _translet;
079
080 public CurrentNodeListIterator(DTMAxisIterator source,
081 CurrentNodeListFilter filter,
082 int currentNode,
083 AbstractTranslet translet)
084 {
085 this(source, !source.isReverse(), filter, currentNode, translet);
086 }
087
088 public CurrentNodeListIterator(DTMAxisIterator source, boolean docOrder,
089 CurrentNodeListFilter filter,
090 int currentNode,
091 AbstractTranslet translet)
092 {
093 _source = source;
094 _filter = filter;
095 _translet = translet;
096 _docOrder = docOrder;
097 _currentNode = currentNode;
098 }
099
100 public DTMAxisIterator forceNaturalOrder() {
101 _docOrder = true;
102 return this;
103 }
104
105 public void setRestartable(boolean isRestartable) {
106 _isRestartable = isRestartable;
107 _source.setRestartable(isRestartable);
108 }
109
110 public boolean isReverse() {
111 return !_docOrder;
112 }
113
114 public DTMAxisIterator cloneIterator() {
115 try {
116 final CurrentNodeListIterator clone =
117 (CurrentNodeListIterator) super.clone();
118 clone._nodes = (IntegerArray) _nodes.clone();
119 clone._source = _source.cloneIterator();
120 clone._isRestartable = false;
121 return clone.reset();
122 }
123 catch (CloneNotSupportedException e) {
124 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR,
125 e.toString());
126 return null;
127 }
128 }
129
130 public DTMAxisIterator reset() {
131 _currentIndex = 0;
132 return resetPosition();
133 }
134
135 public int next() {
136 final int last = _nodes.cardinality();
137 final int currentNode = _currentNode;
138 final AbstractTranslet translet = _translet;
139
140 for (int index = _currentIndex; index < last; ) {
141 final int position = _docOrder ? index + 1 : last - index;
142 final int node = _nodes.at(index++); // note increment
143
144 if (_filter.test(node, position, last, currentNode, translet,
145 this)) {
146 _currentIndex = index;
147 return returnNode(node);
148 }
149 }
150 return END;
151 }
152
153 public DTMAxisIterator setStartNode(int node) {
154 if (_isRestartable) {
155 _source.setStartNode(_startNode = node);
156
157 _nodes.clear();
158 while ((node = _source.next()) != END) {
159 _nodes.add(node);
160 }
161 _currentIndex = 0;
162 resetPosition();
163 }
164 return this;
165 }
166
167 public int getLast() {
168 if (_last == -1) {
169 _last = computePositionOfLast();
170 }
171 return _last;
172 }
173
174 public void setMark() {
175 _markedNode = _currentIndex;
176 }
177
178 public void gotoMark() {
179 _currentIndex = _markedNode;
180 }
181
182 private int computePositionOfLast() {
183 final int last = _nodes.cardinality();
184 final int currNode = _currentNode;
185 final AbstractTranslet translet = _translet;
186
187 int lastPosition = _position;
188 for (int index = _currentIndex; index < last; ) {
189 final int position = _docOrder ? index + 1 : last - index;
190 int nodeIndex = _nodes.at(index++); // note increment
191
192 if (_filter.test(nodeIndex, position, last, currNode, translet,
193 this)) {
194 lastPosition++;
195 }
196 }
197 return lastPosition;
198 }
199 }