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 }