axeswalker.java

来自「JAVA的一些源码 JAVA2 STANDARD EDITION DEVELO」· Java 代码 · 共 588 行

JAVA
588
字号
/* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * $Id: AxesWalker.java,v 1.28 2004/02/17 04:32:08 minchau Exp $ */package com.sun.org.apache.xpath.internal.axes;import java.util.Vector;import com.sun.org.apache.xalan.internal.res.XSLMessages;import com.sun.org.apache.xml.internal.dtm.DTM;import com.sun.org.apache.xml.internal.dtm.DTMAxisTraverser;import com.sun.org.apache.xml.internal.dtm.DTMIterator;import com.sun.org.apache.xpath.internal.Expression;import com.sun.org.apache.xpath.internal.ExpressionOwner;import com.sun.org.apache.xpath.internal.XPathContext;import com.sun.org.apache.xpath.internal.XPathVisitor;import com.sun.org.apache.xpath.internal.compiler.Compiler;import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;/** * Serves as common interface for axes Walkers, and stores common * state variables. */public class AxesWalker extends PredicatedNodeTest        implements Cloneable, PathComponent, ExpressionOwner{    /**   * Construct an AxesWalker using a LocPathIterator.   *   * @param locPathIterator non-null reference to the parent iterator.   */  public AxesWalker(LocPathIterator locPathIterator, int axis)  {    super( locPathIterator );    m_axis = axis;  }    public final WalkingIterator wi()  {    return (WalkingIterator)m_lpi;  }  /**   * Initialize an AxesWalker during the parse of the XPath expression.   *   * @param compiler The Compiler object that has information about this    *                 walker in the op map.   * @param opPos The op code position of this location step.   * @param stepType  The type of location step.   *   * @throws javax.xml.transform.TransformerException   */  public void init(Compiler compiler, int opPos, int stepType)          throws javax.xml.transform.TransformerException  {    initPredicateInfo(compiler, opPos);    // int testType = compiler.getOp(nodeTestOpPos);  }  /**   * Get a cloned AxesWalker.   *   * @return A new AxesWalker that can be used without mutating this one.   *   * @throws CloneNotSupportedException   */  public Object clone() throws CloneNotSupportedException  {    // Do not access the location path itterator during this operation!        AxesWalker clone = (AxesWalker) super.clone();    //clone.setCurrentNode(clone.m_root);    // clone.m_isFresh = true;    return clone;  }    /**   * Do a deep clone of this walker, including next and previous walkers.   * If the this AxesWalker is on the clone list, don't clone but    * return the already cloned version.   *    * @param cloneOwner non-null reference to the cloned location path    *                   iterator to which this clone will be added.   * @param cloneList non-null vector of sources in odd elements, and the    *                  corresponding clones in even vectors.   *    * @return non-null clone, which may be a new clone, or may be a clone    *         contained on the cloneList.   */  AxesWalker cloneDeep(WalkingIterator cloneOwner, Vector cloneList)     throws CloneNotSupportedException  {    AxesWalker clone = findClone(this, cloneList);    if(null != clone)      return clone;    clone = (AxesWalker)this.clone();    clone.setLocPathIterator(cloneOwner);    if(null != cloneList)    {      cloneList.addElement(this);      cloneList.addElement(clone);    }        if(wi().m_lastUsedWalker == this)      cloneOwner.m_lastUsedWalker = clone;          if(null != m_nextWalker)      clone.m_nextWalker = m_nextWalker.cloneDeep(cloneOwner, cloneList);          // If you don't check for the cloneList here, you'll go into an     // recursive infinate loop.      if(null != cloneList)    {      if(null != m_prevWalker)        clone.m_prevWalker = m_prevWalker.cloneDeep(cloneOwner, cloneList);    }    else    {      if(null != m_nextWalker)        clone.m_nextWalker.m_prevWalker = clone;    }    return clone;  }    /**   * Find a clone that corresponds to the key argument.   *    * @param key The original AxesWalker for which there may be a clone.   * @param cloneList vector of sources in odd elements, and the    *                  corresponding clones in even vectors, may be null.   *    * @return A clone that corresponds to the key, or null if key not found.   */  static AxesWalker findClone(AxesWalker key, Vector cloneList)  {    if(null != cloneList)    {      // First, look for clone on list.      int n = cloneList.size();      for (int i = 0; i < n; i+=2)       {        if(key == cloneList.elementAt(i))          return (AxesWalker)cloneList.elementAt(i+1);      }    }    return null;      }    /**   * Detaches the walker from the set which it iterated over, releasing   * any computational resources and placing the iterator in the INVALID   * state.   */  public void detach()  {   	m_currentNode = DTM.NULL;  	m_dtm = null;  	m_traverser = null;  	m_isFresh = true;  	m_root = DTM.NULL;  }    //=============== TreeWalker Implementation ===============  /**   * The root node of the TreeWalker, as specified in setRoot(int root).   * Note that this may actually be below the current node.   *   * @return The context node of the step.   */  public int getRoot()  {    return m_root;  }    /**    * Get the analysis bits for this walker, as defined in the WalkerFactory.   * @return One of WalkerFactory#BIT_DESCENDANT, etc.   */  public int getAnalysisBits()  {  	int axis = getAxis();  	int bit = WalkerFactory.getAnalysisBitFromAxes(axis);  	return bit;  }  /**   * Set the root node of the TreeWalker.   * (Not part of the DOM2 TreeWalker interface).   *   * @param root The context node of this step.   */  public void setRoot(int root)  {    // %OPT% Get this directly from the lpi.    XPathContext xctxt = wi().getXPathContext();    m_dtm = xctxt.getDTM(root);    m_traverser = m_dtm.getAxisTraverser(m_axis);    m_isFresh = true;    m_foundLast = false;    m_root = root;    m_currentNode = root;    if (DTM.NULL == root)    {      throw new RuntimeException(        XSLMessages.createXPATHMessage(XPATHErrorResources.ER_SETTING_WALKER_ROOT_TO_NULL, null)); //"\n !!!! Error! Setting the root of a walker to null!!!");    }    resetProximityPositions();  }  /**   * The node at which the TreeWalker is currently positioned.   * <br> The value must not be null. Alterations to the DOM tree may cause   * the current node to no longer be accepted by the TreeWalker's   * associated filter. currentNode may also be explicitly set to any node,   * whether or not it is within the subtree specified by the root node or   * would be accepted by the filter and whatToShow flags. Further   * traversal occurs relative to currentNode even if it is not part of the   * current view by applying the filters in the requested direction (not   * changing currentNode where no traversal is possible).   *   * @return The node at which the TreeWalker is currently positioned, only null    * if setRoot has not yet been called.   */  public final int getCurrentNode()  {    return m_currentNode;  }  /**   * Set the next walker in the location step chain.   *   *   * @param walker Reference to AxesWalker derivative, or may be null.   */  public void setNextWalker(AxesWalker walker)  {    m_nextWalker = walker;  }  /**   * Get the next walker in the location step chain.   *   *   * @return Reference to AxesWalker derivative, or null.   */  public AxesWalker getNextWalker()  {    return m_nextWalker;  }  /**   * Set or clear the previous walker reference in the location step chain.   *   *   * @param walker Reference to previous walker reference in the location    *               step chain, or null.   */  public void setPrevWalker(AxesWalker walker)  {    m_prevWalker = walker;  }  /**   * Get the previous walker reference in the location step chain.   *   *   * @return Reference to previous walker reference in the location    *               step chain, or null.   */  public AxesWalker getPrevWalker()  {    return m_prevWalker;  }  /**   * This is simply a way to bottle-neck the return of the next node, for    * diagnostic purposes.   *   * @param n Node to return, or null.   *   * @return The argument.   */  private int returnNextNode(int n)  {    return n;  }  /**   * Get the next node in document order on the axes.   *   * @return the next node in document order on the axes, or null.   */  protected int getNextNode()  {    if (m_foundLast)      return DTM.NULL;    if (m_isFresh)    {      m_currentNode = m_traverser.first(m_root);      m_isFresh = false;    }    // I shouldn't have to do this the check for current node, I think.    // numbering\numbering24.xsl fails if I don't do this.  I think     // it occurs as the walkers are backing up. -sb    else if(DTM.NULL != m_currentNode)     {      m_currentNode = m_traverser.next(m_root, m_currentNode);    }    if (DTM.NULL == m_currentNode)      this.m_foundLast = true;    return m_currentNode;  }  /**   *  Moves the <code>TreeWalker</code> to the next visible node in document   * order relative to the current node, and returns the new node. If the   * current node has no next node,  or if the search for nextNode attempts   * to step upward from the TreeWalker's root node, returns   * <code>null</code> , and retains the current node.   * @return  The new node, or <code>null</code> if the current node has no   *   next node  in the TreeWalker's logical view.   */  public int nextNode()  {    int nextNode = DTM.NULL;    AxesWalker walker = wi().getLastUsedWalker();    while (true)    {      if (null == walker)        break;      nextNode = walker.getNextNode();      if (DTM.NULL == nextNode)      {        walker = walker.m_prevWalker;      }      else      {        if (walker.acceptNode(nextNode) != DTMIterator.FILTER_ACCEPT)        {          continue;        }        if (null == walker.m_nextWalker)        {          wi().setLastUsedWalker(walker);          // return walker.returnNextNode(nextNode);          break;        }        else        {          AxesWalker prev = walker;          walker = walker.m_nextWalker;          walker.setRoot(nextNode);          walker.m_prevWalker = prev;          continue;        }      }  // if(null != nextNode)    }  // while(null != walker)    return nextNode;  }  //============= End TreeWalker Implementation =============  /**   * Get the index of the last node that can be itterated to.   *   *   * @param xctxt XPath runtime context.   *   * @return the index of the last node that can be itterated to.   */  public int getLastPos(XPathContext xctxt)  {    int pos = getProximityPosition();        AxesWalker walker;    try    {      walker = (AxesWalker) clone();    }    catch (CloneNotSupportedException cnse)    {      return -1;    }    walker.setPredicateCount(walker.getPredicateCount() - 1);    walker.setNextWalker(null);    walker.setPrevWalker(null);    WalkingIterator lpi = wi();    AxesWalker savedWalker = lpi.getLastUsedWalker();    try    {      lpi.setLastUsedWalker(walker);      int next;      while (DTM.NULL != (next = walker.nextNode()))      {        pos++;      }      // TODO: Should probably save this in the iterator.    }    finally    {      lpi.setLastUsedWalker(savedWalker);    }    // System.out.println("pos: "+pos);    return pos;  }    //============= State Data =============    /**   * The DTM for the root.  This can not be used, or must be changed,    * for the filter walker, or any walker that can have nodes    * from multiple documents.   * Never, ever, access this value without going through getDTM(int node).   */  private DTM m_dtm;    /**   * Set the DTM for this walker.   *    * @param dtm Non-null reference to a DTM.   */  public void setDefaultDTM(DTM dtm)  {    m_dtm = dtm;  }    /**   * Get the DTM for this walker.   *    * @return Non-null reference to a DTM.   */  public DTM getDTM(int node)  {    //    return wi().getXPathContext().getDTM(node);  }    /**   * Returns true if all the nodes in the iteration well be returned in document    * order.   * Warning: This can only be called after setRoot has been called!   *    * @return true as a default.   */  public boolean isDocOrdered()  {    return true;  }    /**   * Returns the axis being iterated, if it is known.   *    * @return Axis.CHILD, etc., or -1 if the axis is not known or is of multiple    * types.   */  public int getAxis()  {    return m_axis;  }    /**   * This will traverse the heararchy, calling the visitor for    * each member.  If the called visitor method returns    * false, the subtree should not be called.   *    * @param owner The owner of the visitor, where that path may be    *              rewritten if needed.   * @param visitor The visitor whose appropriate method will be called.   */  public void callVisitors(ExpressionOwner owner, XPathVisitor visitor)  {  	if(visitor.visitStep(owner, this))  	{  		callPredicateVisitors(visitor);  		if(null != m_nextWalker)  		{  			m_nextWalker.callVisitors(this, visitor);  		}  	}  }    /**   * @see ExpressionOwner#getExpression()   */  public Expression getExpression()  {    return m_nextWalker;  }  /**   * @see ExpressionOwner#setExpression(Expression)   */  public void setExpression(Expression exp)  {  	exp.exprSetParent(this);  	m_nextWalker = (AxesWalker)exp;  }      /**     * @see Expression#deepEquals(Expression)     */    public boolean deepEquals(Expression expr)    {      if (!super.deepEquals(expr))                return false;      AxesWalker walker = (AxesWalker)expr;      if(this.m_axis != walker.m_axis)      	return false;      return true;    }  /**   *  The root node of the TreeWalker, as specified when it was created.   */  transient int m_root = DTM.NULL;  /**   *  The node at which the TreeWalker is currently positioned.   */  private transient int m_currentNode = DTM.NULL;    /** True if an itteration has not begun.  */  transient boolean m_isFresh;  /** The next walker in the location step chain.   *  @serial  */  protected AxesWalker m_nextWalker;    /** The previous walker in the location step chain, or null.   *  @serial   */  AxesWalker m_prevWalker;    /** The traversal axis from where the nodes will be filtered. */  protected int m_axis = -1;  /** The DTM inner traversal class, that corresponds to the super axis. */  protected DTMAxisTraverser m_traverser; }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?