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