1 /* 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. 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 package com.sun.org.apache.xpath.internal; 22 23 import com.sun.org.apache.xalan.internal.extensions.ExpressionContext; 24 import com.sun.org.apache.xalan.internal.res.XSLMessages; 25 import com.sun.org.apache.xml.internal.dtm.Axis; 26 import com.sun.org.apache.xml.internal.dtm.DTM; 27 import com.sun.org.apache.xml.internal.dtm.DTMFilter; 28 import com.sun.org.apache.xml.internal.dtm.DTMIterator; 29 import com.sun.org.apache.xml.internal.dtm.DTMManager; 30 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; 31 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2RTFDTM; 32 import com.sun.org.apache.xml.internal.utils.IntStack; 33 import com.sun.org.apache.xml.internal.utils.NodeVector; 34 import com.sun.org.apache.xml.internal.utils.ObjectStack; 35 import com.sun.org.apache.xml.internal.utils.PrefixResolver; 36 import com.sun.org.apache.xml.internal.utils.XMLString; 37 import com.sun.org.apache.xpath.internal.axes.SubContextList; 38 import com.sun.org.apache.xpath.internal.objects.DTMXRTreeFrag; 39 import com.sun.org.apache.xpath.internal.objects.XObject; 40 import com.sun.org.apache.xpath.internal.objects.XString; 41 import com.sun.org.apache.xpath.internal.res.XPATHErrorResources; 42 import java.lang.reflect.Method; 43 import java.util.ArrayList; 44 import java.util.HashMap; 45 import java.util.Iterator; 46 import java.util.List; 47 import java.util.Map; 48 import java.util.Stack; 49 import javax.xml.transform.ErrorListener; 50 import javax.xml.transform.SourceLocator; 51 import javax.xml.transform.URIResolver; 52 import org.xml.sax.XMLReader; 53 54 /** 55 * Default class for the runtime execution context for XPath. 56 * 57 * <p>This class extends DTMManager but does not directly implement it.</p> 58 * @xsl.usage advanced 59 * @LastModified: Jan 2019 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_overrideDefaultParser; 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(false); 309 } 310 311 public XPathContext(boolean overrideDefaultParser) { 312 init(overrideDefaultParser); 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(false); 328 } 329 330 private void init(boolean overrideDefaultParser) { 331 m_prefixResolvers.push(null); 332 m_currentNodes.push(DTM.NULL); 333 m_currentExpressionNodes.push(DTM.NULL); 334 m_saxLocations.push(null); 335 m_overrideDefaultParser = overrideDefaultParser; 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 // ================================================= 486 487 /** The ErrorListener where errors and warnings are to be reported. */ 488 private ErrorListener m_errorListener; 489 490 /** A default ErrorListener in case our m_errorListener was not specified and our 491 * owner either does not have an ErrorListener or has a null one. 492 */ 493 private ErrorListener m_defaultErrorListener; 494 495 /** 496 * Get the ErrorListener where errors and warnings are to be reported. 497 * 498 * @return A non-null ErrorListener reference. 499 */ 500 public final ErrorListener getErrorListener() 501 { 502 503 if (null != m_errorListener) 504 return m_errorListener; 505 506 ErrorListener retval = null; 507 508 try { 509 if (null != m_ownerGetErrorListener) 510 retval = (ErrorListener) m_ownerGetErrorListener.invoke(m_owner, new Object[] {}); 511 } 512 catch (Exception e) {} 513 514 if (null == retval) 515 { 516 if (null == m_defaultErrorListener) 517 m_defaultErrorListener = new com.sun.org.apache.xml.internal.utils.DefaultErrorHandler(); 518 retval = m_defaultErrorListener; 519 } 520 521 return retval; 522 } 523 524 /** 525 * Set the ErrorListener where errors and warnings are to be reported. 526 * 527 * @param listener A non-null ErrorListener reference. 528 */ 529 public void setErrorListener(ErrorListener listener) throws IllegalArgumentException 530 { 531 if (listener == null) 532 throw new IllegalArgumentException(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler"); 533 m_errorListener = listener; 534 } 535 536 537 // ================================================= 538 539 /** The TrAX URI Resolver for resolving URIs from the document(...) 540 * function to source tree nodes. */ 541 private URIResolver m_uriResolver; 542 543 /** 544 * Get the URIResolver associated with this execution context. 545 * 546 * @return a URI resolver, which may be null. 547 */ 548 public final URIResolver getURIResolver() 549 { 550 return m_uriResolver; 551 } 552 553 /** 554 * Set the URIResolver associated with this execution context. 555 * 556 * @param resolver the URIResolver to be associated with this 557 * execution context, may be null to clear an already set resolver. 558 */ 559 public void setURIResolver(URIResolver resolver) 560 { 561 m_uriResolver = resolver; 562 } 563 564 // ================================================= 565 566 /** The reader of the primary source tree. */ 567 public XMLReader m_primaryReader; 568 569 /** 570 * Get primary XMLReader associated with this execution context. 571 * 572 * @return The reader of the primary source tree. 573 */ 574 public final XMLReader getPrimaryReader() 575 { 576 return m_primaryReader; 577 } 578 579 /** 580 * Set primary XMLReader associated with this execution context. 581 * 582 * @param reader The reader of the primary source tree. 583 */ 584 public void setPrimaryReader(XMLReader reader) 585 { 586 m_primaryReader = reader; 587 } 588 589 // ================================================= 590 591 592 /** Misnamed string manager for XPath messages. */ 593 // private static XSLMessages m_XSLMessages = new XSLMessages(); 594 595 //========================================================== 596 // SECTION: Execution context state tracking 597 //========================================================== 598 599 /** 600 * The current context node list. 601 */ 602 private Stack<DTMIterator> m_contextNodeLists = new Stack<>(); 603 604 public Stack<DTMIterator> getContextNodeListsStack() { return m_contextNodeLists; } 605 public void setContextNodeListsStack(Stack<DTMIterator> s) { m_contextNodeLists = s; } 606 607 /** 608 * Get the current context node list. 609 * 610 * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>, 611 * also referred to here as a <term>context node list</term>. 612 */ 613 public final DTMIterator getContextNodeList() 614 { 615 616 if (m_contextNodeLists.size() > 0) 617 return m_contextNodeLists.peek(); 618 else 619 return null; 620 } 621 622 /** 623 * Set the current context node list. 624 * 625 * @param nl the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>, 626 * also referred to here as a <term>context node list</term>. 627 * @xsl.usage internal 628 */ 629 public final void pushContextNodeList(DTMIterator nl) 630 { 631 m_contextNodeLists.push(nl); 632 } 633 634 /** 635 * Pop the current context node list. 636 * @xsl.usage internal 637 */ 638 public final void popContextNodeList() 639 { 640 if(m_contextNodeLists.isEmpty()) 641 System.err.println("Warning: popContextNodeList when stack is empty!"); 642 else 643 m_contextNodeLists.pop(); 644 } 645 646 /** 647 * The amount to use for stacks that record information during the 648 * recursive execution. 649 */ 650 public static final int RECURSIONLIMIT = (1024*4); 651 652 /** The stack of <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a> objects. 653 * Not to be confused with the current node list. %REVIEW% Note that there 654 * are no bounds check and resize for this stack, so if it is blown, it's all 655 * over. */ 656 private IntStack m_currentNodes = new IntStack(RECURSIONLIMIT); 657 658 // private NodeVector m_currentNodes = new NodeVector(); 659 660 public IntStack getCurrentNodeStack() {return m_currentNodes; } 661 public void setCurrentNodeStack(IntStack nv) { m_currentNodes = nv; } 662 663 /** 664 * Get the current context node. 665 * 666 * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>. 667 */ 668 public final int getCurrentNode() 669 { 670 return m_currentNodes.peek(); 671 } 672 673 /** 674 * Set the current context node and expression node. 675 * 676 * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>. 677 * @param en the sub-expression context node. 678 */ 679 public final void pushCurrentNodeAndExpression(int cn, int en) 680 { 681 m_currentNodes.push(cn); 682 m_currentExpressionNodes.push(cn); 683 } 684 685 /** 686 * Set the current context node. 687 */ 688 public final void popCurrentNodeAndExpression() 689 { 690 m_currentNodes.quickPop(1); 691 m_currentExpressionNodes.quickPop(1); 692 } 693 694 /** 695 * Push the current context node, expression node, and prefix resolver. 696 * 697 * @param cn the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>. 698 * @param en the sub-expression context node. 699 * @param nc the namespace context (prefix resolver. 700 */ 701 public final void pushExpressionState(int cn, int en, PrefixResolver nc) 702 { 703 m_currentNodes.push(cn); 704 m_currentExpressionNodes.push(cn); 705 m_prefixResolvers.push(nc); 706 } 707 708 /** 709 * Pop the current context node, expression node, and prefix resolver. 710 */ 711 public final void popExpressionState() 712 { 713 m_currentNodes.quickPop(1); 714 m_currentExpressionNodes.quickPop(1); 715 m_prefixResolvers.pop(); 716 } 717 718 719 720 /** 721 * Set the current context node. 722 * 723 * @param n the <a href="http://www.w3.org/TR/xslt#dt-current-node">current node</a>. 724 */ 725 public final void pushCurrentNode(int n) 726 { 727 m_currentNodes.push(n); 728 } 729 730 /** 731 * Pop the current context node. 732 */ 733 public final void popCurrentNode() 734 { 735 m_currentNodes.quickPop(1); 736 } 737 738 /** 739 * Set the current predicate root. 740 */ 741 public final void pushPredicateRoot(int n) 742 { 743 m_predicateRoots.push(n); 744 } 745 746 /** 747 * Pop the current predicate root. 748 */ 749 public final void popPredicateRoot() 750 { 751 m_predicateRoots.popQuick(); 752 } 753 754 /** 755 * Get the current predicate root. 756 */ 757 public final int getPredicateRoot() 758 { 759 return m_predicateRoots.peepOrNull(); 760 } 761 762 /** 763 * Set the current location path iterator root. 764 */ 765 public final void pushIteratorRoot(int n) 766 { 767 m_iteratorRoots.push(n); 768 } 769 770 /** 771 * Pop the current location path iterator root. 772 */ 773 public final void popIteratorRoot() 774 { 775 m_iteratorRoots.popQuick(); 776 } 777 778 /** 779 * Get the current location path iterator root. 780 */ 781 public final int getIteratorRoot() 782 { 783 return m_iteratorRoots.peepOrNull(); 784 } 785 786 /** A stack of the current sub-expression nodes. */ 787 private NodeVector m_iteratorRoots = new NodeVector(); 788 789 /** A stack of the current sub-expression nodes. */ 790 private NodeVector m_predicateRoots = new NodeVector(); 791 792 /** A stack of the current sub-expression nodes. */ 793 private IntStack m_currentExpressionNodes = new IntStack(RECURSIONLIMIT); 794 795 796 public IntStack getCurrentExpressionNodeStack() { return m_currentExpressionNodes; } 797 public void setCurrentExpressionNodeStack(IntStack nv) { m_currentExpressionNodes = nv; } 798 799 private IntStack m_predicatePos = new IntStack(); 800 801 public final int getPredicatePos() 802 { 803 return m_predicatePos.peek(); 804 } 805 806 public final void pushPredicatePos(int n) 807 { 808 m_predicatePos.push(n); 809 } 810 811 public final void popPredicatePos() 812 { 813 m_predicatePos.pop(); 814 } 815 816 /** 817 * Get the current node that is the expression's context (i.e. for current() support). 818 * 819 * @return The current sub-expression node. 820 */ 821 public final int getCurrentExpressionNode() 822 { 823 return m_currentExpressionNodes.peek(); 824 } 825 826 /** 827 * Set the current node that is the expression's context (i.e. for current() support). 828 * 829 * @param n The sub-expression node to be current. 830 */ 831 public final void pushCurrentExpressionNode(int n) 832 { 833 m_currentExpressionNodes.push(n); 834 } 835 836 /** 837 * Pop the current node that is the expression's context 838 * (i.e. for current() support). 839 */ 840 public final void popCurrentExpressionNode() 841 { 842 m_currentExpressionNodes.quickPop(1); 843 } 844 845 private ObjectStack m_prefixResolvers 846 = new ObjectStack(RECURSIONLIMIT); 847 848 /** 849 * Get the current namespace context for the xpath. 850 * 851 * @return the current prefix resolver for resolving prefixes to 852 * namespace URLs. 853 */ 854 public final PrefixResolver getNamespaceContext() 855 { 856 return (PrefixResolver) m_prefixResolvers.peek(); 857 } 858 859 /** 860 * Get the current namespace context for the xpath. 861 * 862 * @param pr the prefix resolver to be used for resolving prefixes to 863 * namespace URLs. 864 */ 865 public final void setNamespaceContext(PrefixResolver pr) 866 { 867 m_prefixResolvers.setTop(pr); 868 } 869 870 /** 871 * Push a current namespace context for the xpath. 872 * 873 * @param pr the prefix resolver to be used for resolving prefixes to 874 * namespace URLs. 875 */ 876 public final void pushNamespaceContext(PrefixResolver pr) 877 { 878 m_prefixResolvers.push(pr); 879 } 880 881 /** 882 * Just increment the namespace contest stack, so that setNamespaceContext 883 * can be used on the slot. 884 */ 885 public final void pushNamespaceContextNull() 886 { 887 m_prefixResolvers.push(null); 888 } 889 890 /** 891 * Pop the current namespace context for the xpath. 892 */ 893 public final void popNamespaceContext() 894 { 895 m_prefixResolvers.pop(); 896 } 897 898 //========================================================== 899 // SECTION: Current TreeWalker contexts (for internal use) 900 //========================================================== 901 902 /** 903 * Stack of AxesIterators. 904 */ 905 private Stack<SubContextList> m_axesIteratorStack = new Stack<>(); 906 907 public Stack<SubContextList> getAxesIteratorStackStacks() { return m_axesIteratorStack; } 908 public void setAxesIteratorStackStacks(Stack<SubContextList> s) { m_axesIteratorStack = s; } 909 910 /** 911 * Push a TreeWalker on the stack. 912 * 913 * @param iter A sub-context AxesWalker. 914 * @xsl.usage internal 915 */ 916 public final void pushSubContextList(SubContextList iter) 917 { 918 m_axesIteratorStack.push(iter); 919 } 920 921 /** 922 * Pop the last pushed axes iterator. 923 * @xsl.usage internal 924 */ 925 public final void popSubContextList() 926 { 927 m_axesIteratorStack.pop(); 928 } 929 930 /** 931 * Get the current axes iterator, or return null if none. 932 * 933 * @return the sub-context node list. 934 * @xsl.usage internal 935 */ 936 public SubContextList getSubContextList() 937 { 938 return m_axesIteratorStack.isEmpty() ? null : m_axesIteratorStack.peek(); 939 } 940 941 /** 942 * Get the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a> 943 * as defined by the XSLT spec. 944 * 945 * @return the <a href="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>. 946 * @xsl.usage internal 947 */ 948 949 public com.sun.org.apache.xpath.internal.axes.SubContextList getCurrentNodeList() 950 { 951 return m_axesIteratorStack.isEmpty() ? null : m_axesIteratorStack.get(0); 952 } 953 //========================================================== 954 // SECTION: Implementation of ExpressionContext interface 955 //========================================================== 956 957 /** 958 * Get the current context node. 959 * @return The current context node. 960 */ 961 public final int getContextNode() 962 { 963 return this.getCurrentNode(); 964 } 965 966 /** 967 * Get the current context node list. 968 * @return An iterator for the current context list, as 969 * defined in XSLT. 970 */ 971 public final DTMIterator getContextNodes() 972 { 973 974 try 975 { 976 DTMIterator cnl = getContextNodeList(); 977 978 if (null != cnl) 979 return cnl.cloneWithReset(); 980 else 981 return null; // for now... this might ought to be an empty iterator. 982 } 983 catch (CloneNotSupportedException cnse) 984 { 985 return null; // error reporting? 986 } 987 } 988 989 XPathExpressionContext expressionContext = new XPathExpressionContext(); 990 991 /** 992 * The the expression context for extensions for this context. 993 * 994 * @return An object that implements the ExpressionContext. 995 */ 996 public ExpressionContext getExpressionContext() 997 { 998 return expressionContext; 999 } 1000 1001 public class XPathExpressionContext implements ExpressionContext 1002 { 1003 /** 1004 * Return the XPathContext associated with this XPathExpressionContext. 1005 * Extensions should use this judiciously and only when special processing 1006 * requirements cannot be met another way. Consider requesting an enhancement 1007 * to the ExpressionContext interface to avoid having to call this method. 1008 * @return the XPathContext associated with this XPathExpressionContext. 1009 */ 1010 public XPathContext getXPathContext() 1011 { 1012 return XPathContext.this; 1013 } 1014 1015 /** 1016 * Return the DTMManager object. Though XPathContext context extends 1017 * the DTMManager, it really is a proxy for the real DTMManager. If a 1018 * caller needs to make a lot of calls to the DTMManager, it is faster 1019 * if it gets the real one from this function. 1020 */ 1021 public DTMManager getDTMManager() 1022 { 1023 return m_dtmManager; 1024 } 1025 1026 /** 1027 * Get the current context node. 1028 * @return The current context node. 1029 */ 1030 public org.w3c.dom.Node getContextNode() 1031 { 1032 int context = getCurrentNode(); 1033 1034 return getDTM(context).getNode(context); 1035 } 1036 1037 /** 1038 * Get the current context node list. 1039 * @return An iterator for the current context list, as 1040 * defined in XSLT. 1041 */ 1042 public org.w3c.dom.traversal.NodeIterator getContextNodes() 1043 { 1044 return new com.sun.org.apache.xml.internal.dtm.ref.DTMNodeIterator(getContextNodeList()); 1045 } 1046 1047 /** 1048 * Get the error listener. 1049 * @return The registered error listener. 1050 */ 1051 public ErrorListener getErrorListener() 1052 { 1053 return XPathContext.this.getErrorListener(); 1054 } 1055 /** 1056 * Return the state of the services mechanism feature. 1057 */ 1058 public boolean overrideDefaultParser() { 1059 return m_overrideDefaultParser; 1060 } 1061 1062 /** 1063 * Set the state of the services mechanism feature. 1064 */ 1065 public void setOverrideDefaultParser(boolean flag) { 1066 m_overrideDefaultParser = flag; 1067 } 1068 1069 /** 1070 * Get the value of a node as a number. 1071 * @param n Node to be converted to a number. May be null. 1072 * @return value of n as a number. 1073 */ 1074 public double toNumber(org.w3c.dom.Node n) 1075 { 1076 // %REVIEW% You can't get much uglier than this... 1077 int nodeHandle = getDTMHandleFromNode(n); 1078 DTM dtm = getDTM(nodeHandle); 1079 XString xobj = (XString)dtm.getStringValue(nodeHandle); 1080 return xobj.num(); 1081 } 1082 1083 /** 1084 * Get the value of a node as a string. 1085 * @param n Node to be converted to a string. May be null. 1086 * @return value of n as a string, or an empty string if n is null. 1087 */ 1088 public String toString(org.w3c.dom.Node n) 1089 { 1090 // %REVIEW% You can't get much uglier than this... 1091 int nodeHandle = getDTMHandleFromNode(n); 1092 DTM dtm = getDTM(nodeHandle); 1093 XMLString strVal = dtm.getStringValue(nodeHandle); 1094 return strVal.toString(); 1095 } 1096 1097 /** 1098 * Get a variable based on it's qualified name. 1099 * @param qname The qualified name of the variable. 1100 * @return The evaluated value of the variable. 1101 * @throws javax.xml.transform.TransformerException 1102 */ 1103 1104 public final XObject getVariableOrParam(com.sun.org.apache.xml.internal.utils.QName qname) 1105 throws javax.xml.transform.TransformerException 1106 { 1107 return m_variableStacks.getVariableOrParam(XPathContext.this, qname); 1108 } 1109 1110 } 1111 1112 /** 1113 * Get a DTM to be used as a container for a global Result Tree 1114 * Fragment. This will always be an instance of (derived from? equivalent to?) 1115 * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX 1116 * output to it. It may be a single DTM containing for multiple fragments, 1117 * if the implementation supports that. 1118 * 1119 * Note: The distinction between this method and getRTFDTM() is that the latter 1120 * allocates space from the dynamic variable stack (m_rtfdtm_stack), which may 1121 * be pruned away again as the templates which defined those variables are exited. 1122 * Global variables may be bound late (see XUnresolvedVariable), and never want to 1123 * be discarded, hence we need to allocate them separately and don't actually need 1124 * a stack to track them. 1125 * 1126 * @return a non-null DTM reference. 1127 */ 1128 public DTM getGlobalRTFDTM() 1129 { 1130 // We probably should _NOT_ be applying whitespace filtering at this stage! 1131 // 1132 // Some magic has been applied in DTMManagerDefault to recognize this set of options 1133 // and generate an instance of DTM which can contain multiple documents 1134 // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but 1135 // I didn't want to change the manager API at this time, or expose 1136 // too many dependencies on its internals. (Ideally, I'd like to move 1137 // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly 1138 // specify the subclass here.) 1139 1140 // If it doesn't exist, or if the one already existing is in the middle of 1141 // being constructed, we need to obtain a new DTM to write into. I'm not sure 1142 // the latter will ever arise, but I'd rather be just a bit paranoid.. 1143 if( m_global_rtfdtm==null || m_global_rtfdtm.isTreeIncomplete() ) 1144 { 1145 m_global_rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false); 1146 } 1147 return m_global_rtfdtm; 1148 } 1149 1150 1151 1152 1153 /** 1154 * Get a DTM to be used as a container for a dynamic Result Tree 1155 * Fragment. This will always be an instance of (derived from? equivalent to?) 1156 * SAX2DTM, since each RTF is constructed by temporarily redirecting our SAX 1157 * output to it. It may be a single DTM containing for multiple fragments, 1158 * if the implementation supports that. 1159 * 1160 * @return a non-null DTM reference. 1161 */ 1162 public DTM getRTFDTM() 1163 { 1164 SAX2RTFDTM rtfdtm; 1165 1166 // We probably should _NOT_ be applying whitespace filtering at this stage! 1167 // 1168 // Some magic has been applied in DTMManagerDefault to recognize this set of options 1169 // and generate an instance of DTM which can contain multiple documents 1170 // (SAX2RTFDTM). Perhaps not the optimal way of achieving that result, but 1171 // I didn't want to change the manager API at this time, or expose 1172 // too many dependencies on its internals. (Ideally, I'd like to move 1173 // isTreeIncomplete all the way up to DTM, so we wouldn't need to explicitly 1174 // specify the subclass here.) 1175 1176 if(m_rtfdtm_stack==null) 1177 { 1178 m_rtfdtm_stack=new ArrayList<>(); 1179 rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false); 1180 m_rtfdtm_stack.add(rtfdtm); 1181 ++m_which_rtfdtm; 1182 } 1183 else if(m_which_rtfdtm<0) 1184 { 1185 rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(++m_which_rtfdtm); 1186 } 1187 else 1188 { 1189 rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(m_which_rtfdtm); 1190 1191 // It might already be under construction -- the classic example would be 1192 // an xsl:variable which uses xsl:call-template as part of its value. To 1193 // handle this recursion, we have to start a new RTF DTM, pushing the old 1194 // one onto a stack so we can return to it. This is not as uncommon a case 1195 // as we might wish, unfortunately, as some folks insist on coding XSLT 1196 // as if it were a procedural language... 1197 if(rtfdtm.isTreeIncomplete()) 1198 { 1199 if(++m_which_rtfdtm < m_rtfdtm_stack.size()) 1200 rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.get(m_which_rtfdtm); 1201 else 1202 { 1203 rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false); 1204 m_rtfdtm_stack.add(rtfdtm); 1205 } 1206 } 1207 } 1208 1209 return rtfdtm; 1210 } 1211 1212 /** Push the RTFDTM's context mark, to allows discarding RTFs added after this 1213 * point. (If it doesn't exist we don't push, since we might still be able to 1214 * get away with not creating it. That requires that excessive pops be harmless.) 1215 * */ 1216 public void pushRTFContext() 1217 { 1218 m_last_pushed_rtfdtm.push(m_which_rtfdtm); 1219 if(null!=m_rtfdtm_stack) 1220 ((SAX2RTFDTM)(getRTFDTM())).pushRewindMark(); 1221 } 1222 1223 /** Pop the RTFDTM's context mark. This discards any RTFs added after the last 1224 * mark was set. 1225 * 1226 * If there is no RTF DTM, there's nothing to pop so this 1227 * becomes a no-op. If pushes were issued before this was called, we count on 1228 * the fact that popRewindMark is defined such that overpopping just resets 1229 * to empty. 1230 * 1231 * Complicating factor: We need to handle the case of popping back to a previous 1232 * RTF DTM, if one of the weird produce-an-RTF-to-build-an-RTF cases arose. 1233 * Basically: If pop says this DTM is now empty, then return to the previous 1234 * if one exists, in whatever state we left it in. UGLY, but hopefully the 1235 * situation which forces us to consider this will arise exceedingly rarely. 1236 * */ 1237 public void popRTFContext() 1238 { 1239 int previous=m_last_pushed_rtfdtm.pop(); 1240 if(null==m_rtfdtm_stack) 1241 return; 1242 1243 if(m_which_rtfdtm==previous) 1244 { 1245 if(previous>=0) // guard against none-active 1246 { 1247 boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.get(previous))).popRewindMark(); 1248 } 1249 } 1250 else while(m_which_rtfdtm!=previous) 1251 { 1252 // Empty each DTM before popping, so it's ready for reuse 1253 // _DON'T_ pop the previous, since it's still open (which is why we 1254 // stacked up more of these) and did not receive a mark. 1255 boolean isEmpty=((SAX2RTFDTM)(m_rtfdtm_stack.get(m_which_rtfdtm))).popRewindMark(); 1256 --m_which_rtfdtm; 1257 } 1258 } 1259 1260 /** 1261 * Gets DTMXRTreeFrag object if one has already been created. 1262 * Creates new DTMXRTreeFrag object and adds to m_DTMXRTreeFrags HashMap, 1263 * otherwise. 1264 * @param dtmIdentity 1265 * @return DTMXRTreeFrag 1266 */ 1267 public DTMXRTreeFrag getDTMXRTreeFrag(int dtmIdentity){ 1268 if(m_DTMXRTreeFrags == null){ 1269 m_DTMXRTreeFrags = new HashMap<>(); 1270 } 1271 1272 if(m_DTMXRTreeFrags.containsKey(dtmIdentity)){ 1273 return m_DTMXRTreeFrags.get(dtmIdentity); 1274 }else{ 1275 final DTMXRTreeFrag frag = new DTMXRTreeFrag(dtmIdentity,this); 1276 m_DTMXRTreeFrags.put(dtmIdentity,frag); 1277 return frag ; 1278 } 1279 } 1280 1281 /** 1282 * Cleans DTMXRTreeFrag objects by removing references 1283 * to DTM and XPathContext objects. 1284 */ 1285 private final void releaseDTMXRTreeFrags(){ 1286 if(m_DTMXRTreeFrags == null){ 1287 return; 1288 } 1289 final Iterator<DTMXRTreeFrag> iter = (m_DTMXRTreeFrags.values()).iterator(); 1290 while(iter.hasNext()){ 1291 DTMXRTreeFrag frag = iter.next(); 1292 frag.destruct(); 1293 iter.remove(); 1294 } 1295 m_DTMXRTreeFrags = null; 1296 } 1297 }