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: FilterExprWalker.java 469367 2006-10-31 04:41:08Z minchau $
     20  */
     21 package org.apache.xpath.axes;
     22 
     23 import org.apache.xml.dtm.Axis;
     24 import org.apache.xml.dtm.DTM;
     25 import org.apache.xml.dtm.DTMIterator;
     26 import org.apache.xpath.Expression;
     27 import org.apache.xpath.ExpressionOwner;
     28 import org.apache.xpath.XPathContext;
     29 import org.apache.xpath.XPathVisitor;
     30 import org.apache.xpath.compiler.Compiler;
     31 import org.apache.xpath.compiler.OpCodes;
     32 import org.apache.xpath.objects.XNodeSet;
     33 
     34 /**
     35  * Walker for the OP_VARIABLE, or OP_EXTFUNCTION, or OP_FUNCTION, or OP_GROUP,
     36  * op codes.
     37  * @see <a href="http://www.w3.org/TR/xpath#NT-FilterExpr">XPath FilterExpr descriptions</a>
     38  */
     39 public class FilterExprWalker extends AxesWalker
     40 {
     41     static final long serialVersionUID = 5457182471424488375L;
     42 
     43   /**
     44    * Construct a FilterExprWalker using a LocPathIterator.
     45    *
     46    * @param locPathIterator non-null reference to the parent iterator.
     47    */
     48   public FilterExprWalker(WalkingIterator locPathIterator)
     49   {
     50     super(locPathIterator, Axis.FILTEREDLIST);
     51   }
     52 
     53   /**
     54    * Init a FilterExprWalker.
     55    *
     56    * @param compiler non-null reference to the Compiler that is constructing.
     57    * @param opPos positive opcode position for this step.
     58    * @param stepType The type of step.
     59    *
     60    * @throws javax.xml.transform.TransformerException
     61    */
     62   public void init(Compiler compiler, int opPos, int stepType)
     63           throws javax.xml.transform.TransformerException
     64   {
     65 
     66     super.init(compiler, opPos, stepType);
     67 
     68     // Smooth over an anomily in the opcode map...
     69     switch (stepType)
     70     {
     71     case OpCodes.OP_FUNCTION :
     72     case OpCodes.OP_EXTFUNCTION :
     73     	m_mustHardReset = true;
     74     case OpCodes.OP_GROUP :
     75     case OpCodes.OP_VARIABLE :
     76       m_expr = compiler.compile(opPos);
     77       m_expr.exprSetParent(this);
     78       //if((OpCodes.OP_FUNCTION == stepType) && (m_expr instanceof org.apache.xalan.templates.FuncKey))
     79       if(m_expr instanceof org.apache.xpath.operations.Variable)
     80       {
     81       	// hack/temp workaround
     82       	m_canDetachNodeset = false;
     83       }
     84       break;
     85     default :
     86       m_expr = compiler.compile(opPos + 2);
     87       m_expr.exprSetParent(this);
     88     }
     89 //    if(m_expr instanceof WalkingIterator)
     90 //    {
     91 //      WalkingIterator wi = (WalkingIterator)m_expr;
     92 //      if(wi.getFirstWalker() instanceof FilterExprWalker)
     93 //      {
     94 //      	FilterExprWalker fw = (FilterExprWalker)wi.getFirstWalker();
     95 //      	if(null == fw.getNextWalker())
     96 //      	{
     97 //      		m_expr = fw.m_expr;
     98 //      		m_expr.exprSetParent(this);
     99 //      	}
    100 //      }
    101 //
    102 //    }
    103   }
    104 
    105   /**
    106    * Detaches the walker from the set which it iterated over, releasing
    107    * any computational resources and placing the iterator in the INVALID
    108    * state.
    109    */
    110   public void detach()
    111   {
    112   	super.detach();
    113   	if (m_canDetachNodeset)
    114   	{
    115   	  m_exprObj.detach();
    116   	}
    117   	m_exprObj = null;
    118   }
    119 
    120   /**
    121    *  Set the root node of the TreeWalker.
    122    *
    123    * @param root non-null reference to the root, or starting point of
    124    *        the query.
    125    */
    126   public void setRoot(int root)
    127   {
    128 
    129     super.setRoot(root);
    130 
    131   	m_exprObj = FilterExprIteratorSimple.executeFilterExpr(root,
    132   	                  m_lpi.getXPathContext(), m_lpi.getPrefixResolver(),
    133   	                  m_lpi.getIsTopLevel(), m_lpi.m_stackFrame, m_expr);
    134 
    135   }
    136 
    137   /**
    138    * Get a cloned FilterExprWalker.
    139    *
    140    * @return A new FilterExprWalker that can be used without mutating this one.
    141    *
    142    * @throws CloneNotSupportedException
    143    */
    144   public Object clone() throws CloneNotSupportedException
    145   {
    146 
    147     FilterExprWalker clone = (FilterExprWalker) super.clone();
    148 
    149     if (null != m_exprObj)
    150       clone.m_exprObj = (XNodeSet) m_exprObj.clone();
    151 
    152     return clone;
    153   }
    154 
    155   /**
    156    * This method needs to override AxesWalker.acceptNode because FilterExprWalkers
    157    * don't need to, and shouldn't, do a node test.
    158    * @param n  The node to check to see if it passes the filter or not.
    159    * @return  a constant to determine whether the node is accepted,
    160    *   rejected, or skipped, as defined  above .
    161    */
    162   public short acceptNode(int n)
    163   {
    164 
    165     try
    166     {
    167       if (getPredicateCount() > 0)
    168       {
    169         countProximityPosition(0);
    170 
    171         if (!executePredicates(n, m_lpi.getXPathContext()))
    172           return DTMIterator.FILTER_SKIP;
    173       }
    174 
    175       return DTMIterator.FILTER_ACCEPT;
    176     }
    177     catch (javax.xml.transform.TransformerException se)
    178     {
    179       throw new RuntimeException(se.getMessage());
    180     }
    181   }
    182 
    183   /**
    184    *  Moves the <code>TreeWalker</code> to the next visible node in document
    185    * order relative to the current node, and returns the new node. If the
    186    * current node has no next node,  or if the search for nextNode attempts
    187    * to step upward from the TreeWalker's root node, returns
    188    * <code>null</code> , and retains the current node.
    189    * @return  The new node, or <code>null</code> if the current node has no
    190    *   next node  in the TreeWalker's logical view.
    191    */
    192   public int getNextNode()
    193   {
    194 
    195     if (null != m_exprObj)
    196     {
    197        int next = m_exprObj.nextNode();
    198        return next;
    199     }
    200     else
    201       return DTM.NULL;
    202   }
    203 
    204   /**
    205    * Get the index of the last node that can be itterated to.
    206    *
    207    *
    208    * @param xctxt XPath runtime context.
    209    *
    210    * @return the index of the last node that can be itterated to.
    211    */
    212   public int getLastPos(XPathContext xctxt)
    213   {
    214     return m_exprObj.getLength();
    215   }
    216 
    217   /** The contained expression. Should be non-null.
    218    *  @serial   */
    219   private Expression m_expr;
    220 
    221   /** The result of executing m_expr.  Needs to be deep cloned on clone op.  */
    222   transient private XNodeSet m_exprObj;
    223 
    224   private boolean m_mustHardReset = false;
    225   private boolean m_canDetachNodeset = true;
    226 
    227   /**
    228    * This function is used to fixup variables from QNames to stack frame
    229    * indexes at stylesheet build time.
    230    * @param vars List of QNames that correspond to variables.  This list
    231    * should be searched backwards for the first qualified name that
    232    * corresponds to the variable reference qname.  The position of the
    233    * QName in the vector from the start of the vector will be its position
    234    * in the stack frame (but variables above the globalsTop value will need
    235    * to be offset to the current stack frame).
    236    */
    237   public void fixupVariables(java.util.Vector vars, int globalsSize)
    238   {
    239     super.fixupVariables(vars, globalsSize);
    240     m_expr.fixupVariables(vars, globalsSize);
    241   }
    242 
    243   /**
    244    * Get the inner contained expression of this filter.
    245    */
    246   public Expression getInnerExpression()
    247   {
    248   	return m_expr;
    249   }
    250 
    251   /**
    252    * Set the inner contained expression of this filter.
    253    */
    254   public void setInnerExpression(Expression expr)
    255   {
    256   	expr.exprSetParent(this);
    257   	m_expr = expr;
    258   }
    259 
    260 
    261   /**
    262    * Get the analysis bits for this walker, as defined in the WalkerFactory.
    263    * @return One of WalkerFactory#BIT_DESCENDANT, etc.
    264    */
    265   public int getAnalysisBits()
    266   {
    267       if (null != m_expr && m_expr instanceof PathComponent)
    268       {
    269         return ((PathComponent) m_expr).getAnalysisBits();
    270       }
    271       return WalkerFactory.BIT_FILTER;
    272   }
    273 
    274   /**
    275    * Returns true if all the nodes in the iteration well be returned in document
    276    * order.
    277    * Warning: This can only be called after setRoot has been called!
    278    *
    279    * @return true as a default.
    280    */
    281   public boolean isDocOrdered()
    282   {
    283     return m_exprObj.isDocOrdered();
    284   }
    285 
    286   /**
    287    * Returns the axis being iterated, if it is known.
    288    *
    289    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple
    290    * types.
    291    */
    292   public int getAxis()
    293   {
    294     return m_exprObj.getAxis();
    295   }
    296 
    297   class filterExprOwner implements ExpressionOwner
    298   {
    299       /**
    300      * @see ExpressionOwner#getExpression()
    301      */
    302     public Expression getExpression()
    303     {
    304       return m_expr;
    305     }
    306 
    307     /**
    308      * @see ExpressionOwner#setExpression(Expression)
    309      */
    310     public void setExpression(Expression exp)
    311     {
    312     	exp.exprSetParent(FilterExprWalker.this);
    313     	m_expr = exp;
    314     }
    315   }
    316 
    317 	/**
    318 	 * This will traverse the heararchy, calling the visitor for
    319 	 * each member.  If the called visitor method returns
    320 	 * false, the subtree should not be called.
    321 	 *
    322 	 * @param visitor The visitor whose appropriate method will be called.
    323 	 */
    324 	public void callPredicateVisitors(XPathVisitor visitor)
    325 	{
    326 	  m_expr.callVisitors(new filterExprOwner(), visitor);
    327 
    328 	  super.callPredicateVisitors(visitor);
    329 	}
    330 
    331 
    332     /**
    333      * @see Expression#deepEquals(Expression)
    334      */
    335     public boolean deepEquals(Expression expr)
    336     {
    337       if (!super.deepEquals(expr))
    338                 return false;
    339 
    340       FilterExprWalker walker = (FilterExprWalker)expr;
    341       if(!m_expr.deepEquals(walker.m_expr))
    342       	return false;
    343 
    344       return true;
    345     }
    346 
    347 
    348 
    349 }
    350