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: WalkingIteratorSorted.java 468655 2006-10-28 07:12:06Z minchau $
020     */
021    package org.apache.xpath.axes;
022    
023    import org.apache.xml.dtm.Axis;
024    import org.apache.xml.utils.PrefixResolver;
025    import org.apache.xpath.compiler.Compiler;
026    
027    /**
028     * This class iterates over set of nodes that needs to be sorted.
029     * @xsl.usage internal
030     */
031    public class WalkingIteratorSorted extends WalkingIterator
032    {
033        static final long serialVersionUID = -4512512007542368213L;
034    
035    //  /** True if the nodes will be found in document order */
036    //  protected boolean m_inNaturalOrder = false;
037      
038      /** True if the nodes will be found in document order, and this can 
039       * be determined statically. */
040      protected boolean m_inNaturalOrderStatic = false;
041    
042      /**
043       * Create a WalkingIteratorSorted object.
044       *
045       * @param nscontext The namespace context for this iterator,
046       * should be OK if null.
047       */
048      public WalkingIteratorSorted(PrefixResolver nscontext)
049      {
050        super(nscontext);
051      }
052    
053      /**
054       * Create a WalkingIterator iterator, including creation
055       * of step walkers from the opcode list, and call back
056       * into the Compiler to create predicate expressions.
057       *
058       * @param compiler The Compiler which is creating
059       * this expression.
060       * @param opPos The position of this iterator in the
061       * opcode list from the compiler.
062       * @param shouldLoadWalkers True if walkers should be
063       * loaded, or false if this is a derived iterator and
064       * it doesn't wish to load child walkers.
065       *
066       * @throws javax.xml.transform.TransformerException
067       */
068      WalkingIteratorSorted(
069              Compiler compiler, int opPos, int analysis, boolean shouldLoadWalkers)
070                throws javax.xml.transform.TransformerException
071      {
072        super(compiler, opPos, analysis, shouldLoadWalkers);
073      }
074      
075      /**
076       * Returns true if all the nodes in the iteration well be returned in document 
077       * order.
078       * 
079       * @return true as a default.
080       */
081      public boolean isDocOrdered()
082      {
083        return m_inNaturalOrderStatic;
084      }
085    
086        
087      /**
088       * Tell if the nodeset can be walked in doc order, via static analysis. 
089       *
090       *
091       * @return true if the nodeset can be walked in doc order, without sorting.
092       */
093      boolean canBeWalkedInNaturalDocOrderStatic()
094      {
095    
096        if (null != m_firstWalker)
097        {
098          AxesWalker walker = m_firstWalker;
099          int prevAxis = -1;
100          boolean prevIsSimpleDownAxis = true;
101    
102          for(int i = 0; null != walker; i++)
103          {
104            int axis = walker.getAxis();
105            
106            if(walker.isDocOrdered())
107            {
108              boolean isSimpleDownAxis = ((axis == Axis.CHILD)
109                                       || (axis == Axis.SELF)
110                                       || (axis == Axis.ROOT));
111              // Catching the filtered list here is only OK because
112              // FilterExprWalker#isDocOrdered() did the right thing.
113              if(isSimpleDownAxis || (axis == -1))
114                walker = walker.getNextWalker();
115              else
116              {
117                boolean isLastWalker = (null == walker.getNextWalker());
118                if(isLastWalker)
119                {
120                  if(walker.isDocOrdered() && (axis == Axis.DESCENDANT || 
121                     axis == Axis.DESCENDANTORSELF || axis == Axis.DESCENDANTSFROMROOT
122                     || axis == Axis.DESCENDANTSORSELFFROMROOT) || (axis == Axis.ATTRIBUTE))
123                    return true;
124                }
125                return false;
126              }
127            }
128            else
129              return false;
130          }
131          return true;
132        }
133        return false;
134      }
135    
136    
137    //  /**
138    //   * NEEDSDOC Method canBeWalkedInNaturalDocOrder 
139    //   *
140    //   *
141    //   * NEEDSDOC (canBeWalkedInNaturalDocOrder) @return
142    //   */
143    //  boolean canBeWalkedInNaturalDocOrder()
144    //  {
145    //
146    //    if (null != m_firstWalker)
147    //    {
148    //      AxesWalker walker = m_firstWalker;
149    //      int prevAxis = -1;
150    //      boolean prevIsSimpleDownAxis = true;
151    //
152    //      for(int i = 0; null != walker; i++)
153    //      {
154    //        int axis = walker.getAxis();
155    //        
156    //        if(walker.isDocOrdered())
157    //        {
158    //          boolean isSimpleDownAxis = ((axis == Axis.CHILD)
159    //                                   || (axis == Axis.SELF)
160    //                                   || (axis == Axis.ROOT));
161    //          // Catching the filtered list here is only OK because
162    //          // FilterExprWalker#isDocOrdered() did the right thing.
163    //          if(isSimpleDownAxis || (axis == -1))
164    //            walker = walker.getNextWalker();
165    //          else
166    //          {
167    //            boolean isLastWalker = (null == walker.getNextWalker());
168    //            if(isLastWalker)
169    //            {
170    //              if(walker.isDocOrdered() && (axis == Axis.DESCENDANT || 
171    //                 axis == Axis.DESCENDANTORSELF || axis == Axis.DESCENDANTSFROMROOT
172    //                 || axis == Axis.DESCENDANTSORSELFFROMROOT) || (axis == Axis.ATTRIBUTE))
173    //                return true;
174    //            }
175    //            return false;
176    //          }
177    //        }
178    //        else
179    //          return false;
180    //      }
181    //      return true;
182    //    }
183    //    return false;
184    //  }
185      
186      /**
187       * This function is used to perform some extra analysis of the iterator.
188       * 
189       * @param vars List of QNames that correspond to variables.  This list 
190       * should be searched backwards for the first qualified name that 
191       * corresponds to the variable reference qname.  The position of the 
192       * QName in the vector from the start of the vector will be its position 
193       * in the stack frame (but variables above the globalsTop value will need 
194       * to be offset to the current stack frame).
195       */
196      public void fixupVariables(java.util.Vector vars, int globalsSize)
197      {
198        super.fixupVariables(vars, globalsSize);
199    
200        int analysis = getAnalysisBits();
201        if(WalkerFactory.isNaturalDocOrder(analysis))
202        {
203            m_inNaturalOrderStatic = true;
204        }
205        else
206        {
207            m_inNaturalOrderStatic = false;
208            // System.out.println("Setting natural doc order to false: "+
209            //    WalkerFactory.getAnalysisString(analysis));
210        }
211        
212      }
213    
214    }