KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > XPathContext


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 org.apache.xpath;
20
21 import java.lang.reflect.Method JavaDoc;
22 import java.util.Stack JavaDoc;
23 import java.util.Vector JavaDoc;
24
25 import javax.xml.transform.ErrorListener JavaDoc;
26 import javax.xml.transform.SourceLocator JavaDoc;
27 import javax.xml.transform.TransformerException JavaDoc;
28 import javax.xml.transform.URIResolver JavaDoc;
29
30 import org.apache.xalan.extensions.ExpressionContext;
31 import org.apache.xalan.res.XSLMessages;
32 import org.apache.xml.dtm.Axis;
33 import org.apache.xml.dtm.DTM;
34 import org.apache.xml.dtm.DTMFilter;
35 import org.apache.xml.dtm.DTMIterator;
36 import org.apache.xml.dtm.DTMManager;
37 import org.apache.xml.dtm.DTMWSFilter;
38 import org.apache.xml.dtm.ref.sax2dtm.SAX2RTFDTM;
39 import org.apache.xml.utils.IntStack;
40 import org.apache.xml.utils.NodeVector;
41 import org.apache.xml.utils.ObjectStack;
42 import org.apache.xml.utils.PrefixResolver;
43 import org.apache.xml.utils.SAXSourceLocator;
44 import org.apache.xml.utils.XMLString;
45 import org.apache.xpath.axes.SubContextList;
46 import org.apache.xpath.objects.XObject;
47 import org.apache.xpath.objects.XString;
48 import org.apache.xpath.res.XPATHErrorResources;
49
50 import org.xml.sax.XMLReader JavaDoc;
51
52 /**
53  * Default class for the runtime execution context for XPath.
54  *
55  * <p>This class extends DTMManager but does not directly implement it.</p>
56  * @xsl.usage advanced
57  */

58 public class XPathContext extends DTMManager // implements ExpressionContext
59
{
60     IntStack m_last_pushed_rtfdtm=new IntStack();
61   /**
62    * Stack of cached "reusable" DTMs for Result Tree Fragments.
63    * This is a kluge to handle the problem of starting an RTF before
64    * the old one is complete.
65    *
66    * %REVIEW% I'm using a Vector rather than Stack so we can reuse
67    * the DTMs if the problem occurs multiple times. I'm not sure that's
68    * really a net win versus discarding the DTM and starting a new one...
69    * but the retained RTF DTM will have been tail-pruned so should be small.
70    */

71   private Vector JavaDoc m_rtfdtm_stack=null;
72   /** Index of currently active RTF DTM in m_rtfdtm_stack */
73   private int m_which_rtfdtm=-1;
74   
75  /**
76    * Most recent "reusable" DTM for Global Result Tree Fragments. No stack is
77    * required since we're never going to pop these.
78    */

79   private SAX2RTFDTM m_global_rtfdtm=null;
80   
81     
82   /**
83    * Though XPathContext context extends
84    * the DTMManager, it really is a proxy for this object, which
85    * is the real DTMManager.
86    */

87   protected DTMManager m_dtmManager = DTMManager.newInstance(
88                    org.apache.xpath.objects.XMLStringFactoryImpl.getFactory());
89   
90   /**
91    * Return the DTMManager object. Though XPathContext context extends
92    * the DTMManager, it really is a proxy for the real DTMManager. If a
93    * caller needs to make a lot of calls to the DTMManager, it is faster
94    * if it gets the real one from this function.
95    */

96    public DTMManager getDTMManager()
97    {
98      return m_dtmManager;
99    }
100   
101   /**
102    * Get an instance of a DTM, loaded with the content from the
103    * specified source. If the unique flag is true, a new instance will
104    * always be returned. Otherwise it is up to the DTMManager to return a
105    * new instance or an instance that it already created and may be being used
106    * by someone else.
107    * (I think more parameters will need to be added for error handling, and entity
108    * resolution).
109    *
110    * @param source the specification of the source object, which may be null,
111    * in which case it is assumed that node construction will take
112    * by some other means.
113    * @param unique true if the returned DTM must be unique, probably because it
114    * is going to be mutated.
115    * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
116    * be null.
117    * @param incremental true if the construction should try and be incremental.
118    * @param doIndexing true if the caller considers it worth it to use
119    * indexing schemes.
120    *
121    * @return a non-null DTM reference.
122    */

123   public DTM getDTM(javax.xml.transform.Source JavaDoc source, boolean unique,
124                     DTMWSFilter wsfilter,
125                     boolean incremental,
126                     boolean doIndexing)
127   {
128     return m_dtmManager.getDTM(source, unique, wsfilter,
129                                incremental, doIndexing);
130   }
131                              
132   /**
133    * Get an instance of a DTM that "owns" a node handle.
134    *
135    * @param nodeHandle the nodeHandle.
136    *
137    * @return a non-null DTM reference.
138    */

139   public DTM getDTM(int nodeHandle)
140   {
141     return m_dtmManager.getDTM(nodeHandle);
142   }
143
144   /**
145    * Given a W3C DOM node, try and return a DTM handle.
146    * Note: calling this may be non-optimal.
147    *
148    * @param node Non-null reference to a DOM node.
149    *
150    * @return a valid DTM handle.
151    */

152   public int getDTMHandleFromNode(org.w3c.dom.Node JavaDoc node)
153   {
154     return m_dtmManager.getDTMHandleFromNode(node);
155   }
156 //
157
//
158
/**
159    * %TBD% Doc
160    */

161   public int getDTMIdentity(DTM dtm)
162   {
163     return m_dtmManager.getDTMIdentity(dtm);
164   }
165 //
166
/**
167    * Creates an empty <code>DocumentFragment</code> object.
168    * @return A new <code>DocumentFragment handle</code>.
169    */

170   public DTM createDocumentFragment()
171   {
172     return m_dtmManager.createDocumentFragment();
173   }
174 //
175
/**
176    * Release a DTM either to a lru pool, or completely remove reference.
177    * DTMs without system IDs are always hard deleted.
178    * State: experimental.
179    *
180    * @param dtm The DTM to be released.
181    * @param shouldHardDelete True if the DTM should be removed no matter what.
182    * @return true if the DTM was removed, false if it was put back in a lru pool.
183    */

184   public boolean release(DTM dtm, boolean shouldHardDelete)
185   {
186     // %REVIEW% If it's a DTM which may contain multiple Result Tree
187
// Fragments, we can't discard it unless we know not only that it
188
// is empty, but that the XPathContext itself is going away. So do
189
// _not_ accept the request. (May want to do it as part of
190
// reset(), though.)
191
if(m_rtfdtm_stack!=null && m_rtfdtm_stack.contains(dtm))
192     {
193       return false;
194     }
195     
196     return m_dtmManager.release(dtm, shouldHardDelete);
197   }
198
199   /**
200    * Create a new <code>DTMIterator</code> based on an XPath
201    * <a HREF="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
202    * a <a HREF="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
203    *
204    * @param xpathCompiler ??? Somehow we need to pass in a subpart of the
205    * expression. I hate to do this with strings, since the larger expression
206    * has already been parsed.
207    *
208    * @param pos The position in the expression.
209    * @return The newly created <code>DTMIterator</code>.
210    */

211   public DTMIterator createDTMIterator(Object JavaDoc xpathCompiler, int pos)
212   {
213     return m_dtmManager.createDTMIterator(xpathCompiler, pos);
214   }
215 //
216
/**
217    * Create a new <code>DTMIterator</code> based on an XPath
218    * <a HREF="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
219    * a <a HREF="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
220    *
221    * @param xpathString Must be a valid string expressing a
222    * <a HREF="http://www.w3.org/TR/xpath#NT-LocationPath>LocationPath</a> or
223    * a <a HREF="http://www.w3.org/TR/xpath#NT-UnionExpr">UnionExpr</a>.
224    *
225    * @param presolver An object that can resolve prefixes to namespace URLs.
226    *
227    * @return The newly created <code>DTMIterator</code>.
228    */

229   public DTMIterator createDTMIterator(String JavaDoc xpathString,
230           PrefixResolver presolver)
231   {
232     return m_dtmManager.createDTMIterator(xpathString, presolver);
233   }
234 //
235
/**
236    * Create a new <code>DTMIterator</code> based only on a whatToShow and
237    * a DTMFilter. The traversal semantics are defined as the descendant
238    * access.
239    *
240    * @param whatToShow This flag specifies which node types may appear in
241    * the logical view of the tree presented by the iterator. See the
242    * description of <code>NodeFilter</code> for the set of possible
243    * <code>SHOW_</code> values.These flags can be combined using
244    * <code>OR</code>.
245    * @param filter The <code>NodeFilter</code> to be used with this
246    * <code>TreeWalker</code>, or <code>null</code> to indicate no filter.
247    * @param entityReferenceExpansion The value of this flag determines
248    * whether entity reference nodes are expanded.
249    *
250    * @return The newly created <code>NodeIterator</code>.
251    */

252   public DTMIterator createDTMIterator(int whatToShow,
253           DTMFilter filter, boolean entityReferenceExpansion)
254   {
255     return m_dtmManager.createDTMIterator(whatToShow, filter, entityReferenceExpansion);
256   }
257   
258   /**
259    * Create a new <code>DTMIterator</code> that holds exactly one node.
260    *
261    * @param node The node handle that the DTMIterator will iterate to.
262    *
263    * @return The newly created <code>DTMIterator</code>.
264    */

265   public DTMIterator createDTMIterator(int node)
266   {
267     // DescendantIterator iter = new DescendantIterator();
268
DTMIterator iter = new org.apache.xpath.axes.OneStepIteratorForward(Axis.SELF);
269     iter.setRoot(node, this);
270     return iter;
271     // return m_dtmManager.createDTMIterator(node);
272
}
273
274   /**
275    * Create an XPathContext instance.
276    */

277   public XPathContext()
278   {
279     m_prefixResolvers.push(null);
280     m_currentNodes.push(DTM.NULL);
281     m_currentExpressionNodes.push(DTM.NULL);
282     m_saxLocations.push(null);
283   }
284
285   /**
286    * Create an XPathContext instance.
287    * @param owner Value that can be retrieved via the getOwnerObject() method.
288    * @see #getOwnerObject
289    */

290   public XPathContext(Object JavaDoc owner)
291   {
292     m_owner = owner;
293     try {
294       m_ownerGetErrorListener = m_owner.getClass().getMethod("getErrorListener", new Class JavaDoc[] {});
295     }
296     catch (NoSuchMethodException JavaDoc nsme) {}
297     m_prefixResolvers.push(null);
298     m_currentNodes.push(DTM.NULL);
299     m_currentExpressionNodes.push(DTM.NULL);
300     m_saxLocations.push(null);
301   }
302
303   /**
304    * Reset for new run.
305    */

306   public void reset()
307   {
308     // These couldn't be disposed of earlier (see comments in release()); zap them now.
309
if(m_rtfdtm_stack!=null)
310          for (java.util.Enumeration JavaDoc e = m_rtfdtm_stack.elements() ; e.hasMoreElements() ;)
311             m_dtmManager.release((DTM)e.nextElement(), true);
312
313     m_rtfdtm_stack=null; // drop our references too
314
m_which_rtfdtm=-1;
315     
316     if(m_global_rtfdtm!=null)
317             m_dtmManager.release(m_global_rtfdtm,true);
318     m_global_rtfdtm=null;
319     
320     m_dtmManager = DTMManager.newInstance(
321                    org.apache.xpath.objects.XMLStringFactoryImpl.getFactory());
322                    
323     m_saxLocations.removeAllElements();
324     m_axesIteratorStack.removeAllElements();
325     m_contextNodeLists.removeAllElements();
326     m_currentExpressionNodes.removeAllElements();
327     m_currentNodes.removeAllElements();
328     m_iteratorRoots.RemoveAllNoClear();
329     m_predicatePos.removeAllElements();
330     m_predicateRoots.RemoveAllNoClear();
331     m_prefixResolvers.removeAllElements();
332     
333     m_prefixResolvers.push(null);
334     m_currentNodes.push(DTM.NULL);
335     m_currentExpressionNodes.push(DTM.NULL);
336     m_saxLocations.push(null);
337   }
338
339   /** The current stylesheet locator. */
340   ObjectStack m_saxLocations = new ObjectStack(RECURSIONLIMIT);
341
342   /**
343    * Set the current locater in the stylesheet.
344    *
345    * @param location The location within the stylesheet.
346    */

347   public void setSAXLocator(SourceLocator JavaDoc location)
348   {
349     m_saxLocations.setTop(location);
350   }
351   
352   /**
353    * Set the current locater in the stylesheet.
354    *
355    * @param location The location within the stylesheet.
356    */

357   public void pushSAXLocator(SourceLocator JavaDoc location)
358   {
359     m_saxLocations.push(location);
360   }
361   
362   /**
363    * Push a slot on the locations stack so that setSAXLocator can be
364    * repeatedly called.
365    *
366    * @param location The location within the stylesheet.
367    */

368   public void pushSAXLocatorNull()
369   {
370     m_saxLocations.push(null);
371   }
372
373
374   /**
375    * Pop the current locater.
376    */

377   public void popSAXLocator()
378   {
379     m_saxLocations.pop();
380   }
381
382   /**
383    * Get the current locater in the stylesheet.
384    *
385    * @return The location within the stylesheet, or null if not known.
386    */

387   public SourceLocator JavaDoc getSAXLocator()
388   {
389     return (SourceLocator JavaDoc) m_saxLocations.peek();
390   }
391
392   /** The owner context of this XPathContext. In the case of XSLT, this will be a
393    * Transformer object.
394    */

395   private Object JavaDoc m_owner;
396
397   /** The owner context of this XPathContext. In the case of XSLT, this will be a
398    * Transformer object.
399    */

400   private Method JavaDoc m_ownerGetErrorListener;
401
402   /**
403    * Get the "owner" context of this context, which should be,
404    * in the case of XSLT, the Transformer object. This is needed
405    * so that XSLT functions can get the Transformer.
406    * @return The owner object passed into the constructor, or null.
407    */

408   public Object JavaDoc getOwnerObject()
409   {
410     return m_owner;
411   }
412
413   // ================ VarStack ===================
414

415   /**
416    * The stack of Variable stacks. A VariableStack will be
417    * pushed onto this stack for each template invocation.
418    */

419   private VariableStack m_variableStacks = new VariableStack();
420
421   /**
422    * Get the variable stack, which is in charge of variables and
423    * parameters.
424    *
425    * @return the variable stack, which should not be null.
426    */

427   public final VariableStack getVarStack()
428   {
429     return m_variableStacks;
430   }
431
432   /**
433    * Get the variable stack, which is in charge of variables and
434    * parameters.
435    *
436    * @param varStack non-null reference to the variable stack.
437    */

438   public final void setVarStack(VariableStack varStack)
439   {
440     m_variableStacks = varStack;
441   }
442
443   // ================ SourceTreeManager ===================
444

445   /** The source tree manager, which associates Source objects to source
446    * tree nodes. */

447   private SourceTreeManager m_sourceTreeManager = new SourceTreeManager();
448
449   /**
450    * Get the SourceTreeManager associated with this execution context.
451    *
452    * @return the SourceTreeManager associated with this execution context.
453    */

454   public final SourceTreeManager getSourceTreeManager()
455   {
456     return m_sourceTreeManager;
457   }
458
459   /**
460    * Set the SourceTreeManager associated with this execution context.
461    *
462    * @param mgr the SourceTreeManager to be associated with this
463    * execution context.
464    */

465   public void setSourceTreeManager(SourceTreeManager mgr)
466   {
467     m_sourceTreeManager = mgr;
468   }
469   
470   // =================================================
471

472   /** The ErrorListener where errors and warnings are to be reported. */
473   private ErrorListener JavaDoc m_errorListener;
474
475   /** A default ErrorListener in case our m_errorListener was not specified and our
476    * owner either does not have an ErrorListener or has a null one.
477    */

478   private ErrorListener JavaDoc m_defaultErrorListener;
479
480   /**
481    * Get the ErrorListener where errors and warnings are to be reported.
482    *
483    * @return A non-null ErrorListener reference.
484    */

485   public final ErrorListener JavaDoc getErrorListener()
486   {
487
488     if (null != m_errorListener)
489         return m_errorListener;
490
491     ErrorListener JavaDoc retval = null;
492
493     try {
494       if (null != m_ownerGetErrorListener)
495         retval = (ErrorListener JavaDoc) m_ownerGetErrorListener.invoke(m_owner, new Object JavaDoc[] {});
496     }
497     catch (Exception JavaDoc e) {}
498
499     if (null == retval)
500     {
501       if (null == m_defaultErrorListener)
502         m_defaultErrorListener = new org.apache.xml.utils.DefaultErrorHandler();
503       retval = m_defaultErrorListener;
504     }
505
506     return retval;
507   }
508
509   /**
510    * Set the ErrorListener where errors and warnings are to be reported.
511    *
512    * @param listener A non-null ErrorListener reference.
513    */

514   public void setErrorListener(ErrorListener JavaDoc listener) throws IllegalArgumentException JavaDoc
515   {
516     if (listener == null)
517       throw new IllegalArgumentException JavaDoc(XSLMessages.createXPATHMessage(XPATHErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler");
518
m_errorListener = listener;
519   }
520
521
522   // =================================================
523

524   /** The TrAX URI Resolver for resolving URIs from the document(...)
525    * function to source tree nodes. */

526   private URIResolver JavaDoc m_uriResolver;
527
528   /**
529    * Get the URIResolver associated with this execution context.
530    *
531    * @return a URI resolver, which may be null.
532    */

533   public final URIResolver JavaDoc getURIResolver()
534   {
535     return m_uriResolver;
536   }
537
538   /**
539    * Set the URIResolver associated with this execution context.
540    *
541    * @param resolver the URIResolver to be associated with this
542    * execution context, may be null to clear an already set resolver.
543    */

544   public void setURIResolver(URIResolver JavaDoc resolver)
545   {
546     m_uriResolver = resolver;
547   }
548
549   // =================================================
550

551   /** The reader of the primary source tree. */
552   public XMLReader JavaDoc m_primaryReader;
553
554   /**
555    * Get primary XMLReader associated with this execution context.
556    *
557    * @return The reader of the primary source tree.
558    */

559   public final XMLReader JavaDoc getPrimaryReader()
560   {
561     return m_primaryReader;
562   }
563
564   /**
565    * Set primary XMLReader associated with this execution context.
566    *
567    * @param reader The reader of the primary source tree.
568    */

569   public void setPrimaryReader(XMLReader JavaDoc reader)
570   {
571     m_primaryReader = reader;
572   }
573
574   // =================================================
575

576
577   /** Misnamed string manager for XPath messages. */
578   // private static XSLMessages m_XSLMessages = new XSLMessages();
579

580   /**
581    * Tell the user of an assertion error, and probably throw an
582    * exception.
583    *
584    * @param b If false, a TransformerException will be thrown.
585    * @param msg The assertion message, which should be informative.
586    *
587    * @throws javax.xml.transform.TransformerException if b is false.
588    */

589   private void assertion(boolean b, String JavaDoc msg) throws javax.xml.transform.TransformerException JavaDoc
590   {
591     if (!b)
592     {
593       ErrorListener JavaDoc errorHandler = getErrorListener();
594
595       if (errorHandler != null)
596       {
597         errorHandler.fatalError(
598           new TransformerException JavaDoc(
599             XSLMessages.createMessage(
600               XPATHErrorResources.ER_INCORRECT_PROGRAMMER_ASSERTION,
601               new Object JavaDoc[]{ msg }), (SAXSourceLocator)this.getSAXLocator()));
602       }
603     }
604   }
605
606   //==========================================================
607
// SECTION: Execution context state tracking
608
//==========================================================
609

610   /**
611    * The current context node list.
612    */

613   private Stack JavaDoc m_contextNodeLists = new Stack JavaDoc();
614   
615   public Stack JavaDoc getContextNodeListsStack() { return m_contextNodeLists; }
616   public void setContextNodeListsStack(Stack JavaDoc s) { m_contextNodeLists = s; }
617
618   /**
619    * Get the current context node list.
620    *
621    * @return the <a HREF="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
622    * also refered to here as a <term>context node list</term>.
623    */

624   public final DTMIterator getContextNodeList()
625   {
626
627     if (m_contextNodeLists.size() > 0)
628       return (DTMIterator) m_contextNodeLists.peek();
629     else
630       return null;
631   }
632
633   /**
634    * Set the current context node list.
635    *
636    * @param nl the <a HREF="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>,
637    * also refered to here as a <term>context node list</term>.
638    * @xsl.usage internal
639    */

640   public final void pushContextNodeList(DTMIterator nl)
641   {
642     m_contextNodeLists.push(nl);
643   }
644
645   /**
646    * Pop the current context node list.
647    * @xsl.usage internal
648    */

649   public final void popContextNodeList()
650   {
651     if(m_contextNodeLists.isEmpty())
652       System.err.println("Warning: popContextNodeList when stack is empty!");
653     else
654       m_contextNodeLists.pop();
655   }
656
657   /**
658    * The ammount to use for stacks that record information during the
659    * recursive execution.
660    */

661   public static final int RECURSIONLIMIT = (1024*4);
662
663   /** The stack of <a HREF="http://www.w3.org/TR/xslt#dt-current-node">current node</a> objects.
664    * Not to be confused with the current node list. %REVIEW% Note that there
665    * are no bounds check and resize for this stack, so if it is blown, it's all
666    * over. */

667   private IntStack m_currentNodes = new IntStack(RECURSIONLIMIT);
668    
669 // private NodeVector m_currentNodes = new NodeVector();
670

671   public IntStack getCurrentNodeStack() {return m_currentNodes; }
672   public void setCurrentNodeStack(IntStack nv) { m_currentNodes = nv; }
673
674   /**
675    * Get the current context node.
676    *
677    * @return the <a HREF="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
678    */

679   public final int getCurrentNode()
680   {
681     return m_currentNodes.peek();
682   }
683   
684   /**
685    * Set the current context node and expression node.
686    *
687    * @param cn the <a HREF="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
688    * @param en the sub-expression context node.
689    */

690   public final void pushCurrentNodeAndExpression(int cn, int en)
691   {
692     m_currentNodes.push(cn);
693     m_currentExpressionNodes.push(cn);
694   }
695
696   /**
697    * Set the current context node.
698    */

699   public final void popCurrentNodeAndExpression()
700   {
701     m_currentNodes.quickPop(1);
702     m_currentExpressionNodes.quickPop(1);
703   }
704   
705   /**
706    * Push the current context node, expression node, and prefix resolver.
707    *
708    * @param cn the <a HREF="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
709    * @param en the sub-expression context node.
710    * @param nc the namespace context (prefix resolver.
711    */

712   public final void pushExpressionState(int cn, int en, PrefixResolver nc)
713   {
714     m_currentNodes.push(cn);
715     m_currentExpressionNodes.push(cn);
716     m_prefixResolvers.push(nc);
717   }
718   
719   /**
720    * Pop the current context node, expression node, and prefix resolver.
721    */

722   public final void popExpressionState()
723   {
724     m_currentNodes.quickPop(1);
725     m_currentExpressionNodes.quickPop(1);
726     m_prefixResolvers.pop();
727   }
728
729
730
731   /**
732    * Set the current context node.
733    *
734    * @param n the <a HREF="http://www.w3.org/TR/xslt#dt-current-node">current node</a>.
735    */

736   public final void pushCurrentNode(int n)
737   {
738     m_currentNodes.push(n);
739   }
740   
741   /**
742    * Pop the current context node.
743    */

744   public final void popCurrentNode()
745   {
746     m_currentNodes.quickPop(1);
747   }
748   
749   /**
750    * Set the current predicate root.
751    */

752   public final void pushPredicateRoot(int n)
753   {
754     m_predicateRoots.push(n);
755   }
756
757   /**
758    * Pop the current predicate root.
759    */

760   public final void popPredicateRoot()
761   {
762     m_predicateRoots.popQuick();
763   }
764
765   /**
766    * Get the current predicate root.
767    */

768   public final int getPredicateRoot()
769   {
770     return m_predicateRoots.peepOrNull();
771   }
772   
773   /**
774    * Set the current location path iterator root.
775    */

776   public final void pushIteratorRoot(int n)
777   {
778     m_iteratorRoots.push(n);
779   }
780
781   /**
782    * Pop the current location path iterator root.
783    */

784   public final void popIteratorRoot()
785   {
786     m_iteratorRoots.popQuick();
787   }
788
789   /**
790    * Get the current location path iterator root.
791    */

792   public final int getIteratorRoot()
793   {
794     return m_iteratorRoots.peepOrNull();
795   }
796   
797   /** A stack of the current sub-expression nodes. */
798   private NodeVector m_iteratorRoots = new NodeVector();
799
800   /** A stack of the current sub-expression nodes. */
801   private NodeVector m_predicateRoots = new NodeVector();
802
803   /** A stack of the current sub-expression nodes. */
804   private IntStack m_currentExpressionNodes = new IntStack(RECURSIONLIMIT);
805   
806      
807   public IntStack getCurrentExpressionNodeStack() { return m_currentExpressionNodes; }
808   public void setCurrentExpressionNodeStack(IntStack nv) { m_currentExpressionNodes = nv; }
809   
810   private IntStack m_predicatePos = new IntStack();
811   
812   public final int getPredicatePos()
813   {
814     return m_predicatePos.peek();
815   }
816
817   public final void pushPredicatePos(int n)
818   {
819     m_predicatePos.push(n);
820   }
821
822   public final void popPredicatePos()
823   {
824     m_predicatePos.pop();
825   }
826
827   /**
828    * Get the current node that is the expression's context (i.e. for current() support).
829    *
830    * @return The current sub-expression node.
831    */

832   public final int getCurrentExpressionNode()
833   {
834     return m_currentExpressionNodes.peek();
835   }
836
837   /**
838    * Set the current node that is the expression's context (i.e. for current() support).
839    *
840    * @param n The sub-expression node to be current.
841    */

842   public final void pushCurrentExpressionNode(int n)
843   {
844     m_currentExpressionNodes.push(n);
845   }
846
847   /**
848    * Pop the current node that is the expression's context
849    * (i.e. for current() support).
850    */

851   public final void popCurrentExpressionNode()
852   {
853     m_currentExpressionNodes.quickPop(1);
854   }
855   
856   private ObjectStack m_prefixResolvers
857                                    = new ObjectStack(RECURSIONLIMIT);
858
859   /**
860    * Get the current namespace context for the xpath.
861    *
862    * @return the current prefix resolver for resolving prefixes to
863    * namespace URLs.
864    */

865   public final PrefixResolver getNamespaceContext()
866   {
867     return (PrefixResolver) m_prefixResolvers.peek();
868   }
869
870   /**
871    * Get the 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 setNamespaceContext(PrefixResolver pr)
877   {
878     m_prefixResolvers.setTop(pr);
879   }
880
881   /**
882    * Push a current namespace context for the xpath.
883    *
884    * @param pr the prefix resolver to be used for resolving prefixes to
885    * namespace URLs.
886    */

887   public final void pushNamespaceContext(PrefixResolver pr)
888   {
889     m_prefixResolvers.push(pr);
890   }
891   
892   /**
893    * Just increment the namespace contest stack, so that setNamespaceContext
894    * can be used on the slot.
895    */

896   public final void pushNamespaceContextNull()
897   {
898     m_prefixResolvers.push(null);
899   }
900
901   /**
902    * Pop the current namespace context for the xpath.
903    */

904   public final void popNamespaceContext()
905   {
906     m_prefixResolvers.pop();
907   }
908
909   //==========================================================
910
// SECTION: Current TreeWalker contexts (for internal use)
911
//==========================================================
912

913   /**
914    * Stack of AxesIterators.
915    */

916   private Stack JavaDoc m_axesIteratorStack = new Stack JavaDoc();
917   
918   public Stack JavaDoc getAxesIteratorStackStacks() { return m_axesIteratorStack; }
919   public void setAxesIteratorStackStacks(Stack JavaDoc s) { m_axesIteratorStack = s; }
920
921   /**
922    * Push a TreeWalker on the stack.
923    *
924    * @param iter A sub-context AxesWalker.
925    * @xsl.usage internal
926    */

927   public final void pushSubContextList(SubContextList iter)
928   {
929     m_axesIteratorStack.push(iter);
930   }
931
932   /**
933    * Pop the last pushed axes iterator.
934    * @xsl.usage internal
935    */

936   public final void popSubContextList()
937   {
938     m_axesIteratorStack.pop();
939   }
940
941   /**
942    * Get the current axes iterator, or return null if none.
943    *
944    * @return the sub-context node list.
945    * @xsl.usage internal
946    */

947   public SubContextList getSubContextList()
948   {
949     return m_axesIteratorStack.isEmpty()
950            ? null : (SubContextList) m_axesIteratorStack.peek();
951   }
952   
953   /**
954    * Get the <a HREF="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>
955    * as defined by the XSLT spec.
956    *
957    * @return the <a HREF="http://www.w3.org/TR/xslt#dt-current-node-list">current node list</a>.
958    * @xsl.usage internal
959    */

960
961   public org.apache.xpath.axes.SubContextList getCurrentNodeList()
962   {
963     return m_axesIteratorStack.isEmpty()
964            ? null : (SubContextList) m_axesIteratorStack.elementAt(0);
965   }
966   //==========================================================
967
// SECTION: Implementation of ExpressionContext interface
968
//==========================================================
969

970   /**
971    * Get the current context node.
972    * @return The current context node.
973    */

974   public final int getContextNode()
975   {
976     return this.getCurrentNode();
977   }
978
979   /**
980    * Get the current context node list.
981    * @return An iterator for the current context list, as
982    * defined in XSLT.
983    */

984   public final DTMIterator getContextNodes()
985   {
986
987     try
988     {
989       DTMIterator cnl = getContextNodeList();
990
991       if (null != cnl)
992         return cnl.cloneWithReset();
993       else
994         return null; // for now... this might ought to be an empty iterator.
995
}
996     catch (CloneNotSupportedException JavaDoc cnse)
997     {
998       return null; // error reporting?
999
}
1000  }
1001  
1002  XPathExpressionContext expressionContext = new XPathExpressionContext();
1003  
1004  /**
1005   * The the expression context for extensions for this context.
1006   *
1007   * @return An object that implements the ExpressionContext.
1008   */

1009  public ExpressionContext getExpressionContext()
1010  {
1011    return expressionContext;
1012  }
1013  
1014  public class XPathExpressionContext implements ExpressionContext
1015  {
1016    /**
1017     * Return the XPathContext associated with this XPathExpressionContext.
1018     * Extensions should use this judiciously and only when special processing
1019     * requirements cannot be met another way. Consider requesting an enhancement
1020     * to the ExpressionContext interface to avoid having to call this method.
1021     * @return the XPathContext associated with this XPathExpressionContext.
1022     */

1023     public XPathContext getXPathContext()
1024     {
1025       return XPathContext.this;
1026     }
1027
1028    /**
1029     * Return the DTMManager object. Though XPathContext context extends
1030     * the DTMManager, it really is a proxy for the real DTMManager. If a
1031     * caller needs to make a lot of calls to the DTMManager, it is faster
1032     * if it gets the real one from this function.
1033     */

1034     public DTMManager getDTMManager()
1035     {
1036       return m_dtmManager;
1037     }
1038    
1039    /**
1040     * Get the current context node.
1041     * @return The current context node.
1042     */

1043    public org.w3c.dom.Node JavaDoc getContextNode()
1044    {
1045      int context = getCurrentNode();
1046      
1047      return getDTM(context).getNode(context);
1048    }
1049  
1050    /**
1051     * Get the current context node list.
1052     * @return An iterator for the current context list, as
1053     * defined in XSLT.
1054     */

1055    public org.w3c.dom.traversal.NodeIterator getContextNodes()
1056    {
1057      return new org.apache.xml.dtm.ref.DTMNodeIterator(getContextNodeList());
1058    }
1059
1060    /**
1061     * Get the error listener.
1062     * @return The registered error listener.
1063     */

1064    public ErrorListener JavaDoc getErrorListener()
1065    {
1066      return XPathContext.this.getErrorListener();
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 JavaDoc 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 JavaDoc toString(org.w3c.dom.Node JavaDoc 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(org.apache.xml.utils.QName qname)
1105              throws javax.xml.transform.TransformerException JavaDoc
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 Vector JavaDoc();
1179        rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1180    m_rtfdtm_stack.addElement(rtfdtm);
1181        ++m_which_rtfdtm;
1182    }
1183    else if(m_which_rtfdtm<0)
1184    {
1185        rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(++m_which_rtfdtm);
1186    }
1187    else
1188    {
1189        rtfdtm=(SAX2RTFDTM)m_rtfdtm_stack.elementAt(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.elementAt(m_which_rtfdtm);
1201            else
1202            {
1203                rtfdtm=(SAX2RTFDTM)m_dtmManager.getDTM(null,true,null,false,false);
1204          m_rtfdtm_stack.addElement(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.elementAt(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.elementAt(m_which_rtfdtm))).popRewindMark();
1256        --m_which_rtfdtm;
1257    }
1258  }
1259}
1260
Popular Tags