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