1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: XPathContext.java,v 1.2.4.2 2005/09/15 01:37:55 jeffsuttor Exp $
  22  */
  23 package com.sun.org.apache.xpath.internal;
  24 
  25 import com.sun.org.apache.xalan.internal.extensions.ExpressionContext;
  26 import com.sun.org.apache.xalan.internal.res.XSLMessages;
  27 import com.sun.org.apache.xml.internal.dtm.Axis;
  28 import com.sun.org.apache.xml.internal.dtm.DTM;
  29 import com.sun.org.apache.xml.internal.dtm.DTMFilter;
  30 import com.sun.org.apache.xml.internal.dtm.DTMIterator;
  31 import com.sun.org.apache.xml.internal.dtm.DTMManager;
  32 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
  33 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM;
  34 import com.sun.org.apache.xml.internal.utils.IntStack;
  35 import com.sun.org.apache.xml.internal.utils.NodeVector;
  36 import com.sun.org.apache.xml.internal.utils.ObjectStack;
  37 import com.sun.org.apache.xml.internal.utils.PrefixResolver;
  38 import com.sun.org.apache.xml.internal.utils.XMLString;
  39 import com.sun.org.apache.xpath.internal.axes.SubContextList;
  40 import com.sun.org.apache.xpath.internal.objects.DTMXRTreeFrag;
  41 import com.sun.org.apache.xpath.internal.objects.XObject;
  42 import com.sun.org.apache.xpath.internal.objects.XString;
  43 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
  44 import java.lang.reflect.Method;
  45 import java.util.HashMap;
  46 import java.util.Iterator;
  47 import java.util.Stack;
  48 import java.util.Vector;
  49 import javax.xml.transform.ErrorListener;
  50 import javax.xml.transform.SourceLocator;
  51 import javax.xml.transform.TransformerException;
  52 import javax.xml.transform.URIResolver;
  53 import org.xml.sax.XMLReader;
  54 
  55 /**
  56  * Default class for the runtime execution context for XPath.
  57  *
  58  * <p>This class extends DTMManager but does not directly implement it.</p>
  59  * @xsl.usage advanced
  60  */
  61 public class XPathContext extends DTMManager // implements ExpressionContext
  62 {
  63         IntStack m_last_pushed_rtfdtm=new IntStack();
  64   /**
  65    * Stack of cached "reusable" DTMs for Result Tree Fragments.
  66    * This is a kluge to handle the problem of starting an RTF before
  67    * the old one is complete.
  68    *
  69    * %REVIEW% I'm using a Vector rather than Stack so we can reuse
  70    * the DTMs if the problem occurs multiple times. I'm not sure that's
  71    * really a net win versus discarding the DTM and starting a new one...
  72    * but the retained RTF DTM will have been tail-pruned so should be small.
  73    */
  74   private Vector m_rtfdtm_stack=null;
  75   /** Index of currently active RTF DTM in m_rtfdtm_stack */
  76   private int m_which_rtfdtm=-1;
  77 
  78  /**
  79    * Most recent "reusable" DTM for Global Result Tree Fragments. No stack is
  80    * required since we're never going to pop these.
  81    */
  82   private SAX2RTFDTM m_global_rtfdtm=null;
  83 
  84   /**
  85    * HashMap of cached the DTMXRTreeFrag objects, which are identified by DTM IDs.
  86    * The object are just wrappers for DTMs which are used in  XRTreeFrag.
  87    */
  88   private HashMap m_DTMXRTreeFrags = null;
  89 
  90   /**
  91    * state of the secure processing feature.
  92    */
  93   private boolean m_isSecureProcessing = false;
  94 
  95   private boolean m_useServicesMechanism = true;
  96 
  97   /**
  98    * Though XPathContext context extends
  99    * the DTMManager, it really is a proxy for this object, which
 100    * is the real DTMManager.
 101    */
 102   protected DTMManager m_dtmManager = DTMManager.newInstance(
 103                    com.sun.org.apache.xpath.internal.objects.XMLStringFactoryImpl.getFactory());
 104 
 105   /**
 106    * Return the DTMManager object.  Though XPathContext context extends
 107    * the DTMManager, it really is a proxy for the real DTMManager.  If a
 108    * caller needs to make a lot of calls to the DTMManager, it is faster
 109    * if it gets the real one from this function.
 110    */
 111    public DTMManager getDTMManager()
 112    {
 113      return m_dtmManager;
 114    }
 115 
 116   /**
 117    * Set the state of the secure processing feature
 118    */
 119   public void setSecureProcessing(boolean flag)
 120   {
 121     m_isSecureProcessing = flag;
 122   }
 123 
 124   /**
 125    * Return the state of the secure processing feature
 126    */
 127   public boolean isSecureProcessing()
 128   {
 129     return m_isSecureProcessing;
 130   }
 131 
 132   /**
 133    * Get an instance of a DTM, loaded with the content from the
 134    * specified source.  If the unique flag is true, a new instance will
 135    * always be returned.  Otherwise it is up to the DTMManager to return a
 136    * new instance or an instance that it already created and may be being used
 137    * by someone else.
 138    * (I think more parameters will need to be added for error handling, and entity
 139    * resolution).
 140    *
 141    * @param source the specification of the source object, which may be null,
 142    *               in which case it is assumed that node construction will take
 143    *               by some other means.
 144    * @param unique true if the returned DTM must be unique, probably because it
 145    * is going to be mutated.
 146    * @param wsfilter Enables filtering of whitespace nodes, and may be null.
 147    * @param incremental true if the construction should try and be incremental.
 148    * @param doIndexing true if the caller considers it worth it to use
 149    *                   indexing schemes.
 150    *
 151    * @return a non-null DTM reference.
 152    */
 153   public DTM getDTM(javax.xml.transform.Source source, boolean unique,
 154                     DTMWSFilter wsfilter,
 155                     boolean incremental,
 156                     boolean doIndexing)
 157   {
 158     return m_dtmManager.getDTM(source, unique, wsfilter,
 159                                incremental, doIndexing);
 160   }
 161 
 162   /**
 163    * Get an instance of a DTM that "owns" a node handle.
 164    *
 165    * @param nodeHandle the nodeHandle.
 166    *
 167    * @return a non-null DTM reference.
 168    */
 169   public DTM getDTM(int nodeHandle)
 170   {
 171     return m_dtmManager.getDTM(nodeHandle);
 172   }
 173 
 174   /**
 175    * Given a W3C DOM node, try and return a DTM handle.
 176    * Note: calling this may be non-optimal.
 177    *
 178    * @param node Non-null reference to a DOM node.
 179    *
 180    * @return a valid DTM handle.
 181    */
 182   public int getDTMHandleFromNode(org.w3c.dom.Node node)
 183   {
 184     return m_dtmManager.getDTMHandleFromNode(node);
 185   }
 186 //
 187 //
 188   /**
 189    * %TBD% Doc
 190    */
 191   public int getDTMIdentity(DTM dtm)
 192   {
 193     return m_dtmManager.getDTMIdentity(dtm);
 194   }
 195 //
 196   /**
 197    * Creates an empty <code>DocumentFragment</code> object.
 198    * @return A new <code>DocumentFragment handle</code>.
 199    */
 200   public DTM createDocumentFragment()
 201   {
 202     return m_dtmManager.createDocumentFragment();
 203   }
 204 //
 205   /**
 206    * Release a DTM either to a lru pool, or completely remove reference.
 207    * DTMs without system IDs are always hard deleted.
 208    * State: experimental.
 209    *
 210    * @param dtm The DTM to be released.
 211    * @param shouldHardDelete True if the DTM should be removed no matter what.
 212    * @return true if the DTM was removed, false if it was put back in a lru pool.
 213    */
 214   public boolean release(DTM dtm, boolean shouldHardDelete)
 215   {
 216     // %REVIEW% If it's a DTM which may contain multiple Result Tree
 217     // Fragments, we can't discard it unless we know not only that it
 218     // is empty, but that the XPathContext itself is going away. So do
 219     // _not_ accept the request. (May want to do it as part of
 220     // reset(), though.)
 221     if(m_rtfdtm_stack!=null && m_rtfdtm_stack.contains(dtm))
 222     {
 223       return false;
 224     }
 225 
 226     return m_dtmManager.release(dtm, shouldHardDelete);
 227   }
 228 
 229   /**
 230    * Create a new <code>DTMIterator</code> based on an XPath
 231    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
 232    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
 233    *
 234    * @param xpathCompiler ??? Somehow we need to pass in a subpart of the
 235    * expression.  I hate to do this with strings, since the larger expression
 236    * has already been parsed.
 237    *
 238    * @param pos The position in the expression.
 239    * @return The newly created <code>DTMIterator</code>.
 240    */
 241   public DTMIterator createDTMIterator(Object xpathCompiler, int pos)
 242   {
 243     return m_dtmManager.createDTMIterator(xpathCompiler, pos);
 244   }
 245 //
 246   /**
 247    * Create a new <code>DTMIterator</code> based on an XPath
 248    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
 249    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
 250    *
 251    * @param xpathString Must be a valid string expressing a
 252    * <a href="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
 253    * a <a href="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
 254    *
 255    * @param presolver An object that can resolve prefixes to namespace URLs.
 256    *
 257    * @return The newly created <code>DTMIterator</code>.
 258    */
 259   public DTMIterator createDTMIterator(String xpathString,
 260           PrefixResolver presolver)
 261   {
 262     return m_dtmManager.createDTMIterator(xpathString, presolver);
 263   }
 264 //
 265   /**
 266    * Create a new <code>DTMIterator</code> based only on a whatToShow and
 267    * a DTMFilter.  The traversal semantics are defined as the descendant
 268    * access.
 269    *
 270    * @param whatToShow This flag specifies which node types may appear in
 271    *   the logical view of the tree presented by the iterator. See the
 272    *   description of <code>NodeFilter</code> for the set of possible
 273    *   <code>SHOW_</code> values.These flags can be combined using
 274    *   <code>OR</code>.
 275    * @param filter The <code>NodeFilter</code> to be used with this
 276    *   <code>TreeWalker</code>, or <code>null</code> to indicate no filter.
 277    * @param entityReferenceExpansion The value of this flag determines
 278    *   whether entity reference nodes are expanded.
 279    *
 280    * @return The newly created <code>NodeIterator</code>.
 281    */
 282   public DTMIterator createDTMIterator(int whatToShow,
 283           DTMFilter filter, boolean entityReferenceExpansion)
 284   {
 285     return m_dtmManager.createDTMIterator(whatToShow, filter, entityReferenceExpansion);
 286   }
 287 
 288   /**
 289    * Create a new <code>DTMIterator</code> that holds exactly one node.
 290    *
 291    * @param node The node handle that the DTMIterator will iterate to.
 292    *
 293    * @return The newly created <code>DTMIterator</code>.
 294    */
 295   public DTMIterator createDTMIterator(int node)
 296   {
 297     // DescendantIterator iter = new DescendantIterator();
 298     DTMIterator iter = new com.sun.org.apache.xpath.internal.axes.OneStepIteratorForward(Axis.SELF);
 299     iter.setRoot(node, this);
 300     return iter;
 301     // return m_dtmManager.createDTMIterator(node);
 302   }
 303 
 304   /**
 305    * Create an XPathContext instance.
 306    */
 307   public XPathContext()
 308   {
 309     this(true);
 310   }
 311 
 312   public XPathContext(boolean useServicesMechanism) {
 313       init(useServicesMechanism);
 314   }
 315   /**
 316    **This constructor doesn't seem to be used anywhere -- huizhe wang**
 317    * Create an XPathContext instance.
 318    * @param owner Value that can be retrieved via the getOwnerObject() method.
 319    * @see #getOwnerObject
 320    */
 321   public XPathContext(Object owner)
 322   {
 323     m_owner = owner;
 324     try {
 325       m_ownerGetErrorListener = m_owner.getClass().getMethod("getErrorListener", new Class[] {});
 326     }
 327     catch (NoSuchMethodException nsme) {}
 328     init(true);
 329   }
 330 
 331   private void init(boolean useServicesMechanism) {
 332     m_prefixResolvers.push(null);
 333     m_currentNodes.push(DTM.NULL);
 334     m_currentExpressionNodes.push(DTM.NULL);
 335     m_saxLocations.push(null);
 336     m_useServicesMechanism = useServicesMechanism;
 337     m_dtmManager = DTMManager.newInstance(
 338                    com.sun.org.apache.xpath.internal.objects.XMLStringFactoryImpl.getFactory()
 339                    );
 340   }
 341 
 342   /**
 343    * Reset for new run.
 344    */
 345   public void reset()
 346   {
 347     releaseDTMXRTreeFrags();
 348         // These couldn't be disposed of earlier (see comments in release()); zap them now.
 349         if(m_rtfdtm_stack!=null)
 350                  for (java.util.Enumeration e = m_rtfdtm_stack.elements() ; e.hasMoreElements() ;)
 351                         m_dtmManager.release((DTM)e.nextElement(), true);
 352 
 353     m_rtfdtm_stack=null; // drop our references too
 354     m_which_rtfdtm=-1;
 355 
 356     if(m_global_rtfdtm!=null)
 357                         m_dtmManager.release(m_global_rtfdtm,true);
 358     m_global_rtfdtm=null;
 359 
 360 
 361     m_dtmManager = DTMManager.newInstance(
 362                    com.sun.org.apache.xpath.internal.objects.XMLStringFactoryImpl.getFactory()
 363                    );
 364 
 365     m_saxLocations.removeAllElements();
 366         m_axesIteratorStack.removeAllElements();
 367         m_contextNodeLists.removeAllElements();
 368         m_currentExpressionNodes.removeAllElements();
 369         m_currentNodes.removeAllElements();
 370         m_iteratorRoots.RemoveAllNoClear();
 371         m_predicatePos.removeAllElements();
 372         m_predicateRoots.RemoveAllNoClear();
 373         m_prefixResolvers.removeAllElements();
 374 
 375         m_prefixResolvers.push(null);
 376     m_currentNodes.push(DTM.NULL);
 377     m_currentExpressionNodes.push(DTM.NULL);
 378     m_saxLocations.push(null);
 379   }
 380 
 381   /** The current stylesheet locator. */
 382   ObjectStack m_saxLocations = new ObjectStack(RECURSIONLIMIT);
 383 
 384   /**
 385    * Set the current locater in the stylesheet.
 386    *
 387    * @param location The location within the stylesheet.
 388    */
 389   public void setSAXLocator(SourceLocator location)
 390   {
 391     m_saxLocations.setTop(location);
 392   }
 393 
 394   /**
 395    * Set the current locater in the stylesheet.
 396    *
 397    * @param location The location within the stylesheet.
 398    */
 399   public void pushSAXLocator(SourceLocator location)
 400   {
 401     m_saxLocations.push(location);
 402   }
 403 
 404   /**
 405    * Push a slot on the locations stack so that setSAXLocator can be
 406    * repeatedly called.
 407    *
 408    */
 409   public void pushSAXLocatorNull()
 410   {
 411     m_saxLocations.push(null);
 412   }
 413 
 414 
 415   /**
 416    * Pop the current locater.
 417    */
 418   public void popSAXLocator()
 419   {
 420     m_saxLocations.pop();
 421   }
 422 
 423   /**
 424    * Get the current locater in the stylesheet.
 425    *
 426    * @return The location within the stylesheet, or null if not known.
 427    */
 428   public SourceLocator getSAXLocator()
 429   {
 430     return (SourceLocator) m_saxLocations.peek();
 431   }
 432 
 433   /** The owner context of this XPathContext.  In the case of XSLT, this will be a
 434    *  Transformer object.
 435    */
 436   private Object m_owner;
 437 
 438   /** The owner context of this XPathContext.  In the case of XSLT, this will be a
 439    *  Transformer object.
 440    */
 441   private Method m_ownerGetErrorListener;
 442 
 443   /**
 444    * Get the "owner" context of this context, which should be,
 445    * in the case of XSLT, the Transformer object.  This is needed
 446    * so that XSLT functions can get the Transformer.
 447    * @return The owner object passed into the constructor, or null.
 448    */
 449   public Object getOwnerObject()
 450   {
 451     return m_owner;
 452   }
 453 
 454   // ================ VarStack ===================
 455 
 456   /**
 457    * The stack of Variable stacks.  A VariableStack will be
 458    * pushed onto this stack for each template invocation.
 459    */
 460   private VariableStack m_variableStacks = new VariableStack();
 461 
 462   /**
 463    * Get the variable stack, which is in charge of variables and
 464    * parameters.
 465    *
 466    * @return the variable stack, which should not be null.
 467    */
 468   public final VariableStack getVarStack()
 469   {
 470     return m_variableStacks;
 471   }
 472 
 473   /**
 474    * Get the variable stack, which is in charge of variables and
 475    * parameters.
 476    *
 477    * @param varStack non-null reference to the variable stack.
 478    */
 479   public final void setVarStack(VariableStack varStack)
 480   {
 481     m_variableStacks = varStack;
 482   }
 483 
 484   // ================ SourceTreeManager ===================
 485 
 486   /** The source tree manager, which associates Source objects to source
 487    *  tree nodes. */
 488   private SourceTreeManager m_sourceTreeManager = new SourceTreeManager();
 489 
 490   /**
 491    * Get the SourceTreeManager associated with this execution context.
 492    *
 493    * @return the SourceTreeManager associated with this execution context.
 494    */
 495   public final SourceTreeManager getSourceTreeManager()
 496   {
 497     return m_sourceTreeManager;
 498   }
 499 
 500   /**
 501    * Set the SourceTreeManager associated with this execution context.
 502    *
 503    * @param mgr the SourceTreeManager to be associated with this
 504    *        execution context.
 505    */
 506   public void setSourceTreeManager(SourceTreeManager mgr)
 507   {
 508     m_sourceTreeManager = mgr;
 509   }
 510 
 511   // =================================================
 512 
 513   /** The ErrorListener where errors and warnings are to be reported.   */
 514   private ErrorListener m_errorListener;
 515 
 516   /** A default ErrorListener in case our m_errorListener was not specified and our
 517    *  owner either does not have an ErrorListener or has a null one.
 518    */
 519   private ErrorListener m_defaultErrorListener;
 520 
 521   /**
 522    * Get the ErrorListener where errors and warnings are to be reported.
 523    *
 524    * @return A non-null ErrorListener reference.
 525    */
 526   public final ErrorListener getErrorListener()
 527   {
 528 
 529     if (null != m_errorListener)
 530         return m_errorListener;
 531 
 532     ErrorListener retval = null;
 533 
 534     try {
 535       if (null != m_ownerGetErrorListener)
 536         retval = (ErrorListener) m_ownerGetErrorListener.invoke(m_owner, new Object[] {});
 537     }
 538     catch (Exception e) {}
 539 
 540     if (null == retval)
 541     {
 542       if (null == m_defaultErrorListener)
 543         m_defaultErrorListener = new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler();
 544       retval = m_defaultErrorListener;
 545     }
 546 
 547     return retval;
 548   }
 549 
 550   /**
 551    * Set the ErrorListener where errors and warnings are to be reported.
 552    *
 553    * @param listener A non-null ErrorListener reference.
 554    */
 555   public void setErrorListener(ErrorListener listener) throws IllegalArgumentException
 556   {
 557     if (listener == null)
 558       throw new IllegalArgumentException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler");
 559     m_errorListener = listener;
 560   }
 561 
 562 
 563   // =================================================
 564 
 565   /** The TrAX URI Resolver for resolving URIs from the document(...)
 566    *  function to source tree nodes.  */
 567   private URIResolver m_uriResolver;
 568 
 569   /**
 570    * Get the URIResolver associated with this execution context.
 571    *
 572    * @return a URI resolver, which may be null.
 573    */
 574   public final URIResolver getURIResolver()
 575   {
 576     return m_uriResolver;
 577   }
 578 
 579   /**
 580    * Set the URIResolver associated with this execution context.
 581    *
 582    * @param resolver the URIResolver to be associated with this
 583    *        execution context, may be null to clear an already set resolver.
 584    */
 585   public void setURIResolver(URIResolver resolver)
 586   {
 587     m_uriResolver = resolver;
 588   }
 589 
 590   // =================================================
 591 
 592   /** The reader of the primary source tree.    */
 593   public XMLReader m_primaryReader;
 594 
 595   /**
 596    * Get primary XMLReader associated with this execution context.
 597    *
 598    * @return The reader of the primary source tree.
 599    */
 600   public final XMLReader getPrimaryReader()
 601   {
 602     return m_primaryReader;
 603   }
 604 
 605   /**
 606    * Set primary XMLReader associated with this execution context.
 607    *
 608    * @param reader The reader of the primary source tree.
 609    */
 610   public void setPrimaryReader(XMLReader reader)
 611   {
 612     m_primaryReader = reader;
 613   }
 614 
 615   // =================================================
 616 
 617 
 618   /** Misnamed string manager for XPath messages.  */
 619   // private static XSLMessages m_XSLMessages = new XSLMessages();
 620 
 621   //==========================================================
 622   // SECTION: Execution context state tracking
 623   //==========================================================
 624 
 625   /**
 626    * The current context node list.
 627    */
 628   private Stack m_contextNodeLists = new Stack();
 629 
 630   public Stack getContextNodeListsStack() { return m_contextNodeLists; }
 631   public void setContextNodeListsStack(Stack s) { m_contextNodeLists = s; }
 632 
 633   /**
 634    * Get the current context node list.
 635    *
 636    * @return  the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
 637    * also referred to here as a <term>context node list</term>.
 638    */
 639   public final DTMIterator getContextNodeList()
 640   {
 641 
 642     if (m_contextNodeLists.size() > 0)
 643       return (DTMIterator) m_contextNodeLists.peek();
 644     else
 645       return null;
 646   }
 647 
 648   /**
 649    * Set the current context node list.
 650    *
 651    * @param nl the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
 652    * also referred to here as a <term>context node list</term>.
 653    * @xsl.usage internal
 654    */
 655   public final void pushContextNodeList(DTMIterator nl)
 656   {
 657     m_contextNodeLists.push(nl);
 658   }
 659 
 660   /**
 661    * Pop the current context node list.
 662    * @xsl.usage internal
 663    */
 664   public final void popContextNodeList()
 665   {
 666         if(m_contextNodeLists.isEmpty())
 667           System.err.println("Warning: popContextNodeList when stack is empty!");
 668         else
 669       m_contextNodeLists.pop();
 670   }
 671 
 672   /**
 673    * The amount to use for stacks that record information during the
 674    * recursive execution.
 675    */
 676   public static final int RECURSIONLIMIT = (1024*4);
 677 
 678   /** The stack of <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a> objects.
 679    *  Not to be confused with the current node list.  %REVIEW% Note that there
 680    *  are no bounds check and resize for this stack, so if it is blown, it's all
 681    *  over.  */
 682   private IntStack m_currentNodes = new IntStack(RECURSIONLIMIT);
 683 
 684 //  private NodeVector m_currentNodes = new NodeVector();
 685 
 686   public IntStack getCurrentNodeStack() {return m_currentNodes; }
 687   public void setCurrentNodeStack(IntStack nv) { m_currentNodes = nv; }
 688 
 689   /**
 690    * Get the current context node.
 691    *
 692    * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 693    */
 694   public final int getCurrentNode()
 695   {
 696     return m_currentNodes.peek();
 697   }
 698 
 699   /**
 700    * Set the current context node and expression node.
 701    *
 702    * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 703    * @param en the sub-expression context node.
 704    */
 705   public final void pushCurrentNodeAndExpression(int cn, int en)
 706   {
 707     m_currentNodes.push(cn);
 708     m_currentExpressionNodes.push(cn);
 709   }
 710 
 711   /**
 712    * Set the current context node.
 713    */
 714   public final void popCurrentNodeAndExpression()
 715   {
 716     m_currentNodes.quickPop(1);
 717     m_currentExpressionNodes.quickPop(1);
 718   }
 719 
 720   /**
 721    * Push the current context node, expression node, and prefix resolver.
 722    *
 723    * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 724    * @param en the sub-expression context node.
 725    * @param nc the namespace context (prefix resolver.
 726    */
 727   public final void pushExpressionState(int cn, int en, PrefixResolver nc)
 728   {
 729     m_currentNodes.push(cn);
 730     m_currentExpressionNodes.push(cn);
 731     m_prefixResolvers.push(nc);
 732   }
 733 
 734   /**
 735    * Pop the current context node, expression node, and prefix resolver.
 736    */
 737   public final void popExpressionState()
 738   {
 739     m_currentNodes.quickPop(1);
 740     m_currentExpressionNodes.quickPop(1);
 741     m_prefixResolvers.pop();
 742   }
 743 
 744 
 745 
 746   /**
 747    * Set the current context node.
 748    *
 749    * @param n the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
 750    */
 751   public final void pushCurrentNode(int n)
 752   {
 753     m_currentNodes.push(n);
 754   }
 755 
 756   /**
 757    * Pop the current context node.
 758    */
 759   public final void popCurrentNode()
 760   {
 761     m_currentNodes.quickPop(1);
 762   }
 763 
 764   /**
 765    * Set the current predicate root.
 766    */
 767   public final void pushPredicateRoot(int n)
 768   {
 769     m_predicateRoots.push(n);
 770   }
 771 
 772   /**
 773    * Pop the current predicate root.
 774    */
 775   public final void popPredicateRoot()
 776   {
 777     m_predicateRoots.popQuick();
 778   }
 779 
 780   /**
 781    * Get the current predicate root.
 782    */
 783   public final int getPredicateRoot()
 784   {
 785     return m_predicateRoots.peepOrNull();
 786   }
 787 
 788   /**
 789    * Set the current location path iterator root.
 790    */
 791   public final void pushIteratorRoot(int n)
 792   {
 793     m_iteratorRoots.push(n);
 794   }
 795 
 796   /**
 797    * Pop the current location path iterator root.
 798    */
 799   public final void popIteratorRoot()
 800   {
 801     m_iteratorRoots.popQuick();
 802   }
 803 
 804   /**
 805    * Get the current location path iterator root.
 806    */
 807   public final int getIteratorRoot()
 808   {
 809     return m_iteratorRoots.peepOrNull();
 810   }
 811 
 812   /** A stack of the current sub-expression nodes.  */
 813   private NodeVector m_iteratorRoots = new NodeVector();
 814 
 815   /** A stack of the current sub-expression nodes.  */
 816   private NodeVector m_predicateRoots = new NodeVector();
 817 
 818   /** A stack of the current sub-expression nodes.  */
 819   private IntStack m_currentExpressionNodes = new IntStack(RECURSIONLIMIT);
 820 
 821 
 822   public IntStack getCurrentExpressionNodeStack() { return m_currentExpressionNodes; }
 823   public void setCurrentExpressionNodeStack(IntStack nv) { m_currentExpressionNodes = nv; }
 824 
 825   private IntStack m_predicatePos = new IntStack();
 826 
 827   public final int getPredicatePos()
 828   {
 829     return m_predicatePos.peek();
 830   }
 831 
 832   public final void pushPredicatePos(int n)
 833   {
 834     m_predicatePos.push(n);
 835   }
 836 
 837   public final void popPredicatePos()
 838   {
 839     m_predicatePos.pop();
 840   }
 841 
 842   /**
 843    * Get the current node that is the expression's context (i.e. for current() support).
 844    *
 845    * @return The current sub-expression node.
 846    */
 847   public final int getCurrentExpressionNode()
 848   {
 849     return m_currentExpressionNodes.peek();
 850   }
 851 
 852   /**
 853    * Set the current node that is the expression's context (i.e. for current() support).
 854    *
 855    * @param n The sub-expression node to be current.
 856    */
 857   public final void pushCurrentExpressionNode(int n)
 858   {
 859     m_currentExpressionNodes.push(n);
 860   }
 861 
 862   /**
 863    * Pop the current node that is the expression's context
 864    * (i.e. for current() support).
 865    */
 866   public final void popCurrentExpressionNode()
 867   {
 868     m_currentExpressionNodes.quickPop(1);
 869   }
 870 
 871   private ObjectStack m_prefixResolvers
 872                                    = new ObjectStack(RECURSIONLIMIT);
 873 
 874   /**
 875    * Get the current namespace context for the xpath.
 876    *
 877    * @return the current prefix resolver for resolving prefixes to
 878    *         namespace URLs.
 879    */
 880   public final PrefixResolver getNamespaceContext()
 881   {
 882     return (PrefixResolver) m_prefixResolvers.peek();
 883   }
 884 
 885   /**
 886    * Get the current namespace context for the xpath.
 887    *
 888    * @param pr the prefix resolver to be used for resolving prefixes to
 889    *         namespace URLs.
 890    */
 891   public final void setNamespaceContext(PrefixResolver pr)
 892   {
 893     m_prefixResolvers.setTop(pr);
 894   }
 895 
 896   /**
 897    * Push a current namespace context for the xpath.
 898    *
 899    * @param pr the prefix resolver to be used for resolving prefixes to
 900    *         namespace URLs.
 901    */
 902   public final void pushNamespaceContext(PrefixResolver pr)
 903   {
 904     m_prefixResolvers.push(pr);
 905   }
 906 
 907   /**
 908    * Just increment the namespace contest stack, so that setNamespaceContext
 909    * can be used on the slot.
 910    */
 911   public final void pushNamespaceContextNull()
 912   {
 913     m_prefixResolvers.push(null);
 914   }
 915 
 916   /**
 917    * Pop the current namespace context for the xpath.
 918    */
 919   public final void popNamespaceContext()
 920   {
 921     m_prefixResolvers.pop();
 922   }
 923 
 924   //==========================================================
 925   // SECTION: Current TreeWalker contexts (for internal use)
 926   //==========================================================
 927 
 928   /**
 929    * Stack of AxesIterators.
 930    */
 931   private Stack m_axesIteratorStack = new Stack();
 932 
 933   public Stack getAxesIteratorStackStacks() { return m_axesIteratorStack; }
 934   public void setAxesIteratorStackStacks(Stack s) { m_axesIteratorStack = s; }
 935 
 936   /**
 937    * Push a TreeWalker on the stack.
 938    *
 939    * @param iter A sub-context AxesWalker.
 940    * @xsl.usage internal
 941    */
 942   public final void pushSubContextList(SubContextList iter)
 943   {
 944     m_axesIteratorStack.push(iter);
 945   }
 946 
 947   /**
 948    * Pop the last pushed axes iterator.
 949    * @xsl.usage internal
 950    */
 951   public final void popSubContextList()
 952   {
 953     m_axesIteratorStack.pop();
 954   }
 955 
 956   /**
 957    * Get the current axes iterator, or return null if none.
 958    *
 959    * @return the sub-context node list.
 960    * @xsl.usage internal
 961    */
 962   public SubContextList getSubContextList()
 963   {
 964     return m_axesIteratorStack.isEmpty()
 965            ? null : (SubContextList) m_axesIteratorStack.peek();
 966   }
 967 
 968   /**
 969    * Get the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>
 970    * as defined by the XSLT spec.
 971    *
 972    * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>.
 973    * @xsl.usage internal
 974    */
 975 
 976   public com.sun.org.apache.xpath.internal.axes.SubContextList getCurrentNodeList()
 977   {
 978     return m_axesIteratorStack.isEmpty()
 979            ? null : (SubContextList) m_axesIteratorStack.elementAt(0);
 980   }
 981   //==========================================================
 982   // SECTION: Implementation of ExpressionContext interface
 983   //==========================================================
 984 
 985   /**
 986    * Get the current context node.
 987    * @return The current context node.
 988    */
 989   public final int getContextNode()
 990   {
 991     return this.getCurrentNode();
 992   }
 993 
 994   /**
 995    * Get the current context node list.
 996    * @return An iterator for the current context list, as
 997    * defined in XSLT.
 998    */
 999   public final DTMIterator getContextNodes()
1000   {
1001 
1002     try
1003     {
1004       DTMIterator cnl = getContextNodeList();
1005 
1006       if (null != cnl)
1007         return cnl.cloneWithReset();
1008       else
1009         return null;  // for now... this might ought to be an empty iterator.
1010     }
1011     catch (CloneNotSupportedException cnse)
1012     {
1013       return null;  // error reporting?
1014     }
1015   }
1016 
1017   XPathExpressionContext expressionContext = new XPathExpressionContext();
1018 
1019   /**
1020    * The the expression context for extensions for this context.
1021    *
1022    * @return An object that implements the ExpressionContext.
1023    */
1024   public ExpressionContext getExpressionContext()
1025   {
1026     return expressionContext;
1027   }
1028 
1029   public class XPathExpressionContext implements ExpressionContext
1030   {
1031     /**
1032      * Return the XPathContext associated with this XPathExpressionContext.
1033      * Extensions should use this judiciously and only when special processing
1034      * requirements cannot be met another way.  Consider requesting an enhancement
1035      * to the ExpressionContext interface to avoid having to call this method.
1036      * @return the XPathContext associated with this XPathExpressionContext.
1037      */
1038      public XPathContext getXPathContext()
1039      {
1040        return XPathContext.this;
1041      }
1042 
1043     /**
1044      * Return the DTMManager object.  Though XPathContext context extends
1045      * the DTMManager, it really is a proxy for the real DTMManager.  If a
1046      * caller needs to make a lot of calls to the DTMManager, it is faster
1047      * if it gets the real one from this function.
1048      */
1049      public DTMManager getDTMManager()
1050      {
1051        return m_dtmManager;
1052      }
1053 
1054     /**
1055      * Get the current context node.
1056      * @return The current context node.
1057      */
1058     public org.w3c.dom.Node getContextNode()
1059     {
1060       int context = getCurrentNode();
1061 
1062       return getDTM(context).getNode(context);
1063     }
1064 
1065     /**
1066      * Get the current context node list.
1067      * @return An iterator for the current context list, as
1068      * defined in XSLT.
1069      */
1070     public org.w3c.dom.traversal.NodeIterator getContextNodes()
1071     {
1072       return new com.sun.org.apache.xml.internal.dtm.ref.DTMNodeIterator(getContextNodeList());
1073     }
1074 
1075     /**
1076      * Get the error listener.
1077      * @return The registered error listener.
1078      */
1079     public ErrorListener getErrorListener()
1080     {
1081       return XPathContext.this.getErrorListener();
1082     }
1083     /**
1084      * Return the state of the services mechanism feature.
1085      */
1086     public boolean useServicesMechnism() {
1087         return m_useServicesMechanism;
1088     }
1089 
1090     /**
1091      * Set the state of the services mechanism feature.
1092      */
1093     public void setServicesMechnism(boolean flag) {
1094         m_useServicesMechanism = flag;
1095     }
1096 
1097     /**
1098      * Get the value of a node as a number.
1099      * @param n Node to be converted to a number.  May be null.
1100      * @return value of n as a number.
1101      */
1102     public double toNumber(org.w3c.dom.Node n)
1103     {
1104       // %REVIEW% You can't get much uglier than this...
1105       int nodeHandle = getDTMHandleFromNode(n);
1106       DTM dtm = getDTM(nodeHandle);
1107       XString xobj = (XString)dtm.getStringValue(nodeHandle);
1108       return xobj.num();
1109     }
1110 
1111     /**
1112      * Get the value of a node as a string.
1113      * @param n Node to be converted to a string.  May be null.
1114      * @return value of n as a string, or an empty string if n is null.
1115      */
1116     public String toString(org.w3c.dom.Node n)
1117     {
1118       // %REVIEW% You can't get much uglier than this...
1119       int nodeHandle = getDTMHandleFromNode(n);
1120       DTM dtm = getDTM(nodeHandle);
1121       XMLString strVal = dtm.getStringValue(nodeHandle);
1122       return strVal.toString();
1123     }
1124 
1125     /**
1126      * Get a variable based on it's qualified name.
1127      * @param qname The qualified name of the variable.
1128      * @return The evaluated value of the variable.
1129      * @throws javax.xml.transform.TransformerException
1130      */
1131 
1132     public final XObject getVariableOrParam(com.sun.org.apache.xml.internal.utils.QName qname)
1133               throws javax.xml.transform.TransformerException
1134     {
1135       return m_variableStacks.getVariableOrParam(XPathContext.this, qname);
1136     }
1137 
1138   }
1139 
1140  /**
1141    * Get a DTM to be used as a container for a global Result Tree
1142    * Fragment. This will always be an instance of (derived from? equivalent to?)
1143    * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX
1144    * output to it. It may be a single DTM containing for multiple fragments,
1145    * if the implementation supports that.
1146    *
1147    * Note: The distinction between this method and getRTFDTM() is that the latter
1148    * allocates space from the dynamic variable stack (m_rtfdtm_stack), which may
1149    * be pruned away again as the templates which defined those variables are exited.
1150    * Global variables may be bound late (see XUnresolvedVariable), and never want to
1151    * be discarded, hence we need to allocate them separately and don't actually need
1152    * a stack to track them.
1153    *
1154    * @return a non-null DTM reference.
1155    */
1156   public DTM getGlobalRTFDTM()
1157   {
1158         // We probably should _NOT_ be applying whitespace filtering at this stage!
1159         //
1160         // Some magic has been applied in DTMManagerDefault to recognize this set of options
1161         // and generate an instance of DTM which can contain multiple documents
1162         // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but
1163         // I didn't want to change the manager API at this time, or expose
1164         // too many dependencies on its internals. (Ideally, I'd like to move
1165         // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly
1166         // specify the subclass here.)
1167 
1168         // If it doesn't exist, or if the one already existing is in the middle of
1169         // being constructed, we need to obtain a new DTM to write into. I'm not sure
1170         // the latter will ever arise, but I'd rather be just a bit paranoid..
1171         if( m_global_rtfdtm==null || m_global_rtfdtm.isTreeIncomplete() )
1172         {
1173                 m_global_rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1174         }
1175     return m_global_rtfdtm;
1176   }
1177 
1178 
1179 
1180 
1181   /**
1182    * Get a DTM to be used as a container for a dynamic Result Tree
1183    * Fragment. This will always be an instance of (derived from? equivalent to?)
1184    * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX
1185    * output to it. It may be a single DTM containing for multiple fragments,
1186    * if the implementation supports that.
1187    *
1188    * @return a non-null DTM reference.
1189    */
1190   public DTM getRTFDTM()
1191   {
1192         SAX2RTFDTM rtfdtm;
1193 
1194         // We probably should _NOT_ be applying whitespace filtering at this stage!
1195         //
1196         // Some magic has been applied in DTMManagerDefault to recognize this set of options
1197         // and generate an instance of DTM which can contain multiple documents
1198         // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but
1199         // I didn't want to change the manager API at this time, or expose
1200         // too many dependencies on its internals. (Ideally, I'd like to move
1201         // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly
1202         // specify the subclass here.)
1203 
1204         if(m_rtfdtm_stack==null)
1205         {
1206                 m_rtfdtm_stack=new Vector();
1207                 rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1208     m_rtfdtm_stack.addElement(rtfdtm);
1209                 ++m_which_rtfdtm;
1210         }
1211         else if(m_which_rtfdtm<0)
1212         {
1213                 rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(++m_which_rtfdtm);
1214         }
1215         else
1216         {
1217                 rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(m_which_rtfdtm);
1218 
1219                 // It might already be under construction -- the classic example would be
1220                 // an xsl:variable which uses xsl:call-template as part of its value. To
1221                 // handle this recursion, we have to start a new RTF DTM, pushing the old
1222                 // one onto a stack so we can return to it. This is not as uncommon a case
1223                 // as we might wish, unfortunately, as some folks insist on coding XSLT
1224                 // as if it were a procedural language...
1225                 if(rtfdtm.isTreeIncomplete())
1226                 {
1227                         if(++m_which_rtfdtm < m_rtfdtm_stack.size())
1228                                 rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(m_which_rtfdtm);
1229                         else
1230                         {
1231                                 rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1232           m_rtfdtm_stack.addElement(rtfdtm);
1233                         }
1234                 }
1235         }
1236 
1237     return rtfdtm;
1238   }
1239 
1240   /** Push the RTFDTM's context mark, to allows discarding RTFs added after this
1241    * point. (If it doesn't exist we don't push, since we might still be able to
1242    * get away with not creating it. That requires that excessive pops be harmless.)
1243    * */
1244   public void pushRTFContext()
1245   {
1246         m_last_pushed_rtfdtm.push(m_which_rtfdtm);
1247         if(null!=m_rtfdtm_stack)
1248                 ((SAX2RTFDTM)(getRTFDTM())).pushRewindMark();
1249   }
1250 
1251   /** Pop the RTFDTM's context mark. This discards any RTFs added after the last
1252    * mark was set.
1253    *
1254    * If there is no RTF DTM, there's nothing to pop so this
1255    * becomes a no-op. If pushes were issued before this was called, we count on
1256    * the fact that popRewindMark is defined such that overpopping just resets
1257    * to empty.
1258    *
1259    * Complicating factor: We need to handle the case of popping back to a previous
1260    * RTF DTM, if one of the weird produce-an-RTF-to-build-an-RTF cases arose.
1261    * Basically: If pop says this DTM is now empty, then return to the previous
1262    * if one exists, in whatever state we left it in. UGLY, but hopefully the
1263    * situation which forces us to consider this will arise exceedingly rarely.
1264    * */
1265   public void popRTFContext()
1266   {
1267         int previous=m_last_pushed_rtfdtm.pop();
1268         if(null==m_rtfdtm_stack)
1269                 return;
1270 
1271         if(m_which_rtfdtm==previous)
1272         {
1273                 if(previous>=0) // guard against none-active
1274                 {
1275                         boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.elementAt(previous))).popRewindMark();
1276                 }
1277         }
1278         else while(m_which_rtfdtm!=previous)
1279         {
1280                 // Empty each DTM before popping, so it's ready for reuse
1281                 // _DON'T_ pop the previous, since it's still open (which is why we
1282                 // stacked up more of these) and did not receive a mark.
1283                 boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.elementAt(m_which_rtfdtm))).popRewindMark();
1284                 --m_which_rtfdtm;
1285         }
1286   }
1287 
1288   /**
1289    * Gets DTMXRTreeFrag object if one has already been created.
1290    * Creates new DTMXRTreeFrag object and adds to m_DTMXRTreeFrags  HashMap,
1291    * otherwise.
1292    * @param dtmIdentity
1293    * @return DTMXRTreeFrag
1294    */
1295   public DTMXRTreeFrag getDTMXRTreeFrag(int dtmIdentity){
1296     if(m_DTMXRTreeFrags == null){
1297       m_DTMXRTreeFrags = new HashMap();
1298     }
1299 
1300     if(m_DTMXRTreeFrags.containsKey(new Integer(dtmIdentity))){
1301        return (DTMXRTreeFrag)m_DTMXRTreeFrags.get(new Integer(dtmIdentity));
1302     }else{
1303       final DTMXRTreeFrag frag = new DTMXRTreeFrag(dtmIdentity,this);
1304       m_DTMXRTreeFrags.put(new Integer(dtmIdentity),frag);
1305       return frag ;
1306     }
1307   }
1308 
1309   /**
1310    * Cleans DTMXRTreeFrag objects by removing references
1311    * to DTM and XPathContext objects.
1312    */
1313   private final void releaseDTMXRTreeFrags(){
1314     if(m_DTMXRTreeFrags == null){
1315       return;
1316     }
1317     final Iterator iter = (m_DTMXRTreeFrags.values()).iterator();
1318     while(iter.hasNext()){
1319       DTMXRTreeFrag frag = (DTMXRTreeFrag)iter.next();
1320       frag.destruct();
1321       iter.remove();
1322     }
1323     m_DTMXRTreeFrags = null;
1324  }
1325 }