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 }
--- EOF ---