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: BasicTestIterator.java 469314 2006-10-30 23:31:59Z minchau $
020     */
021    package org.apache.xpath.axes;
022    
023    import org.apache.xml.dtm.DTM;
024    import org.apache.xml.dtm.DTMFilter;
025    import org.apache.xml.dtm.DTMIterator;
026    import org.apache.xml.utils.PrefixResolver;
027    import org.apache.xpath.compiler.Compiler;
028    import org.apache.xpath.compiler.OpMap;
029    
030    /**
031     * Base for iterators that handle predicates.  Does the basic next 
032     * node logic, so all the derived iterator has to do is get the 
033     * next node.
034     */
035    public abstract class BasicTestIterator extends LocPathIterator
036    {
037        static final long serialVersionUID = 3505378079378096623L;
038      /**
039       * Create a LocPathIterator object.
040       *
041       * @param nscontext The namespace context for this iterator,
042       * should be OK if null.
043       */
044      protected BasicTestIterator()
045      {
046      }
047    
048    
049      /**
050       * Create a LocPathIterator object.
051       *
052       * @param nscontext The namespace context for this iterator,
053       * should be OK if null.
054       */
055      protected BasicTestIterator(PrefixResolver nscontext)
056      {
057    
058        super(nscontext);
059      }
060    
061      /**
062       * Create a LocPathIterator object, including creation
063       * of step walkers from the opcode list, and call back
064       * into the Compiler to create predicate expressions.
065       *
066       * @param compiler The Compiler which is creating
067       * this expression.
068       * @param opPos The position of this iterator in the
069       * opcode list from the compiler.
070       *
071       * @throws javax.xml.transform.TransformerException
072       */
073      protected BasicTestIterator(Compiler compiler, int opPos, int analysis)
074              throws javax.xml.transform.TransformerException
075      {
076        super(compiler, opPos, analysis, false);
077        
078        int firstStepPos = OpMap.getFirstChildPos(opPos);
079        int whatToShow = compiler.getWhatToShow(firstStepPos);
080    
081        if ((0 == (whatToShow
082                   & (DTMFilter.SHOW_ATTRIBUTE 
083                   | DTMFilter.SHOW_NAMESPACE 
084                   | DTMFilter.SHOW_ELEMENT
085                   | DTMFilter.SHOW_PROCESSING_INSTRUCTION))) 
086                   || (whatToShow == DTMFilter.SHOW_ALL))
087          initNodeTest(whatToShow);
088        else
089        {
090          initNodeTest(whatToShow, compiler.getStepNS(firstStepPos),
091                                  compiler.getStepLocalName(firstStepPos));
092        }
093        initPredicateInfo(compiler, firstStepPos);
094      }
095    
096      /**
097       * Create a LocPathIterator object, including creation
098       * of step walkers from the opcode list, and call back
099       * into the Compiler to create predicate expressions.
100       *
101       * @param compiler The Compiler which is creating
102       * this expression.
103       * @param opPos The position of this iterator in the
104       * opcode list from the compiler.
105       * @param shouldLoadWalkers True if walkers should be
106       * loaded, or false if this is a derived iterator and
107       * it doesn't wish to load child walkers.
108       *
109       * @throws javax.xml.transform.TransformerException
110       */
111      protected BasicTestIterator(
112              Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
113                throws javax.xml.transform.TransformerException
114      {
115        super(compiler, opPos, analysis, shouldLoadWalkers);
116      }
117    
118            
119      /**
120       * Get the next node via getNextXXX.  Bottlenecked for derived class override.
121       * @return The next node on the axis, or DTM.NULL.
122       */
123      protected abstract int getNextNode();
124    
125      /**
126       *  Returns the next node in the set and advances the position of the
127       * iterator in the set. After a NodeIterator is created, the first call
128       * to nextNode() returns the first node in the set.
129       *
130       * @return  The next <code>Node</code> in the set being iterated over, or
131       *   <code>null</code> if there are no more members in that set.
132       */
133      public int nextNode()
134      {      
135            if(m_foundLast)
136            {
137                    m_lastFetched = DTM.NULL;
138                    return DTM.NULL;
139            }
140                    
141        if(DTM.NULL == m_lastFetched)
142        {
143          resetProximityPositions();
144        }
145    
146        int next;
147        
148        org.apache.xpath.VariableStack vars;
149        int savedStart;
150        if (-1 != m_stackFrame)
151        {
152          vars = m_execContext.getVarStack();
153    
154          // These three statements need to be combined into one operation.
155          savedStart = vars.getStackFrame();
156    
157          vars.setStackFrame(m_stackFrame);
158        }
159        else
160        {
161          // Yuck.  Just to shut up the compiler!
162          vars = null;
163          savedStart = 0;
164        }
165        
166        try
167        {
168          do
169          {
170            next = getNextNode();
171      
172            if (DTM.NULL != next)
173            {
174              if(DTMIterator.FILTER_ACCEPT == acceptNode(next))
175                break;
176              else
177                continue;
178            }
179            else
180              break;
181          }
182          while (next != DTM.NULL);
183      
184          if (DTM.NULL != next)
185          {
186            m_pos++;
187            return next;
188          }
189          else
190          {
191            m_foundLast = true;
192      
193            return DTM.NULL;
194          }
195        }
196        finally
197        {
198          if (-1 != m_stackFrame)
199          {
200            // These two statements need to be combined into one operation.
201            vars.setStackFrame(savedStart);
202          }
203        }
204      }
205      
206      /**
207       *  Get a cloned Iterator that is reset to the beginning
208       *  of the query.
209       * 
210       *  @return A cloned NodeIterator set of the start of the query.
211       * 
212       *  @throws CloneNotSupportedException
213       */
214      public DTMIterator cloneWithReset() throws CloneNotSupportedException
215      {
216    
217        ChildTestIterator clone = (ChildTestIterator) super.cloneWithReset();
218    
219        clone.resetProximityPositions();
220    
221        return clone;
222      }
223    
224    
225    }
226