Home | History | Annotate | Download | only in axes
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id: ReverseAxesWalker.java 513117 2007-03-01 03:28:52Z minchau $
     20  */
     21 package org.apache.xpath.axes;
     22 
     23 import org.apache.xml.dtm.DTM;
     24 import org.apache.xml.dtm.DTMAxisIterator;
     25 import org.apache.xpath.XPathContext;
     26 
     27 /**
     28  * Walker for a reverse axes.
     29  * @see <a href="http://www.w3.org/TR/xpath#predicates">XPath 2.4 Predicates</a>
     30  */
     31 public class ReverseAxesWalker extends AxesWalker
     32 {
     33     static final long serialVersionUID = 2847007647832768941L;
     34 
     35   /**
     36    * Construct an AxesWalker using a LocPathIterator.
     37    *
     38    * @param locPathIterator The location path iterator that 'owns' this walker.
     39    */
     40   ReverseAxesWalker(LocPathIterator locPathIterator, int axis)
     41   {
     42     super(locPathIterator, axis);
     43   }
     44 
     45   /**
     46    * Set the root node of the TreeWalker.
     47    * (Not part of the DOM2 TreeWalker interface).
     48    *
     49    * @param root The context node of this step.
     50    */
     51   public void setRoot(int root)
     52   {
     53     super.setRoot(root);
     54     m_iterator = getDTM(root).getAxisIterator(m_axis);
     55     m_iterator.setStartNode(root);
     56   }
     57 
     58   /**
     59    * Detaches the walker from the set which it iterated over, releasing
     60    * any computational resources and placing the iterator in the INVALID
     61    * state.
     62    */
     63   public void detach()
     64   {
     65     m_iterator = null;
     66     super.detach();
     67   }
     68 
     69   /**
     70    * Get the next node in document order on the axes.
     71    *
     72    * @return the next node in document order on the axes, or null.
     73    */
     74   protected int getNextNode()
     75   {
     76     if (m_foundLast)
     77       return DTM.NULL;
     78 
     79     int next = m_iterator.next();
     80 
     81     if (m_isFresh)
     82       m_isFresh = false;
     83 
     84     if (DTM.NULL == next)
     85       this.m_foundLast = true;
     86 
     87     return next;
     88   }
     89 
     90 
     91   /**
     92    * Tells if this is a reverse axes.  Overrides AxesWalker#isReverseAxes.
     93    *
     94    * @return true for this class.
     95    */
     96   public boolean isReverseAxes()
     97   {
     98     return true;
     99   }
    100 
    101 //  /**
    102 //   *  Set the root node of the TreeWalker.
    103 //   *
    104 //   * @param root The context node of this step.
    105 //   */
    106 //  public void setRoot(int root)
    107 //  {
    108 //    super.setRoot(root);
    109 //  }
    110 
    111   /**
    112    * Get the current sub-context position.  In order to do the
    113    * reverse axes count, for the moment this re-searches the axes
    114    * up to the predicate.  An optimization on this is to cache
    115    * the nodes searched, but, for the moment, this case is probably
    116    * rare enough that the added complexity isn't worth it.
    117    *
    118    * @param predicateIndex The predicate index of the proximity position.
    119    *
    120    * @return The pridicate index, or -1.
    121    */
    122   protected int getProximityPosition(int predicateIndex)
    123   {
    124     // A negative predicate index seems to occur with
    125     // (preceding-sibling::*|following-sibling::*)/ancestor::*[position()]/*[position()]
    126     // -sb
    127     if(predicateIndex < 0)
    128       return -1;
    129 
    130     int count = m_proximityPositions[predicateIndex];
    131 
    132     if (count <= 0)
    133     {
    134       AxesWalker savedWalker = wi().getLastUsedWalker();
    135 
    136       try
    137       {
    138         ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
    139 
    140         clone.setRoot(this.getRoot());
    141 
    142         clone.setPredicateCount(predicateIndex);
    143 
    144         clone.setPrevWalker(null);
    145         clone.setNextWalker(null);
    146         wi().setLastUsedWalker(clone);
    147 
    148         // Count 'em all
    149         count++;
    150         int next;
    151 
    152         while (DTM.NULL != (next = clone.nextNode()))
    153         {
    154           count++;
    155         }
    156 
    157         m_proximityPositions[predicateIndex] = count;
    158       }
    159       catch (CloneNotSupportedException cnse)
    160       {
    161 
    162         // can't happen
    163       }
    164       finally
    165       {
    166         wi().setLastUsedWalker(savedWalker);
    167       }
    168     }
    169 
    170     return count;
    171   }
    172 
    173   /**
    174    * Count backwards one proximity position.
    175    *
    176    * @param i The predicate index.
    177    */
    178   protected void countProximityPosition(int i)
    179   {
    180     if (i < m_proximityPositions.length)
    181       m_proximityPositions[i]--;
    182   }
    183 
    184   /**
    185    * Get the number of nodes in this node list.  The function is probably ill
    186    * named?
    187    *
    188    *
    189    * @param xctxt The XPath runtime context.
    190    *
    191    * @return the number of nodes in this node list.
    192    */
    193   public int getLastPos(XPathContext xctxt)
    194   {
    195 
    196     int count = 0;
    197     AxesWalker savedWalker = wi().getLastUsedWalker();
    198 
    199     try
    200     {
    201       ReverseAxesWalker clone = (ReverseAxesWalker) this.clone();
    202 
    203       clone.setRoot(this.getRoot());
    204 
    205       clone.setPredicateCount(m_predicateIndex);
    206 
    207       clone.setPrevWalker(null);
    208       clone.setNextWalker(null);
    209       wi().setLastUsedWalker(clone);
    210 
    211       // Count 'em all
    212       // count = 1;
    213       int next;
    214 
    215       while (DTM.NULL != (next = clone.nextNode()))
    216       {
    217         count++;
    218       }
    219     }
    220     catch (CloneNotSupportedException cnse)
    221     {
    222 
    223       // can't happen
    224     }
    225     finally
    226     {
    227       wi().setLastUsedWalker(savedWalker);
    228     }
    229 
    230     return count;
    231   }
    232 
    233   /**
    234    * Returns true if all the nodes in the iteration well be returned in document
    235    * order.
    236    * Warning: This can only be called after setRoot has been called!
    237    *
    238    * @return false.
    239    */
    240   public boolean isDocOrdered()
    241   {
    242     return false;  // I think.
    243   }
    244 
    245   /** The DTM inner traversal class, that corresponds to the super axis. */
    246   protected DTMAxisIterator m_iterator;
    247 }
    248