KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > transformer > TransformerImpl


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: TransformerImpl.java,v 1.158 2004/02/23 21:33:14 igorh Exp $
18  */

19 package org.apache.xalan.transformer;
20
21 import java.io.IOException JavaDoc;
22 import java.io.StringWriter JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.Properties JavaDoc;
25 import java.util.Stack JavaDoc;
26 import java.util.StringTokenizer JavaDoc;
27 import java.util.Vector JavaDoc;
28
29 import javax.xml.parsers.DocumentBuilder JavaDoc;
30 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
31 import javax.xml.parsers.ParserConfigurationException JavaDoc;
32 import javax.xml.transform.ErrorListener JavaDoc;
33 import javax.xml.transform.OutputKeys JavaDoc;
34 import javax.xml.transform.Result JavaDoc;
35 import javax.xml.transform.Source JavaDoc;
36 import javax.xml.transform.SourceLocator JavaDoc;
37 import javax.xml.transform.Transformer JavaDoc;
38 import javax.xml.transform.TransformerException JavaDoc;
39 import javax.xml.transform.URIResolver JavaDoc;
40 import javax.xml.transform.dom.DOMResult JavaDoc;
41 import javax.xml.transform.dom.DOMSource JavaDoc;
42 import javax.xml.transform.sax.SAXResult JavaDoc;
43 import javax.xml.transform.sax.SAXSource JavaDoc;
44 import javax.xml.transform.stream.StreamResult JavaDoc;
45 import javax.xml.transform.stream.StreamSource JavaDoc;
46
47 import org.apache.xalan.extensions.ExtensionsTable;
48 import org.apache.xalan.res.XSLMessages;
49 import org.apache.xalan.res.XSLTErrorResources;
50 import org.apache.xml.serializer.Method;
51 import org.apache.xml.serializer.Serializer;
52 import org.apache.xml.serializer.SerializerFactory;
53 import org.apache.xalan.templates.AVT;
54 import org.apache.xalan.templates.Constants;
55 import org.apache.xalan.templates.ElemAttributeSet;
56 import org.apache.xalan.templates.ElemForEach;
57 import org.apache.xalan.templates.ElemSort;
58 import org.apache.xalan.templates.ElemTemplate;
59 import org.apache.xalan.templates.ElemTemplateElement;
60 import org.apache.xalan.templates.ElemTextLiteral;
61 import org.apache.xalan.templates.ElemVariable;
62 import org.apache.xalan.templates.OutputProperties;
63 import org.apache.xalan.templates.Stylesheet;
64 import org.apache.xalan.templates.StylesheetComposed;
65 import org.apache.xalan.templates.StylesheetRoot;
66 import org.apache.xalan.templates.XUnresolvedVariable;
67 import org.apache.xalan.trace.GenerateEvent;
68 import org.apache.xalan.trace.TraceManager;
69 import org.apache.xml.dtm.DTM;
70 import org.apache.xml.dtm.DTMIterator;
71 import org.apache.xml.dtm.DTMManager;
72 import org.apache.xml.dtm.DTMWSFilter;
73 import org.apache.xml.serializer.ToHTMLSAXHandler;
74 import org.apache.xml.serializer.ToSAXHandler;
75 import org.apache.xml.serializer.ToTextSAXHandler;
76 import org.apache.xml.serializer.ToTextStream;
77 import org.apache.xml.serializer.ToXMLSAXHandler;
78 import org.apache.xml.serializer.SerializationHandler;
79 import org.apache.xml.utils.BoolStack;
80 import org.apache.xml.utils.DOMBuilder;
81 import org.apache.xml.utils.NodeVector;
82 import org.apache.xml.utils.ObjectPool;
83 import org.apache.xml.utils.ObjectStack;
84 import org.apache.xml.utils.QName;
85 import org.apache.xml.utils.SAXSourceLocator;
86 import org.apache.xml.utils.ThreadControllerWrapper;
87 import org.apache.xpath.Arg;
88 import org.apache.xpath.ExtensionsProvider;
89 import org.apache.xpath.VariableStack;
90 import org.apache.xpath.XPathContext;
91 import org.apache.xpath.functions.FuncExtFunction;
92 import org.apache.xpath.objects.XObject;
93 import org.xml.sax.Attributes JavaDoc;
94 import org.xml.sax.ContentHandler JavaDoc;
95 import org.xml.sax.SAXException JavaDoc;
96 import org.xml.sax.SAXNotRecognizedException JavaDoc;
97 import org.xml.sax.SAXNotSupportedException JavaDoc;
98 import org.xml.sax.ext.DeclHandler JavaDoc;
99 import org.xml.sax.ext.LexicalHandler JavaDoc;
100
101 /**
102  * This class implements the
103  * {@link javax.xml.transform.Transformer} interface, and is the core
104  * representation of the transformation execution.</p>
105  * @xsl.usage advanced
106  */

107 public class TransformerImpl extends Transformer JavaDoc
108         implements Runnable JavaDoc, DTMWSFilter, ExtensionsProvider, org.apache.xml.serializer.SerializerTrace
109 {
110
111   // Synch object to gaurd against setting values from the TrAX interface
112
// or reentry while the transform is going on.
113

114   /** NEEDSDOC Field m_reentryGuard */
115   private Boolean JavaDoc m_reentryGuard = new Boolean JavaDoc(true);
116
117   /**
118    * This is null unless we own the stream.
119    */

120   private java.io.FileOutputStream JavaDoc m_outputStream = null;
121
122   /**
123    * True if the parser events should be on the main thread,
124    * false if not. Experemental. Can not be set right now.
125    */

126   private boolean m_parserEventsOnMain = true;
127
128   /** The thread that the transformer is running on. */
129   private Thread JavaDoc m_transformThread;
130
131   /** The base URL of the source tree. */
132   private String JavaDoc m_urlOfSource = null;
133
134   /** The Result object at the start of the transform, if any. */
135   private Result JavaDoc m_outputTarget = null;
136
137   /**
138    * The output format object set by the user. May be null.
139    */

140   private OutputProperties m_outputFormat;
141
142
143   /**
144    * The content handler for the source input tree.
145    */

146   ContentHandler JavaDoc m_inputContentHandler;
147
148   /**
149    * The content handler for the result tree.
150    */

151   private ContentHandler JavaDoc m_outputContentHandler = null;
152
153   // /*
154
// * Use member variable to store param variables as they're
155
// * being created, use member variable so we don't
156
// * have to create a new vector every time.
157
// */
158
// private Vector m_newVars = new Vector();
159

160   /** The JAXP Document Builder, mainly to create Result Tree Fragments. */
161   DocumentBuilder JavaDoc m_docBuilder = null;
162
163   /**
164    * A pool of ResultTreeHandlers, for serialization of a subtree to text.
165    * Please note that each of these also holds onto a Text Serializer.
166    */

167   private ObjectPool m_textResultHandlerObjectPool =
168     new ObjectPool(ToTextStream.class);
169
170   /**
171    * Related to m_textResultHandlerObjectPool, this is a pool of
172    * StringWriters, which are passed to the Text Serializers.
173    * (I'm not sure if this is really needed any more. -sb)
174    */

175   private ObjectPool m_stringWriterObjectPool =
176     new ObjectPool(StringWriter JavaDoc.class);
177
178   /**
179    * A static text format object, which can be used over and
180    * over to create the text serializers.
181    */

182   private OutputProperties m_textformat = new OutputProperties(Method.TEXT);
183
184   // Commenteded out in response to problem reported by
185
// Nicola Brown <Nicola.Brown@jacobsrimell.com>
186
// /**
187
// * Flag to let us know if an exception should be reported inside the
188
// * postExceptionFromThread method. This is needed if the transform is
189
// * being generated from SAX events, and thus there is no central place
190
// * to report the exception from. (An exception is usually picked up in
191
// * the main thread from the transform thread in {@link #transform(Source source)}
192
// * from {@link #getExceptionThrown()}. )
193
// */
194
// private boolean m_reportInPostExceptionFromThread = false;
195

196   /**
197    * A node vector used as a stack to track the current
198    * ElemTemplateElement. Needed for the
199    * org.apache.xalan.transformer.TransformState interface,
200    * so a tool can discover the calling template. Note the use of an array
201    * for this limits the recursion depth to 4K.
202    */

203   ObjectStack m_currentTemplateElements
204       = new ObjectStack(XPathContext.RECURSIONLIMIT);
205   
206   /** The top of the currentTemplateElements stack. */
207   //int m_currentTemplateElementsTop = 0;
208

209   /**
210    * A node vector used as a stack to track the current
211    * ElemTemplate that was matched.
212    * Needed for the
213    * org.apache.xalan.transformer.TransformState interface,
214    * so a tool can discover the matched template
215    */

216   Stack JavaDoc m_currentMatchTemplates = new Stack JavaDoc();
217
218   /**
219    * A node vector used as a stack to track the current
220    * node that was matched.
221    * Needed for the
222    * org.apache.xalan.transformer.TransformState interface,
223    * so a tool can discover the matched
224    * node.
225    */

226   NodeVector m_currentMatchedNodes = new NodeVector();
227
228   /**
229    * The root of a linked set of stylesheets.
230    */

231   private StylesheetRoot m_stylesheetRoot = null;
232
233   /**
234    * If this is set to true, do not warn about pattern
235    * match conflicts.
236    */

237   private boolean m_quietConflictWarnings = true;
238
239   /**
240    * The liason to the XML parser, so the XSL processor
241    * can handle included files, and the like, and do the
242    * initial parse of the XSL document.
243    */

244   private XPathContext m_xcontext;
245
246   /**
247    * Object to guard agains infinite recursion when
248    * doing queries.
249    */

250   private StackGuard m_stackGuard;
251
252   /**
253    * Output handler to bottleneck SAX events.
254    */

255   private SerializationHandler m_serializationHandler;
256
257   /** The key manager, which manages xsl:keys. */
258   private KeyManager m_keyManager = new KeyManager();
259
260   /**
261    * Stack for the purposes of flagging infinite recursion with
262    * attribute sets.
263    */

264   Stack JavaDoc m_attrSetStack = null;
265
266   /**
267    * The table of counters for xsl:number support.
268    * @see ElemNumber
269    */

270   CountersTable m_countersTable = null;
271
272   /**
273    * Is > 0 when we're processing a for-each.
274    */

275   BoolStack m_currentTemplateRuleIsNull = new BoolStack();
276
277   /**
278    * Keeps track of the result delivered by any EXSLT <code>func:result</code>
279    * instruction that has been executed for the currently active EXSLT
280    * <code>func:function</code>
281    */

282   ObjectStack m_currentFuncResult = new ObjectStack();
283   
284   /**
285    * The message manager, which manages error messages, warning
286    * messages, and other types of message events.
287    */

288   private MsgMgr m_msgMgr;
289
290   /**
291    * This is a compile-time flag to turn off calling
292    * of trace listeners. Set this to false for optimization purposes.
293    */

294   public static boolean S_DEBUG = false;
295
296   /**
297    * The SAX error handler, where errors and warnings are sent.
298    */

299   private ErrorListener JavaDoc m_errorHandler =
300     new org.apache.xml.utils.DefaultErrorHandler();
301
302   /**
303    * The trace manager.
304    */

305   private TraceManager m_traceManager = new TraceManager(this);
306
307   /**
308    * If the transform thread throws an exception, the exception needs to
309    * be stashed away so that the main thread can pass it on to the
310    * client.
311    */

312   private Exception JavaDoc m_exceptionThrown = null;
313
314   /**
315    * The InputSource for the source tree, which is needed if the
316    * parse thread is not the main thread, in order for the parse
317    * thread's run method to get to the input source.
318    * (Delete this if reversing threads is outlawed. -sb)
319    */

320   private Source JavaDoc m_xmlSource;
321
322   /**
323    * This is needed for support of setSourceTreeDocForThread(Node doc),
324    * which must be called in order for the transform thread's run
325    * method to obtain the root of the source tree to be transformed.
326    */

327   private int m_doc;
328
329   /**
330    * If the the transform is on the secondary thread, we
331    * need to know when it is done, so we can return.
332    */

333   private boolean m_isTransformDone = false;
334
335   /** Flag to to tell if the tranformer needs to be reset. */
336   private boolean m_hasBeenReset = false;
337
338   /** NEEDSDOC Field m_shouldReset */
339   private boolean m_shouldReset = true;
340
341   /**
342    * NEEDSDOC Method setShouldReset
343    *
344    *
345    * NEEDSDOC @param shouldReset
346    */

347   public void setShouldReset(boolean shouldReset)
348   {
349     m_shouldReset = shouldReset;
350   }
351
352   /**
353    * A stack of current template modes.
354    */

355   private Stack JavaDoc m_modes = new Stack JavaDoc();
356
357   //==========================================================
358
// SECTION: Constructor
359
//==========================================================
360

361   /**
362    * Construct a TransformerImpl.
363    *
364    * @param stylesheet The root of the stylesheet tree.
365    */

366   public TransformerImpl(StylesheetRoot stylesheet)
367    // throws javax.xml.transform.TransformerException
368
{
369     setStylesheet(stylesheet);
370     setXPathContext(new XPathContext(this));
371     getXPathContext().setNamespaceContext(stylesheet);
372     m_stackGuard = new StackGuard(this);
373   }
374   
375   // ================ ExtensionsTable ===================
376

377   /**
378    * The table of ExtensionHandlers.
379    */

380   private ExtensionsTable m_extensionsTable = null;
381
382   /**
383    * Get the extensions table object.
384    *
385    * @return The extensions table.
386    */

387   public ExtensionsTable getExtensionsTable()
388   {
389     return m_extensionsTable;
390   }
391
392   /**
393    * If the stylesheet contains extensions, set the extensions table object.
394    *
395    *
396    * @param sroot The stylesheet.
397    * @throws javax.xml.transform.TransformerException
398    */

399   void setExtensionsTable(StylesheetRoot sroot)
400        throws javax.xml.transform.TransformerException JavaDoc
401   {
402     try
403     {
404       if (sroot.getExtensions() != null)
405         m_extensionsTable = new ExtensionsTable(sroot);
406     }
407     catch (javax.xml.transform.TransformerException JavaDoc te)
408     {te.printStackTrace();}
409   }
410   
411   //== Implementation of the XPath ExtensionsProvider interface.
412

413   public boolean functionAvailable(String JavaDoc ns, String JavaDoc funcName)
414           throws javax.xml.transform.TransformerException JavaDoc
415   {
416     return getExtensionsTable().functionAvailable(ns, funcName);
417   }
418   
419   public boolean elementAvailable(String JavaDoc ns, String JavaDoc elemName)
420           throws javax.xml.transform.TransformerException JavaDoc
421   {
422     return getExtensionsTable().elementAvailable(ns, elemName);
423   }
424    
425   public Object JavaDoc extFunction(String JavaDoc ns, String JavaDoc funcName,
426                             Vector JavaDoc argVec, Object JavaDoc methodKey)
427             throws javax.xml.transform.TransformerException JavaDoc
428   {//System.out.println("TransImpl.extFunction() " + ns + " " + funcName +" " + getExtensionsTable());
429
return getExtensionsTable().extFunction(ns, funcName,
430                                         argVec, methodKey,
431                                         getXPathContext().getExpressionContext());
432   }
433
434   public Object JavaDoc extFunction(FuncExtFunction extFunction, Vector JavaDoc argVec)
435             throws javax.xml.transform.TransformerException JavaDoc
436   {
437     return getExtensionsTable().extFunction(extFunction, argVec,
438                                             getXPathContext().getExpressionContext());
439   }
440   
441   //=========================
442

443   /**
444    * Reset the state. This needs to be called after a process() call
445    * is invoked, if the processor is to be used again.
446    */

447   public void reset()
448   {
449
450     if (!m_hasBeenReset && m_shouldReset)
451     {
452       m_hasBeenReset = true;
453
454       if (this.m_outputStream != null)
455       {
456         try
457         {
458           m_outputStream.close();
459         }
460         catch (java.io.IOException JavaDoc ioe){}
461       }
462
463       m_outputStream = null;
464
465       // I need to look more carefully at which of these really
466
// needs to be reset.
467
m_countersTable = null;
468
469       m_xcontext.reset();
470       
471       m_xcontext.getVarStack().reset();
472       resetUserParameters();
473       
474
475       m_currentTemplateElements.removeAllElements();
476       m_currentMatchTemplates.removeAllElements();
477       m_currentMatchedNodes.removeAllElements();
478       
479       m_serializationHandler = null;
480       m_outputTarget = null;
481       m_keyManager = new KeyManager();
482       m_attrSetStack = null;
483       m_countersTable = null;
484       m_currentTemplateRuleIsNull = new BoolStack();
485       m_xmlSource = null;
486       m_doc = DTM.NULL;
487       m_isTransformDone = false;
488       m_transformThread = null;
489
490       // m_inputContentHandler = null;
491
// For now, reset the document cache each time.
492
m_xcontext.getSourceTreeManager().reset();
493     }
494
495     // m_reportInPostExceptionFromThread = false;
496
}
497
498   /**
499    * <code>getProperty</code> returns the current setting of the
500    * property described by the <code>property</code> argument.
501    *
502    * %REVIEW% Obsolete now that source_location is handled in the TransformerFactory?
503    *
504    * @param property a <code>String</code> value
505    * @return a <code>boolean</code> value
506    */

507   public boolean getProperty(String JavaDoc property)
508   {
509     return false;
510   }
511
512   /**
513    * Set a runtime property for this <code>TransformerImpl</code>.
514    *
515    * %REVIEW% Obsolete now that source_location is handled in the TransformerFactory?
516    *
517    * @param property a <code>String</code> value
518    * @param value an <code>Object</code> value
519    */

520   public void setProperty(String JavaDoc property, Object JavaDoc value)
521   {
522   }
523
524   // ========= Transformer Interface Implementation ==========
525

526   /**
527    * Get true if the parser events should be on the main thread,
528    * false if not. Experimental. Can not be set right now.
529    *
530    * @return true if the parser events should be on the main thread,
531    * false if not.
532    * @xsl.usage experimental
533    */

534   public boolean isParserEventsOnMain()
535   {
536     return m_parserEventsOnMain;
537   }
538
539   /**
540    * Get the thread that the transform process is on.
541    *
542    * @return The thread that the transform process is on, or null.
543    * @xsl.usage internal
544    */

545   public Thread JavaDoc getTransformThread()
546   {
547     return m_transformThread;
548   }
549
550   /**
551    * Get the thread that the transform process is on.
552    *
553    * @param t The transform thread, may be null.
554    * @xsl.usage internal
555    */

556   public void setTransformThread(Thread JavaDoc t)
557   {
558     m_transformThread = t;
559   }
560
561   /** NEEDSDOC Field m_hasTransformThreadErrorCatcher */
562   private boolean m_hasTransformThreadErrorCatcher = false;
563
564   /**
565    * Return true if the transform was initiated from the transform method,
566    * otherwise it was probably done from a pure parse events.
567    *
568    * NEEDSDOC ($objectName$) @return
569    */

570   public boolean hasTransformThreadErrorCatcher()
571   {
572     return m_hasTransformThreadErrorCatcher;
573   }
574         
575         /**
576    * Process the source tree to SAX parse events.
577    * @param source The input for the source tree.
578    *
579    * @throws TransformerException
580    */

581   public void transform(Source JavaDoc source) throws TransformerException JavaDoc
582   {
583                 transform(source, true);
584         }
585
586   /**
587    * Process the source tree to SAX parse events.
588    * @param source The input for the source tree.
589    * @param shouldRelease Flag indicating whether to release DTMManager.
590    *
591    * @throws TransformerException
592    */

593   public void transform(Source JavaDoc source, boolean shouldRelease) throws TransformerException JavaDoc
594   {
595
596     try
597     {
598         
599       // Patch for bugzilla #13863. If we don't reset the namespaceContext
600
// then we will get a NullPointerException if transformer is reused
601
// (for stylesheets that use xsl:key). Not sure if this should go
602
// here or in reset(). -is
603
if(getXPathContext().getNamespaceContext() == null){
604          getXPathContext().setNamespaceContext(getStylesheet());
605       }
606       String JavaDoc base = source.getSystemId();
607       
608       // If no systemID of the source, use the base of the stylesheet.
609
if(null == base)
610       {
611         base = m_stylesheetRoot.getBaseIdentifier();
612       }
613
614       // As a last resort, use the current user dir.
615
if(null == base)
616       {
617         String JavaDoc currentDir = "";
618         try {
619           currentDir = System.getProperty("user.dir");
620         }
621         catch (SecurityException JavaDoc se) {}// user.dir not accessible from applet
622

623         if (currentDir.startsWith(java.io.File.separator))
624           base = "file://" + currentDir;
625         else
626           base = "file:///" + currentDir;
627         
628         base = base + java.io.File.separatorChar
629                + source.getClass().getName();
630       }
631       setBaseURLOfSource(base);
632       DTMManager mgr = m_xcontext.getDTMManager();
633       /*
634        * According to JAXP1.2, new SAXSource()/StreamSource()
635        * should create an empty input tree, with a default root node.
636        * new DOMSource()creates an empty document using DocumentBuilder.
637        * newDocument(); Use DocumentBuilder.newDocument() for all 3 situations,
638        * since there is no clear spec. how to create an empty tree when
639        * both SAXSource() and StreamSource() are used.
640        */

641       if ((source instanceof StreamSource JavaDoc && source.getSystemId()==null &&
642          ((StreamSource JavaDoc)source).getInputStream()==null &&
643          ((StreamSource JavaDoc)source).getReader()==null)||
644          (source instanceof SAXSource JavaDoc &&
645          ((SAXSource JavaDoc)source).getInputSource()==null &&
646          ((SAXSource JavaDoc)source).getXMLReader()==null )||
647          (source instanceof DOMSource JavaDoc && ((DOMSource JavaDoc)source).getNode()==null)){
648         try {
649           DocumentBuilderFactory JavaDoc builderF =
650                    DocumentBuilderFactory.newInstance();
651           DocumentBuilder JavaDoc builder = builderF.newDocumentBuilder();
652           String JavaDoc systemID = source.getSystemId();
653           source = new DOMSource JavaDoc(builder.newDocument());
654
655           // Copy system ID from original, empty Source to new Source
656
if (systemID != null) {
657             source.setSystemId(systemID);
658           }
659         } catch (ParserConfigurationException JavaDoc e) {
660           fatalError(e);
661         }
662       }
663       DTM dtm = mgr.getDTM(source, false, this, true, true);
664       dtm.setDocumentBaseURI(base);
665       
666       boolean hardDelete = true; // %REVIEW% I have to think about this. -sb
667

668       try
669       {
670         // NOTE: This will work because this is _NOT_ a shared DTM, and thus has
671
// only a single Document node. If it could ever be an RTF or other
672
// shared DTM, look at dtm.getDocumentRoot(nodeHandle).
673
this.transformNode(dtm.getDocument());
674       }
675       finally
676       {
677         if (shouldRelease)
678           mgr.release(dtm, hardDelete);
679       }
680
681       // Kick off the parse. When the ContentHandler gets
682
// the startDocument event, it will call transformNode( node ).
683
// reader.parse( xmlSource );
684
// This has to be done to catch exceptions thrown from
685
// the transform thread spawned by the STree handler.
686
Exception JavaDoc e = getExceptionThrown();
687
688       if (null != e)
689       {
690         if (e instanceof javax.xml.transform.TransformerException JavaDoc)
691         {
692           throw (javax.xml.transform.TransformerException JavaDoc) e;
693         }
694         else if (e instanceof org.apache.xml.utils.WrappedRuntimeException)
695         {
696           fatalError(
697               ((org.apache.xml.utils.WrappedRuntimeException) e).getException());
698         }
699         else
700         {
701           throw new javax.xml.transform.TransformerException JavaDoc(e);
702         }
703       }
704       else if (null != m_serializationHandler)
705       {
706         m_serializationHandler.endDocument();
707       }
708     }
709     catch (org.apache.xml.utils.WrappedRuntimeException wre)
710     {
711       Throwable JavaDoc throwable = wre.getException();
712
713       while (throwable
714              instanceof org.apache.xml.utils.WrappedRuntimeException)
715       {
716         throwable =
717           ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException();
718       }
719
720       fatalError(throwable);
721     }
722
723     // Patch attributed to David Eisenberg <david@catcode.com>
724
catch (org.xml.sax.SAXParseException JavaDoc spe)
725     {
726       fatalError(spe);
727     }
728     catch (org.xml.sax.SAXException JavaDoc se)
729     {
730       m_errorHandler.fatalError(new TransformerException JavaDoc(se));
731     }
732     finally
733     {
734       m_hasTransformThreadErrorCatcher = false;
735
736       // This looks to be redundent to the one done in TransformNode.
737
reset();
738     }
739   }
740   
741   private void fatalError(Throwable JavaDoc throwable) throws TransformerException JavaDoc
742   {
743     if (throwable instanceof org.xml.sax.SAXParseException JavaDoc)
744       m_errorHandler.fatalError(new TransformerException JavaDoc(throwable.getMessage(),new SAXSourceLocator((org.xml.sax.SAXParseException JavaDoc)throwable)));
745     else
746       m_errorHandler.fatalError(new TransformerException JavaDoc(throwable));
747     
748   }
749
750   /**
751    * Get the base URL of the source.
752    *
753    * @return The base URL of the source tree, or null.
754    */

755   public String JavaDoc getBaseURLOfSource()
756   {
757     return m_urlOfSource;
758   }
759
760   /**
761    * Get the base URL of the source.
762    *
763    *
764    * NEEDSDOC @param base
765    * @return The base URL of the source tree, or null.
766    */

767   public void setBaseURLOfSource(String JavaDoc base)
768   {
769     m_urlOfSource = base;
770   }
771
772   /**
773    * Get the original output target.
774    *
775    * @return The Result object used to kick of the transform or null.
776    */

777   public Result JavaDoc getOutputTarget()
778   {
779     return m_outputTarget;
780   }
781
782   /**
783    * Set the original output target. This is useful when using a SAX transform and
784    * supplying a ContentHandler or when the URI of the output target should
785    * not be the same as the systemID of the original output target.
786    *
787    *
788    * NEEDSDOC @param outputTarget
789    */

790   public void setOutputTarget(Result JavaDoc outputTarget)
791   {
792     m_outputTarget = outputTarget;
793   }
794
795   /**
796    * Get an output property that is in effect for the
797    * transformation. The property specified may be a property
798    * that was set with setOutputProperty, or it may be a
799    * property specified in the stylesheet.
800    *
801    * @param name A non-null String that specifies an output
802    * property name, which may be namespace qualified.
803    *
804    * NEEDSDOC @param qnameString
805    *
806    * @return The string value of the output property, or null
807    * if no property was found.
808    *
809    * @throws IllegalArgumentException If the property is not supported.
810    *
811    * @see javax.xml.transform.OutputKeys
812    */

813   public String JavaDoc getOutputProperty(String JavaDoc qnameString)
814           throws IllegalArgumentException JavaDoc
815   {
816
817     String JavaDoc value = null;
818     OutputProperties props = getOutputFormat();
819
820     value = props.getProperty(qnameString);
821
822     if (null == value)
823     {
824       if (!OutputProperties.isLegalPropertyKey(qnameString))
825         throw new IllegalArgumentException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object JavaDoc[]{qnameString})); //"output property not recognized: "
826
//+ qnameString);
827
}
828
829     return value;
830   }
831
832   /**
833    * Get the value of a property, without using the default properties. This
834    * can be used to test if a property has been explicitly set by the stylesheet
835    * or user.
836    *
837    * @param name The property name, which is a fully-qualified URI.
838    *
839    * NEEDSDOC @param qnameString
840    *
841    * @return The value of the property, or null if not found.
842    *
843    * @throws IllegalArgumentException If the property is not supported,
844    * and is not namespaced.
845    */

846   public String JavaDoc getOutputPropertyNoDefault(String JavaDoc qnameString)
847           throws IllegalArgumentException JavaDoc
848   {
849
850     String JavaDoc value = null;
851     OutputProperties props = getOutputFormat();
852
853     value = (String JavaDoc) props.getProperties().get(qnameString);
854
855     if (null == value)
856     {
857       if (!OutputProperties.isLegalPropertyKey(qnameString))
858         throw new IllegalArgumentException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object JavaDoc[]{qnameString})); //"output property not recognized: "
859
// + qnameString);
860
}
861
862     return value;
863   }
864
865   /**
866    * Set the value of a property. Recognized properties are:
867    *
868    * <p>"http://xml.apache.org/xslt/sourcebase" - the base URL for the
869    * source, which is needed when pure SAX ContentHandler transformation
870    * is to be done.</p>
871    *
872    * @param name The property name, which is a fully-qualified URI.
873    * @param value The requested value for the property.
874    * @throws IllegalArgumentException if the property name is not legal.
875    */

876   public void setOutputProperty(String JavaDoc name, String JavaDoc value)
877           throws IllegalArgumentException JavaDoc
878   {
879
880     synchronized (m_reentryGuard)
881     {
882
883       // Get the output format that was set by the user, otherwise get the
884
// output format from the stylesheet.
885
if (null == m_outputFormat)
886       {
887         m_outputFormat =
888           (OutputProperties) getStylesheet().getOutputComposed().clone();
889       }
890
891       if (!OutputProperties.isLegalPropertyKey(name))
892         throw new IllegalArgumentException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object JavaDoc[]{name})); //"output property not recognized: "
893
//+ name);
894

895       m_outputFormat.setProperty(name, value);
896     }
897   }
898
899   /**
900    * Set the output properties for the transformation. These
901    * properties will override properties set in the templates
902    * with xsl:output.
903    *
904    * <p>If argument to this function is null, any properties
905    * previously set will be removed.</p>
906    *
907    * @param oformat A set of output properties that will be
908    * used to override any of the same properties in effect
909    * for the transformation.
910    *
911    * @see javax.xml.transform.OutputKeys
912    * @see java.util.Properties
913    *
914    * @throws IllegalArgumentException if any of the argument keys are not
915    * recognized and are not namespace qualified.
916    */

917   public void setOutputProperties(Properties JavaDoc oformat)
918         throws IllegalArgumentException JavaDoc
919   {
920
921     synchronized (m_reentryGuard)
922     {
923       if (null != oformat)
924       {
925
926         // See if an *explicit* method was set.
927
String JavaDoc method = (String JavaDoc) oformat.get(OutputKeys.METHOD);
928
929         if (null != method)
930           m_outputFormat = new OutputProperties(method);
931         else if(m_outputFormat==null)
932           m_outputFormat = new OutputProperties();
933
934         m_outputFormat.copyFrom(oformat);
935         // copyFrom does not set properties that have been already set, so
936
// this must be called after, which is a bit in the reverse from
937
// what one might think.
938
m_outputFormat.copyFrom(m_stylesheetRoot.getOutputProperties());
939       }
940       else {
941         // if oformat is null JAXP says that any props previously set are removed
942
// and we are to revert back to those in the templates object (i.e. Stylesheet).
943
m_outputFormat = null;
944       }
945     }
946   }
947
948   /**
949    * Get a copy of the output properties for the transformation. These
950    * properties will override properties set in the templates
951    * with xsl:output.
952    *
953    * <p>Note that mutation of the Properties object returned will not
954    * effect the properties that the transformation contains.</p>
955    *
956    * @return A copy of the set of output properties in effect
957    * for the next transformation.
958    *
959    * NEEDSDOC ($objectName$) @return
960    */

961   public Properties JavaDoc getOutputProperties()
962   {
963     return (Properties JavaDoc) getOutputFormat().getProperties().clone();
964   }
965
966     /**
967      * Create a result ContentHandler from a Result object, based
968      * on the current OutputProperties.
969      *
970      * @param outputTarget Where the transform result should go,
971      * should not be null.
972      *
973      * @return A valid ContentHandler that will create the
974      * result tree when it is fed SAX events.
975      *
976      * @throws TransformerException
977      */

978     public SerializationHandler createSerializationHandler(Result JavaDoc outputTarget)
979             throws TransformerException JavaDoc
980     {
981        SerializationHandler xoh =
982         createSerializationHandler(outputTarget, getOutputFormat());
983        return xoh;
984     }
985
986     /**
987      * Create a ContentHandler from a Result object and an OutputProperties.
988      *
989      * @param outputTarget Where the transform result should go,
990      * should not be null.
991      * @param format The OutputProperties object that will contain
992      * instructions on how to serialize the output.
993      *
994      * @return A valid ContentHandler that will create the
995      * result tree when it is fed SAX events.
996      *
997      * @throws TransformerException
998      */

999     public SerializationHandler createSerializationHandler(
1000            Result JavaDoc outputTarget, OutputProperties format)
1001              throws TransformerException JavaDoc
1002    {
1003
1004      SerializationHandler xoh;
1005
1006      // If the Result object contains a Node, then create
1007
// a ContentHandler that will add nodes to the input node.
1008
org.w3c.dom.Node JavaDoc outputNode = null;
1009
1010      if (outputTarget instanceof DOMResult JavaDoc)
1011      {
1012        outputNode = ((DOMResult JavaDoc) outputTarget).getNode();
1013
1014        org.w3c.dom.Document JavaDoc doc;
1015        short type;
1016
1017        if (null != outputNode)
1018        {
1019          type = outputNode.getNodeType();
1020          doc = (org.w3c.dom.Node.DOCUMENT_NODE == type)
1021                ? (org.w3c.dom.Document JavaDoc) outputNode
1022                : outputNode.getOwnerDocument();
1023        }
1024        else
1025        {
1026          doc = org.apache.xml.utils.DOMHelper.createDocument();
1027          outputNode = doc;
1028          type = outputNode.getNodeType();
1029
1030          ((DOMResult JavaDoc) outputTarget).setNode(outputNode);
1031        }
1032
1033        ContentHandler JavaDoc handler =
1034          (org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE == type)
1035          ? new DOMBuilder(doc, (org.w3c.dom.DocumentFragment JavaDoc) outputNode)
1036          : new DOMBuilder(doc, outputNode);
1037          String JavaDoc encoding = format.getProperty(OutputKeys.ENCODING);
1038          xoh = new ToXMLSAXHandler(handler, (LexicalHandler JavaDoc)handler, encoding);
1039      }
1040      else if (outputTarget instanceof SAXResult JavaDoc)
1041      {
1042        ContentHandler JavaDoc handler = ((SAXResult JavaDoc) outputTarget).getHandler();
1043        
1044        if (null == handler)
1045           throw new IllegalArgumentException JavaDoc(
1046             "handler can not be null for a SAXResult");
1047             
1048        LexicalHandler JavaDoc lexHandler;
1049        if (handler instanceof LexicalHandler JavaDoc)
1050            lexHandler = (LexicalHandler JavaDoc) handler;
1051        else
1052            lexHandler = null;
1053            
1054        String JavaDoc encoding = format.getProperty(OutputKeys.ENCODING);
1055        String JavaDoc method = format.getProperty(OutputKeys.METHOD);
1056        if (org.apache.xml.serializer.Method.HTML.equals(method))
1057        {
1058            xoh = new ToHTMLSAXHandler(handler, lexHandler, encoding);
1059        }
1060        else if (org.apache.xml.serializer.Method.TEXT.equals(method))
1061        {
1062            xoh = new ToTextSAXHandler(handler, lexHandler, encoding);
1063        }
1064        else
1065        {
1066            ToXMLSAXHandler toXMLSAXHandler = new ToXMLSAXHandler(handler, lexHandler, encoding);
1067            toXMLSAXHandler.setShouldOutputNSAttr(false);
1068            xoh = toXMLSAXHandler;
1069 
1070        }
1071
1072        String JavaDoc publicID = format.getProperty(OutputKeys.DOCTYPE_PUBLIC);
1073        String JavaDoc systemID = format.getProperty(OutputKeys.DOCTYPE_SYSTEM);
1074        if (systemID != null)
1075            xoh.setDoctypeSystem(systemID);
1076        if (publicID != null)
1077            xoh.setDoctypePublic(publicID);
1078        
1079        if (handler instanceof TransformerClient) {
1080            XalanTransformState state = new XalanTransformState();
1081            ((TransformerClient)handler).setTransformState(state);
1082            ((ToSAXHandler)xoh).setTransformState(state);
1083        }
1084
1085 
1086      }
1087
1088      // Otherwise, create a ContentHandler that will serialize the
1089
// result tree to either a stream or a writer.
1090
else if (outputTarget instanceof StreamResult JavaDoc)
1091      {
1092        StreamResult JavaDoc sresult = (StreamResult JavaDoc) outputTarget;
1093        String JavaDoc method = format.getProperty(OutputKeys.METHOD);
1094
1095        try
1096        {
1097          SerializationHandler serializer =
1098            (SerializationHandler) SerializerFactory.getSerializer(format.getProperties());
1099
1100          if (null != sresult.getWriter())
1101            serializer.setWriter(sresult.getWriter());
1102          else if (null != sresult.getOutputStream())
1103            serializer.setOutputStream(sresult.getOutputStream());
1104          else if (null != sresult.getSystemId())
1105          {
1106            String JavaDoc fileURL = sresult.getSystemId();
1107
1108            if (fileURL.startsWith("file:///"))
1109            {
1110              if (fileURL.substring(8).indexOf(":") >0)
1111                fileURL = fileURL.substring(8);
1112              else
1113                fileURL = fileURL.substring(7);
1114            }
1115
1116            m_outputStream = new java.io.FileOutputStream JavaDoc(fileURL);
1117
1118            serializer.setOutputStream(m_outputStream);
1119            
1120            xoh = serializer;
1121          }
1122          else
1123            throw new TransformerException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_NO_OUTPUT_SPECIFIED, null)); //"No output specified!");
1124

1125          // handler = serializer.asContentHandler();
1126

1127        // this.setSerializer(serializer);
1128

1129          xoh = serializer;
1130        }
1131// catch (UnsupportedEncodingException uee)
1132
// {
1133
// throw new TransformerException(uee);
1134
// }
1135
catch (IOException JavaDoc ioe)
1136        {
1137          throw new TransformerException JavaDoc(ioe);
1138        }
1139      }
1140      else
1141      {
1142        throw new TransformerException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_TRANSFORM_TO_RESULT_TYPE, new Object JavaDoc[]{outputTarget.getClass().getName()})); //"Can't transform to a Result of type "
1143
//+ outputTarget.getClass().getName()
1144
//+ "!");
1145
}
1146      
1147      // before we forget, lets make the created handler hold a reference
1148
// to the current TransformImpl object
1149
xoh.setTransformer(this);
1150
1151      SourceLocator JavaDoc srcLocator = getStylesheet();
1152      xoh.setSourceLocator(srcLocator);
1153      
1154      
1155      return xoh;
1156
1157   
1158    }
1159        
1160        /**
1161   * Process the source tree to the output result.
1162   * @param xmlSource The input for the source tree.
1163   * @param outputTarget The output source target.
1164   *
1165   * @throws TransformerException
1166   */

1167  public void transform(Source JavaDoc xmlSource, Result JavaDoc outputTarget)
1168          throws TransformerException JavaDoc
1169  {
1170                transform(xmlSource, outputTarget, true);
1171        }
1172
1173  /**
1174   * Process the source tree to the output result.
1175   * @param xmlSource The input for the source tree.
1176   * @param outputTarget The output source target.
1177   * @param shouldRelease Flag indicating whether to release DTMManager.
1178   *
1179   * @throws TransformerException
1180   */

1181  public void transform(Source JavaDoc xmlSource, Result JavaDoc outputTarget, boolean shouldRelease)
1182          throws TransformerException JavaDoc
1183  {
1184
1185    synchronized (m_reentryGuard)
1186    {
1187      SerializationHandler xoh = createSerializationHandler(outputTarget);
1188      this.setSerializationHandler(xoh);
1189
1190      m_outputTarget = outputTarget;
1191
1192      transform(xmlSource, shouldRelease);
1193    }
1194  }
1195
1196  /**
1197   * Process the source node to the output result, if the
1198   * processor supports the "http://xml.org/trax/features/dom/input"
1199   * feature.
1200   * %REVIEW% Do we need a Node version of this?
1201   * @param node The input source node, which can be any valid DTM node.
1202   * @param outputTarget The output source target.
1203   *
1204   * @throws TransformerException
1205   */

1206  public void transformNode(int node, Result JavaDoc outputTarget)
1207          throws TransformerException JavaDoc
1208  {
1209    
1210
1211    SerializationHandler xoh = createSerializationHandler(outputTarget);
1212    this.setSerializationHandler(xoh);
1213
1214    m_outputTarget = outputTarget;
1215
1216    transformNode(node);
1217  }
1218
1219  /**
1220   * Process the source node to the output result, if the
1221   * processor supports the "http://xml.org/trax/features/dom/input"
1222   * feature.
1223   * %REVIEW% Do we need a Node version of this?
1224   * @param node The input source node, which can be any valid DTM node.
1225   * @param outputTarget The output source target.
1226   *
1227   * @throws TransformerException
1228   */

1229  public void transformNode(int node) throws TransformerException JavaDoc
1230  {
1231    //dml
1232
setExtensionsTable(getStylesheet());
1233    // Make sure we're not writing to the same output content handler.
1234
synchronized (m_serializationHandler)
1235    {
1236      m_hasBeenReset = false;
1237      
1238      XPathContext xctxt = getXPathContext();
1239      DTM dtm = xctxt.getDTM(node);
1240
1241      try
1242      {
1243        pushGlobalVars(node);
1244
1245        // ==========
1246
// Give the top-level templates a chance to pass information into
1247
// the context (this is mainly for setting up tables for extensions).
1248
StylesheetRoot stylesheet = this.getStylesheet();
1249        int n = stylesheet.getGlobalImportCount();
1250
1251        for (int i = 0; i < n; i++)
1252        {
1253          StylesheetComposed imported = stylesheet.getGlobalImport(i);
1254          int includedCount = imported.getIncludeCountComposed();
1255
1256          for (int j = -1; j < includedCount; j++)
1257          {
1258            Stylesheet included = imported.getIncludeComposed(j);
1259
1260            included.runtimeInit(this);
1261
1262            for (ElemTemplateElement child = included.getFirstChildElem();
1263                    child != null; child = child.getNextSiblingElem())
1264            {
1265              child.runtimeInit(this);
1266            }
1267          }
1268        }
1269        // ===========
1270
// System.out.println("Calling applyTemplateToNode - "+Thread.currentThread().getName());
1271
DTMIterator dtmIter = new org.apache.xpath.axes.SelfIteratorNoPredicate();
1272        dtmIter.setRoot(node, xctxt);
1273        xctxt.pushContextNodeList(dtmIter);
1274        try
1275        {
1276          this.applyTemplateToNode(null, null, node);
1277        }
1278        finally
1279        {
1280          xctxt.popContextNodeList();
1281        }
1282        // m_stylesheetRoot.getStartRule().execute(this);
1283

1284        // System.out.println("Done with applyTemplateToNode - "+Thread.currentThread().getName());
1285
if (null != m_serializationHandler)
1286        {
1287          m_serializationHandler.endDocument();
1288        }
1289      }
1290      catch (Exception JavaDoc se)
1291      {
1292
1293        // System.out.println(Thread.currentThread().getName()+" threw an exception! "
1294
// +se.getMessage());
1295
// If an exception was thrown, we need to make sure that any waiting
1296
// handlers can terminate, which I guess is best done by sending
1297
// an endDocument.
1298

1299        // SAXSourceLocator
1300
while(se instanceof org.apache.xml.utils.WrappedRuntimeException)
1301        {
1302          Exception JavaDoc e = ((org.apache.xml.utils.WrappedRuntimeException)se).getException();
1303          if(null != e)
1304            se = e;
1305        }
1306        
1307        if (null != m_serializationHandler)
1308        {
1309          try
1310          {
1311            if(se instanceof org.xml.sax.SAXParseException JavaDoc)
1312              m_serializationHandler.fatalError((org.xml.sax.SAXParseException JavaDoc)se);
1313            else if(se instanceof TransformerException JavaDoc)
1314            {
1315              TransformerException JavaDoc te = ((TransformerException JavaDoc)se);
1316              SAXSourceLocator sl = new SAXSourceLocator( te.getLocator() );
1317              m_serializationHandler.fatalError(new org.xml.sax.SAXParseException JavaDoc(te.getMessage(), sl, te));
1318            }
1319            else
1320            {
1321              m_serializationHandler.fatalError(new org.xml.sax.SAXParseException JavaDoc(se.getMessage(), new SAXSourceLocator(), se));
1322            }
1323          }
1324          catch (Exception JavaDoc e){}
1325        }
1326        
1327        if(se instanceof TransformerException JavaDoc)
1328        {
1329          m_errorHandler.fatalError((TransformerException JavaDoc)se);
1330        }
1331        else if(se instanceof org.xml.sax.SAXParseException JavaDoc)
1332        {
1333          m_errorHandler.fatalError(new TransformerException JavaDoc(se.getMessage(),
1334                      new SAXSourceLocator((org.xml.sax.SAXParseException JavaDoc)se),
1335                      se));
1336        }
1337        else
1338        {
1339          m_errorHandler.fatalError(new TransformerException JavaDoc(se));
1340        }
1341        
1342      }
1343      finally
1344      {
1345        this.reset();
1346      }
1347    }
1348  }
1349
1350  /**
1351   * Get a SAX2 ContentHandler for the input.
1352   *
1353   * @return A valid ContentHandler, which should never be null, as
1354   * long as getFeature("http://xml.org/trax/features/sax/input")
1355   * returns true.
1356   */

1357  public ContentHandler JavaDoc getInputContentHandler()
1358  {
1359    return getInputContentHandler(false);
1360  }
1361
1362  /**
1363   * Get a SAX2 ContentHandler for the input.
1364   *
1365   * @param doDocFrag true if a DocumentFragment should be created as
1366   * the root, rather than a Document.
1367   *
1368   * @return A valid ContentHandler, which should never be null, as
1369   * long as getFeature("http://xml.org/trax/features/sax/input")
1370   * returns true.
1371   */

1372  public ContentHandler JavaDoc getInputContentHandler(boolean doDocFrag)
1373  {
1374
1375    if (null == m_inputContentHandler)
1376    {
1377
1378      // if(null == m_urlOfSource && null != m_stylesheetRoot)
1379
// m_urlOfSource = m_stylesheetRoot.getBaseIdentifier();
1380
m_inputContentHandler = new TransformerHandlerImpl(this, doDocFrag,
1381              m_urlOfSource);
1382    }
1383
1384    return m_inputContentHandler;
1385  }
1386
1387  /**
1388   * Get a SAX2 DeclHandler for the input.
1389   * @return A valid DeclHandler, which should never be null, as
1390   * long as getFeature("http://xml.org/trax/features/sax/input")
1391   * returns true.
1392   */

1393  public DeclHandler JavaDoc getInputDeclHandler()
1394  {
1395
1396    if (m_inputContentHandler instanceof DeclHandler JavaDoc)
1397      return (DeclHandler JavaDoc) m_inputContentHandler;
1398    else
1399      return null;
1400  }
1401
1402  /**
1403   * Get a SAX2 LexicalHandler for the input.
1404   * @return A valid LexicalHandler, which should never be null, as
1405   * long as getFeature("http://xml.org/trax/features/sax/input")
1406   * returns true.
1407   */

1408  public LexicalHandler JavaDoc getInputLexicalHandler()
1409  {
1410
1411    if (m_inputContentHandler instanceof LexicalHandler JavaDoc)
1412      return (LexicalHandler JavaDoc) m_inputContentHandler;
1413    else
1414      return null;
1415  }
1416
1417  /**
1418   * Set the output properties for the transformation. These
1419   * properties will override properties set in the templates
1420   * with xsl:output.
1421   *
1422   * @param oformat A valid OutputProperties object (which will
1423   * not be mutated), or null.
1424   */

1425  public void setOutputFormat(OutputProperties oformat)
1426  {
1427    m_outputFormat = oformat;
1428  }
1429
1430  /**
1431   * Get the output properties used for the transformation.
1432   *
1433   * @return the output format that was set by the user,
1434   * otherwise the output format from the stylesheet.
1435   */

1436  public OutputProperties getOutputFormat()
1437  {
1438
1439    // Get the output format that was set by the user, otherwise get the
1440
// output format from the stylesheet.
1441
OutputProperties format = (null == m_outputFormat)
1442                              ? getStylesheet().getOutputComposed()
1443                              : m_outputFormat;
1444
1445    return format;
1446  }
1447
1448  /**
1449   * Set a parameter for the templates.
1450   *
1451   * @param name The name of the parameter.
1452   * @param namespace The namespace of the parameter.
1453   * @param value The value object. This can be any valid Java object
1454   * -- it's up to the processor to provide the proper
1455   * coersion to the object, or simply pass it on for use
1456   * in extensions.
1457   */

1458  public void setParameter(String JavaDoc name, String JavaDoc namespace, Object JavaDoc value)
1459  {
1460
1461    VariableStack varstack = getXPathContext().getVarStack();
1462    QName qname = new QName(namespace, name);
1463    XObject xobject = XObject.create(value, getXPathContext());
1464    
1465    StylesheetRoot sroot = m_stylesheetRoot;
1466    Vector JavaDoc vars = sroot.getVariablesAndParamsComposed();
1467    int i = vars.size();
1468    while (--i >= 0)
1469    {
1470      ElemVariable variable = (ElemVariable)vars.elementAt(i);
1471      if(variable.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE &&
1472         variable.getName().equals(qname))
1473      {
1474          varstack.setGlobalVariable(i, xobject);
1475      }
1476    }
1477  }
1478
1479  /** NEEDSDOC Field m_userParams */
1480  Vector JavaDoc m_userParams;
1481
1482  /**
1483   * Set a parameter for the transformation.
1484   *
1485   * @param name The name of the parameter,
1486   * which may have a namespace URI.
1487   * @param value The value object. This can be any valid Java object
1488   * -- it's up to the processor to provide the proper
1489   * coersion to the object, or simply pass it on for use
1490   * in extensions.
1491   */

1492  public void setParameter(String JavaDoc name, Object JavaDoc value)
1493  {
1494    
1495    if (value == null) {
1496      throw new IllegalArgumentException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_SET_PARAM_VALUE, new Object JavaDoc[]{name}));
1497    }
1498
1499    StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(name, "{}", false);
1500
1501    try
1502    {
1503
1504      // The first string might be the namespace, or it might be
1505
// the local name, if the namespace is null.
1506
String JavaDoc s1 = tokenizer.nextToken();
1507      String JavaDoc s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
1508
1509      if (null == m_userParams)
1510        m_userParams = new Vector JavaDoc();
1511
1512      if (null == s2)
1513      {
1514        replaceOrPushUserParam(new QName(s1), XObject.create(value, getXPathContext()));
1515        setParameter(s1, null, value);
1516      }
1517      else
1518      {
1519        replaceOrPushUserParam(new QName(s1, s2), XObject.create(value, getXPathContext()));
1520        setParameter(s2, s1, value);
1521      }
1522    }
1523    catch (java.util.NoSuchElementException JavaDoc nsee)
1524    {
1525
1526      // Should throw some sort of an error.
1527
}
1528  }
1529
1530  /**
1531   * NEEDSDOC Method replaceOrPushUserParam
1532   *
1533   *
1534   * NEEDSDOC @param qname
1535   * NEEDSDOC @param xval
1536   */

1537  private void replaceOrPushUserParam(QName qname, XObject xval)
1538  {
1539
1540    int n = m_userParams.size();
1541
1542    for (int i = n - 1; i >= 0; i--)
1543    {
1544      Arg arg = (Arg) m_userParams.elementAt(i);
1545
1546      if (arg.getQName().equals(qname))
1547      {
1548        m_userParams.setElementAt(new Arg(qname, xval, true), i);
1549
1550        return;
1551      }
1552    }
1553
1554    m_userParams.addElement(new Arg(qname, xval, true));
1555  }
1556
1557  /**
1558   * Get a parameter that was explicitly set with setParameter
1559   * or setParameters.
1560   *
1561   *
1562   * NEEDSDOC @param name
1563   * @return A parameter that has been set with setParameter
1564   * or setParameters,
1565   * *not* all the xsl:params on the stylesheet (which require
1566   * a transformation Source to be evaluated).
1567   */

1568  public Object JavaDoc getParameter(String JavaDoc name)
1569  {
1570
1571    try
1572    {
1573
1574      // VariableStack varstack = getXPathContext().getVarStack();
1575
// The first string might be the namespace, or it might be
1576
// the local name, if the namespace is null.
1577
QName qname = QName.getQNameFromString(name);
1578
1579      if (null == m_userParams)
1580        return null;
1581
1582      int n = m_userParams.size();
1583
1584      for (int i = n - 1; i >= 0; i--)
1585      {
1586        Arg arg = (Arg) m_userParams.elementAt(i);
1587
1588        if (arg.getQName().equals(qname))
1589        {
1590          return arg.getVal().object();
1591        }
1592      }
1593
1594      return null;
1595    }
1596    catch (java.util.NoSuchElementException JavaDoc nsee)
1597    {
1598
1599      // Should throw some sort of an error.
1600
return null;
1601    }
1602  }
1603  
1604  /**
1605   * Reset parameters that the user specified for the transformation.
1606   * Called during transformer.reset() after we have cleared the
1607   * variable stack. We need to make sure that user params are
1608   * reset so that the transformer object can be reused.
1609   */

1610  private void resetUserParameters()
1611  {
1612
1613    try
1614    {
1615      
1616      if (null == m_userParams)
1617        return;
1618
1619      int n = m_userParams.size();
1620      for (int i = n - 1; i >= 0; i--)
1621      {
1622        Arg arg = (Arg) m_userParams.elementAt(i);
1623        QName name = arg.getQName();
1624        // The first string might be the namespace, or it might be
1625
// the local name, if the namespace is null.
1626
String JavaDoc s1 = name.getNamespace();
1627        String JavaDoc s2 = name.getLocalPart();
1628
1629        setParameter(s2, s1, arg.getVal().object());
1630        
1631      }
1632      
1633    }
1634    catch (java.util.NoSuchElementException JavaDoc nsee)
1635    {
1636      // Should throw some sort of an error.
1637

1638    }
1639  }
1640
1641  /**
1642   * Set a bag of parameters for the transformation. Note that
1643   * these will not be additive, they will replace the existing
1644   * set of parameters.
1645   *
1646   * @param name The name of the parameter,
1647   * which may have a namespace URI.
1648   * @param value The value object. This can be any valid Java object
1649   * -- it's up to the processor to provide the proper
1650   * coersion to the object, or simply pass it on for use
1651   * in extensions.
1652   *
1653   * NEEDSDOC @param params
1654   */

1655  public void setParameters(Properties JavaDoc params)
1656  {
1657
1658    clearParameters();
1659
1660    Enumeration JavaDoc names = params.propertyNames();
1661
1662    while (names.hasMoreElements())
1663    {
1664      String JavaDoc name = params.getProperty((String JavaDoc) names.nextElement());
1665      StringTokenizer JavaDoc tokenizer = new StringTokenizer JavaDoc(name, "{}", false);
1666
1667      try
1668      {
1669
1670        // The first string might be the namespace, or it might be
1671
// the local name, if the namespace is null.
1672
String JavaDoc s1 = tokenizer.nextToken();
1673        String JavaDoc s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
1674
1675        if (null == s2)
1676          setParameter(s1, null, params.getProperty(name));
1677        else
1678          setParameter(s2, s1, params.getProperty(name));
1679      }
1680      catch (java.util.NoSuchElementException JavaDoc nsee)
1681      {
1682
1683        // Should throw some sort of an error.
1684
}
1685    }
1686  }
1687
1688  /**
1689   * Reset the parameters to a null list.
1690   */

1691  public void clearParameters()
1692  {
1693
1694    synchronized (m_reentryGuard)
1695    {
1696      VariableStack varstack = new VariableStack();
1697
1698      m_xcontext.setVarStack(varstack);
1699
1700      m_userParams = null;
1701    }
1702  }
1703
1704
1705  /**
1706   * Internal -- push the global variables from the Stylesheet onto
1707   * the context's runtime variable stack.
1708   * <p>If we encounter a variable
1709   * that is already defined in the variable stack, we ignore it. This
1710   * is because the second variable definition will be at a lower import
1711   * precedence. Presumably, global"variables at the same import precedence
1712   * with the same name will have been caught during the recompose process.
1713   * <p>However, if we encounter a parameter that is already defined in the
1714   * variable stack, we need to see if this is a parameter whose value was
1715   * supplied by a setParameter call. If so, we need to "receive" the one
1716   * already in the stack, ignoring this one. If it is just an earlier
1717   * xsl:param or xsl:variable definition, we ignore it using the same
1718   * reasoning as explained above for the variable.
1719   *
1720   * @param contextNode The root of the source tree, can't be null.
1721   *
1722   * @throws TransformerException
1723   */

1724  protected void pushGlobalVars(int contextNode) throws TransformerException JavaDoc
1725  {
1726
1727    XPathContext xctxt = m_xcontext;
1728    VariableStack vs = xctxt.getVarStack();
1729    StylesheetRoot sr = getStylesheet();
1730    Vector JavaDoc vars = sr.getVariablesAndParamsComposed();
1731    
1732    int i = vars.size();
1733    vs.link(i);
1734
1735    while (--i >= 0)
1736    {
1737      ElemVariable v = (ElemVariable) vars.elementAt(i);
1738
1739      // XObject xobj = v.getValue(this, contextNode);
1740
XObject xobj = new XUnresolvedVariable(v, contextNode, this,
1741                                     vs.getStackFrame(), 0, true);
1742      
1743      if(null == vs.elementAt(i))
1744        vs.setGlobalVariable(i, xobj);
1745    }
1746
1747  }
1748
1749  /**
1750   * Set an object that will be used to resolve URIs used in
1751   * document(), etc.
1752   * @param resolver An object that implements the URIResolver interface,
1753   * or null.
1754   */

1755  public void setURIResolver(URIResolver JavaDoc resolver)
1756  {
1757
1758    synchronized (m_reentryGuard)
1759    {
1760      m_xcontext.getSourceTreeManager().setURIResolver(resolver);
1761    }
1762  }
1763
1764  /**
1765   * Get an object that will be used to resolve URIs used in
1766   * document(), etc.
1767   *
1768   * @return An object that implements the URIResolver interface,
1769   * or null.
1770   */

1771  public URIResolver JavaDoc getURIResolver()
1772  {
1773    return m_xcontext.getSourceTreeManager().getURIResolver();
1774  }
1775
1776  // ======== End Transformer Implementation ========
1777

1778  /**
1779   * Set the content event handler.
1780   *
1781   * @param resolver The new content handler.
1782   *
1783   * NEEDSDOC @param handler
1784   * @throws java.lang.NullPointerException If the handler
1785   * is null.
1786   * @see org.xml.sax.XMLReader#setContentHandler
1787   */

1788  public void setContentHandler(ContentHandler JavaDoc handler)
1789  {
1790
1791    if (handler == null)
1792    {
1793      throw new NullPointerException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_CONTENT_HANDLER, null)); //"Null content handler");
1794
}
1795    else
1796    {
1797      m_outputContentHandler = handler;
1798
1799      if (null == m_serializationHandler)
1800      {
1801        ToXMLSAXHandler h = new ToXMLSAXHandler();
1802        h.setContentHandler(handler);
1803        h.setTransformer(this);
1804        
1805        m_serializationHandler = h;
1806      }
1807      else
1808        m_serializationHandler.setContentHandler(handler);
1809    }
1810  }
1811
1812  /**
1813   * Get the content event handler.
1814   *
1815   * @return The current content handler, or null if none was set.
1816   * @see org.xml.sax.XMLReader#getContentHandler
1817   */

1818  public ContentHandler JavaDoc getContentHandler()
1819  {
1820    return m_outputContentHandler;
1821  }
1822
1823  /**
1824   * Given a stylesheet element, create a result tree fragment from it's
1825   * contents. The fragment will be built within the shared RTF DTM system
1826   * used as a variable stack.
1827   * @param templateParent The template element that holds the fragment.
1828   * @return the NodeHandle for the root node of the resulting RTF.
1829   *
1830   * @throws TransformerException
1831   * @xsl.usage advanced
1832   */

1833  public int transformToRTF(ElemTemplateElement templateParent)
1834          throws TransformerException JavaDoc
1835  {
1836    // Retrieve a DTM to contain the RTF. At this writing, this may be a
1837
// multi-document DTM (SAX2RTFDTM).
1838
DTM dtmFrag = m_xcontext.getRTFDTM();
1839    return transformToRTF(templateParent,dtmFrag);
1840  }
1841  
1842  /**
1843   * Given a stylesheet element, create a result tree fragment from it's
1844   * contents. The fragment will also use the shared DTM system, but will
1845   * obtain its space from the global variable pool rather than the dynamic
1846   * variable stack. This allows late binding of XUnresolvedVariables without
1847   * the risk that their content will be discarded when the variable stack
1848   * is popped.
1849   *
1850   * @param templateParent The template element that holds the fragment.
1851   * @return the NodeHandle for the root node of the resulting RTF.
1852   *
1853   * @throws TransformerException
1854   * @xsl.usage advanced
1855   */

1856  public int transformToGlobalRTF(ElemTemplateElement templateParent)
1857          throws TransformerException JavaDoc
1858  {
1859    // Retrieve a DTM to contain the RTF. At this writing, this may be a
1860
// multi-document DTM (SAX2RTFDTM).
1861
DTM dtmFrag = m_xcontext.getGlobalRTFDTM();
1862    return transformToRTF(templateParent,dtmFrag);
1863  }
1864  
1865  /**
1866   * Given a stylesheet element, create a result tree fragment from it's
1867   * contents.
1868   * @param templateParent The template element that holds the fragment.
1869   * @param dtmFrag The DTM to write the RTF into
1870   * @return the NodeHandle for the root node of the resulting RTF.
1871   *
1872   * @throws TransformerException
1873   * @xsl.usage advanced
1874   */

1875  private int transformToRTF(ElemTemplateElement templateParent,DTM dtmFrag)
1876          throws TransformerException JavaDoc
1877  {
1878
1879    XPathContext xctxt = m_xcontext;
1880    
1881    ContentHandler JavaDoc rtfHandler = dtmFrag.getContentHandler();
1882
1883    // Obtain the ResultTreeFrag's root node.
1884
// NOTE: In SAX2RTFDTM, this value isn't available until after
1885
// the startDocument has been issued, so assignment has been moved
1886
// down a bit in the code.
1887
int resultFragment; // not yet reliably = dtmFrag.getDocument();
1888

1889    // Save the current result tree handler.
1890
SerializationHandler savedRTreeHandler = this.m_serializationHandler;
1891 
1892
1893    // And make a new handler for the RTF.
1894
ToSAXHandler h = new ToXMLSAXHandler();
1895    h.setContentHandler(rtfHandler);
1896    h.setTransformer(this);
1897    
1898    // Replace the old handler (which was already saved)
1899
m_serializationHandler = h;
1900 
1901    // use local variable for the current handler
1902
SerializationHandler rth = m_serializationHandler;
1903
1904    try
1905    {
1906      rth.startDocument();
1907      
1908      // startDocument is "bottlenecked" in RTH. We need it acted upon immediately,
1909
// to set the DTM's state as in-progress, so that if the xsl:variable's body causes
1910
// further RTF activity we can keep that from bashing this DTM.
1911
rth.flushPending();
1912 
1913      try
1914      {
1915
1916        // Do the transformation of the child elements.
1917
executeChildTemplates(templateParent, true);
1918
1919        // Make sure everything is flushed!
1920
rth.flushPending();
1921        
1922        // Get the document ID. May not exist until the RTH has not only
1923
// received, but flushed, the startDocument, and may be invalid
1924
// again after the document has been closed (still debating that)
1925
// ... so waiting until just before the end seems simplest/safest.
1926
resultFragment = dtmFrag.getDocument();
1927      }
1928      finally
1929      {
1930        rth.endDocument();
1931      }
1932    }
1933    catch (org.xml.sax.SAXException JavaDoc se)
1934    {
1935      throw new TransformerException JavaDoc(se);
1936    }
1937    finally
1938    {
1939
1940      // Restore the previous result tree handler.
1941
this.m_serializationHandler = savedRTreeHandler;
1942    }
1943
1944    return resultFragment;
1945  }
1946
1947  /**
1948   * Get the StringWriter pool, so that StringWriter
1949   * objects may be reused.
1950   *
1951   * @return The string writer pool, not null.
1952   * @xsl.usage internal
1953   */

1954  public ObjectPool getStringWriterPool()
1955  {
1956    return m_stringWriterObjectPool;
1957  }
1958
1959  /**
1960   * Take the contents of a template element, process it, and
1961   * convert it to a string.
1962   *
1963   * @param elem The parent element whose children will be output
1964   * as a string.
1965   * @param transformer The XSLT transformer instance.
1966   * @param sourceNode The current source node context.
1967   * @param mode The current xslt mode.
1968   *
1969   * @return The stringized result of executing the elements children.
1970   *
1971   * @throws TransformerException
1972   * @xsl.usage advanced
1973   */

1974  public String JavaDoc transformToString(ElemTemplateElement elem)
1975          throws TransformerException JavaDoc
1976  {
1977    ElemTemplateElement firstChild = elem.getFirstChildElem();
1978    if(null == firstChild)
1979      return "";
1980    if(elem.hasTextLitOnly() && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize)
1981    {
1982      return ((ElemTextLiteral)firstChild).getNodeValue();
1983    }
1984
1985    // Save the current result tree handler.
1986
SerializationHandler savedRTreeHandler = this.m_serializationHandler;
1987
1988    // Create a Serializer object that will handle the SAX events
1989
// and build the ResultTreeFrag nodes.
1990
StringWriter JavaDoc sw = (StringWriter JavaDoc) m_stringWriterObjectPool.getInstance();
1991
1992    m_serializationHandler =
1993        (ToTextStream) m_textResultHandlerObjectPool.getInstance();
1994
1995      if (null == m_serializationHandler)
1996      {
1997        // if we didn't get one from the pool, go make a new one
1998

1999        
2000        Serializer serializer = org.apache.xml.serializer.SerializerFactory.getSerializer(
2001            m_textformat.getProperties());
2002        m_serializationHandler = (SerializationHandler) serializer;
2003      }
2004
2005        m_serializationHandler.setTransformer(this);
2006        m_serializationHandler.setWriter(sw);
2007 
2008 
2009    String JavaDoc result;
2010
2011    try
2012    {
2013        /* Don't call startDocument, the SerializationHandler will
2014         * generate its own internal startDocument call anyways
2015         */

2016      // this.m_serializationHandler.startDocument();
2017

2018      // Do the transformation of the child elements.
2019
executeChildTemplates(elem, true);
2020        this.m_serializationHandler.endDocument();
2021
2022      result = sw.toString();
2023    }
2024    catch (org.xml.sax.SAXException JavaDoc se)
2025    {
2026      throw new TransformerException JavaDoc(se);
2027    }
2028    finally
2029    {
2030      sw.getBuffer().setLength(0);
2031
2032      try
2033      {
2034        sw.close();
2035      }
2036      catch (Exception JavaDoc ioe){}
2037
2038      m_stringWriterObjectPool.freeInstance(sw);
2039      m_serializationHandler.reset();
2040      m_textResultHandlerObjectPool.freeInstance(m_serializationHandler);
2041
2042      // Restore the previous result tree handler.
2043
m_serializationHandler = savedRTreeHandler;
2044    }
2045
2046    return result;
2047  }
2048
2049  /**
2050   * Given an element and mode, find the corresponding
2051   * template and process the contents.
2052   *
2053   * @param xslInstruction The calling element.
2054   * @param template The template to use if xsl:for-each, or null.
2055   * @param child The source context node.
2056   * @param mode The current mode, may be null.
2057   * @throws TransformerException
2058   * @return true if applied a template, false if not.
2059   * @xsl.usage advanced
2060   */

2061  public boolean applyTemplateToNode(ElemTemplateElement xslInstruction, // xsl:apply-templates or xsl:for-each
2062
ElemTemplate template, int child)
2063                                             throws TransformerException JavaDoc
2064  {
2065
2066    DTM dtm = m_xcontext.getDTM(child);
2067    short nodeType = dtm.getNodeType(child);
2068    boolean isDefaultTextRule = false;
2069    boolean isApplyImports = false;
2070
2071    if (null == template)
2072    {
2073      int maxImportLevel, endImportLevel=0;
2074      isApplyImports = ((xslInstruction == null)
2075                                ? false
2076                                : xslInstruction.getXSLToken()
2077                                  == Constants.ELEMNAME_APPLY_IMPORTS);
2078
2079      if (isApplyImports)
2080      {
2081        maxImportLevel =
2082          xslInstruction.getStylesheetComposed().getImportCountComposed() - 1;
2083        endImportLevel =
2084          xslInstruction.getStylesheetComposed().getEndImportCountComposed();
2085      }
2086      else
2087      {
2088        maxImportLevel = -1;
2089      }
2090
2091      // If we're trying an xsl:apply-imports at the top level (ie there are no
2092
// imported stylesheets), we need to indicate that there is no matching template.
2093
// The above logic will calculate a maxImportLevel of -1 which indicates
2094
// that we should find any template. This is because a value of -1 for
2095
// maxImportLevel has a special meaning. But we don't want that.
2096
// We want to match -no- templates. See bugzilla bug 1170.
2097
if (isApplyImports && (maxImportLevel == -1))
2098      {
2099        template = null;
2100      }
2101      else
2102      {
2103
2104        // Find the XSL template that is the best match for the
2105
// element.
2106
XPathContext xctxt = m_xcontext;
2107
2108        try
2109        {
2110          xctxt.pushNamespaceContext(xslInstruction);
2111
2112          QName mode = this.getMode();
2113          
2114          if (isApplyImports)
2115            template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode,
2116                  maxImportLevel, endImportLevel, m_quietConflictWarnings, dtm);
2117          else
2118            template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode,
2119                  m_quietConflictWarnings, dtm);
2120          
2121        }
2122        finally
2123        {
2124          xctxt.popNamespaceContext();
2125        }
2126      }
2127
2128      // If that didn't locate a node, fall back to a default template rule.
2129
// See http://www.w3.org/TR/xslt#built-in-rule.
2130
if (null == template)
2131      {
2132        switch (nodeType)
2133        {
2134        case DTM.DOCUMENT_FRAGMENT_NODE :
2135        case DTM.ELEMENT_NODE :
2136          template = m_stylesheetRoot.getDefaultRule();
2137          break;
2138        case DTM.CDATA_SECTION_NODE :
2139        case DTM.TEXT_NODE :
2140        case DTM.ATTRIBUTE_NODE :
2141          template = m_stylesheetRoot.getDefaultTextRule();
2142          isDefaultTextRule = true;
2143          break;
2144        case DTM.DOCUMENT_NODE :
2145          template = m_stylesheetRoot.getDefaultRootRule();
2146          break;
2147        default :
2148
2149          // No default rules for processing instructions and the like.
2150
return false;
2151        }
2152      }
2153    }
2154
2155    // If we are processing the default text rule, then just clone
2156
// the value directly to the result tree.
2157
try
2158    {
2159      pushElemTemplateElement(template);
2160      m_xcontext.pushCurrentNode(child);
2161      pushPairCurrentMatched(template, child);
2162      
2163      // Fix copy copy29 test.
2164
if (!isApplyImports) {
2165          DTMIterator cnl = new org.apache.xpath.NodeSetDTM(child, m_xcontext.getDTMManager());
2166          m_xcontext.pushContextNodeList(cnl);
2167      }
2168
2169      if (isDefaultTextRule)
2170      {
2171        switch (nodeType)
2172        {
2173        case DTM.CDATA_SECTION_NODE :
2174        case DTM.TEXT_NODE :
2175          ClonerToResultTree.cloneToResultTree(child, nodeType,
2176                                        dtm, getResultTreeHandler(), false);
2177          break;
2178        case DTM.ATTRIBUTE_NODE :
2179          dtm.dispatchCharactersEvents(child, getResultTreeHandler(), false);
2180          break;
2181        }
2182      }
2183      else
2184      {
2185
2186        // Fire a trace event for the template.
2187

2188        if (TransformerImpl.S_DEBUG)
2189          getTraceManager().fireTraceEvent(template);
2190        // And execute the child templates.
2191
// 9/11/00: If template has been compiled, hand off to it
2192
// since much (most? all?) of the processing has been inlined.
2193
// (It would be nice if there was a single entry point that
2194
// worked for both... but the interpretive system works by
2195
// having the Tranformer execute the children, while the
2196
// compiled obviously has to run its own code. It's
2197
// also unclear that "execute" is really the right name for
2198
// that entry point.)
2199
m_xcontext.setSAXLocator(template);
2200        // m_xcontext.getVarStack().link();
2201
m_xcontext.getVarStack().link(template.m_frameSize);
2202        executeChildTemplates(template, true);
2203        
2204        if (TransformerImpl.S_DEBUG)
2205          getTraceManager().fireTraceEndEvent(template);
2206      }
2207    }
2208    catch (org.xml.sax.SAXException JavaDoc se)
2209    {
2210      throw new TransformerException JavaDoc(se);
2211    }
2212    finally
2213    {
2214      if (!isDefaultTextRule)
2215        m_xcontext.getVarStack().unlink();
2216      m_xcontext.popCurrentNode();
2217      if (!isApplyImports) {
2218          m_xcontext.popContextNodeList();
2219          popCurrentMatched();
2220      }
2221      popElemTemplateElement();
2222    }
2223
2224    return true;
2225  }
2226  
2227  
2228  /**
2229   * Execute each of the children of a template element. This method
2230   * is only for extension use.
2231   *
2232   * @param elem The ElemTemplateElement that contains the children
2233   * that should execute.
2234   * @param sourceNode The current context node.
2235   * NEEDSDOC @param context
2236   * @param mode The current mode.
2237   * @param handler The ContentHandler to where the result events
2238   * should be fed.
2239   *
2240   * @throws TransformerException
2241   * @xsl.usage advanced
2242   */

2243  public void executeChildTemplates(
2244          ElemTemplateElement elem, org.w3c.dom.Node JavaDoc context, QName mode, ContentHandler JavaDoc handler)
2245            throws TransformerException JavaDoc
2246  {
2247
2248    XPathContext xctxt = m_xcontext;
2249
2250    try
2251    {
2252      if(null != mode)
2253        pushMode(mode);
2254      xctxt.pushCurrentNode(xctxt.getDTMHandleFromNode(context));
2255      executeChildTemplates(elem, handler);
2256    }
2257    finally
2258    {
2259      xctxt.popCurrentNode();
2260      
2261      // I'm not sure where or why this was here. It is clearly in
2262
// error though, without a corresponding pushMode().
2263
if (null != mode)
2264        popMode();
2265    }
2266  }
2267
2268  /**
2269   * Execute each of the children of a template element.
2270   *
2271   * @param transformer The XSLT transformer instance.
2272   *
2273   * @param elem The ElemTemplateElement that contains the children
2274   * that should execute.
2275   * @param sourceNode The current context node.
2276   * @param mode The current mode.
2277   * @param shouldAddAttrs true if xsl:attributes should be executed.
2278   *
2279   * @throws TransformerException
2280   * @xsl.usage advanced
2281   */

2282  public void executeChildTemplates(
2283          ElemTemplateElement elem, boolean shouldAddAttrs)
2284            throws TransformerException JavaDoc
2285  {
2286
2287    // Does this element have any children?
2288
ElemTemplateElement t = elem.getFirstChildElem();
2289
2290    if (null == t)
2291      return;
2292    
2293    if(elem.hasTextLitOnly() && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize)
2294    {
2295      char[] chars = ((ElemTextLiteral)t).getChars();
2296      try
2297      {
2298        // Have to push stuff on for tooling...
2299
this.pushElemTemplateElement(t);
2300        m_serializationHandler.characters(chars, 0, chars.length);
2301      }
2302      catch(SAXException JavaDoc se)
2303      {
2304        throw new TransformerException JavaDoc(se);
2305      }
2306      finally
2307      {
2308        this.popElemTemplateElement();
2309      }
2310      return;
2311    }
2312
2313// // Check for infinite loops if we have to.
2314
// boolean check = (m_stackGuard.m_recursionLimit > -1);
2315
//
2316
// if (check)
2317
// getStackGuard().push(elem, xctxt.getCurrentNode());
2318

2319    XPathContext xctxt = m_xcontext;
2320    xctxt.pushSAXLocatorNull();
2321    int currentTemplateElementsTop = m_currentTemplateElements.size();
2322    m_currentTemplateElements.push(null);
2323
2324    try
2325    {
2326      // Loop through the children of the template, calling execute on
2327
// each of them.
2328
for (; t != null; t = t.getNextSiblingElem())
2329      {
2330        if (!shouldAddAttrs
2331                && t.getXSLToken() == Constants.ELEMNAME_ATTRIBUTE)
2332          continue;
2333
2334        xctxt.setSAXLocator(t);
2335        m_currentTemplateElements.setElementAt(t,currentTemplateElementsTop);
2336        t.execute(this);
2337      }
2338    }
2339    catch(RuntimeException JavaDoc re)
2340    {
2341        TransformerException JavaDoc te = new TransformerException JavaDoc(re);
2342        te.setLocator(t);
2343        throw te;
2344    }
2345    finally
2346    {
2347      m_currentTemplateElements.pop();
2348      xctxt.popSAXLocator();
2349    }
2350
2351    // Check for infinite loops if we have to
2352
// if (check)
2353
// getStackGuard().pop();
2354
}
2355    /**
2356      * Execute each of the children of a template element.
2357      *
2358      * @param elem The ElemTemplateElement that contains the children
2359      * that should execute.
2360      * @param handler The ContentHandler to where the result events
2361      * should be fed.
2362      *
2363      * @throws TransformerException
2364      * @xsl.usage advanced
2365      */

2366     public void executeChildTemplates(
2367             ElemTemplateElement elem, ContentHandler JavaDoc handler)
2368               throws TransformerException JavaDoc
2369     {
2370
2371       SerializationHandler xoh = this.getSerializationHandler();
2372
2373       // These may well not be the same! In this case when calling
2374
// the Redirect extension, it has already set the ContentHandler
2375
// in the Transformer.
2376
SerializationHandler savedHandler = xoh;
2377
2378       try
2379       {
2380         xoh.flushPending();
2381
2382         // %REVIEW% Make sure current node is being pushed.
2383
LexicalHandler JavaDoc lex = null;
2384         if (handler instanceof LexicalHandler JavaDoc) {
2385            lex = (LexicalHandler JavaDoc) handler;
2386         }
2387         m_serializationHandler = new ToXMLSAXHandler(handler, lex, savedHandler.getEncoding());
2388         m_serializationHandler.setTransformer(this);
2389         executeChildTemplates(elem, true);
2390       }
2391       catch (TransformerException JavaDoc e)
2392       {
2393         throw e;
2394       }
2395       catch (SAXException JavaDoc se) {
2396         throw new TransformerException JavaDoc(se);
2397       }
2398       finally
2399       {
2400         m_serializationHandler = savedHandler;
2401    }
2402  }
2403
2404  /**
2405   * Get the keys for the xsl:sort elements.
2406   * Note: Should this go into ElemForEach?
2407   *
2408   * @param foreach Valid ElemForEach element, not null.
2409   * @param sourceNodeContext The current node context in the source tree,
2410   * needed to evaluate the Attribute Value Templates.
2411   *
2412   * @return A Vector of NodeSortKeys, or null.
2413   *
2414   * @throws TransformerException
2415   * @xsl.usage advanced
2416   */

2417  public Vector JavaDoc processSortKeys(ElemForEach foreach, int sourceNodeContext)
2418          throws TransformerException JavaDoc
2419  {
2420
2421    Vector JavaDoc keys = null;
2422    XPathContext xctxt = m_xcontext;
2423    int nElems = foreach.getSortElemCount();
2424
2425    if (nElems > 0)
2426      keys = new Vector JavaDoc();
2427
2428    // March backwards, collecting the sort keys.
2429
for (int i = 0; i < nElems; i++)
2430    {
2431      ElemSort sort = foreach.getSortElem(i);
2432      
2433      if (TransformerImpl.S_DEBUG)
2434        getTraceManager().fireTraceEvent(sort);
2435     
2436      String JavaDoc langString =
2437        (null != sort.getLang())
2438        ? sort.getLang().evaluate(xctxt, sourceNodeContext, foreach) : null;
2439      String JavaDoc dataTypeString = sort.getDataType().evaluate(xctxt,
2440                                sourceNodeContext, foreach);
2441
2442      if (dataTypeString.indexOf(":") >= 0)
2443        System.out.println(
2444          "TODO: Need to write the hooks for QNAME sort data type");
2445      else if (!(dataTypeString.equalsIgnoreCase(Constants.ATTRVAL_DATATYPE_TEXT))
2446               &&!(dataTypeString.equalsIgnoreCase(
2447                 Constants.ATTRVAL_DATATYPE_NUMBER)))
2448        foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2449                      new Object JavaDoc[]{ Constants.ATTRNAME_DATATYPE,
2450                                    dataTypeString });
2451
2452      boolean treatAsNumbers =
2453        ((null != dataTypeString) && dataTypeString.equals(
2454        Constants.ATTRVAL_DATATYPE_NUMBER)) ? true : false;
2455      String JavaDoc orderString = sort.getOrder().evaluate(xctxt, sourceNodeContext,
2456                             foreach);
2457
2458      if (!(orderString.equalsIgnoreCase(Constants.ATTRVAL_ORDER_ASCENDING))
2459              &&!(orderString.equalsIgnoreCase(
2460                Constants.ATTRVAL_ORDER_DESCENDING)))
2461        foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2462                      new Object JavaDoc[]{ Constants.ATTRNAME_ORDER,
2463                                    orderString });
2464
2465      boolean descending =
2466        ((null != orderString) && orderString.equals(
2467        Constants.ATTRVAL_ORDER_DESCENDING)) ? true : false;
2468      AVT caseOrder = sort.getCaseOrder();
2469      boolean caseOrderUpper;
2470
2471      if (null != caseOrder)
2472      {
2473        String JavaDoc caseOrderString = caseOrder.evaluate(xctxt, sourceNodeContext,
2474                                                    foreach);
2475
2476        if (!(caseOrderString.equalsIgnoreCase(Constants.ATTRVAL_CASEORDER_UPPER))
2477                &&!(caseOrderString.equalsIgnoreCase(
2478                  Constants.ATTRVAL_CASEORDER_LOWER)))
2479          foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2480                        new Object JavaDoc[]{ Constants.ATTRNAME_CASEORDER,
2481                                      caseOrderString });
2482
2483        caseOrderUpper =
2484          ((null != caseOrderString) && caseOrderString.equals(
2485          Constants.ATTRVAL_CASEORDER_UPPER)) ? true : false;
2486      }
2487      else
2488      {
2489        caseOrderUpper = false;
2490      }
2491
2492      keys.addElement(new NodeSortKey(this, sort.getSelect(), treatAsNumbers,
2493                                      descending, langString, caseOrderUpper,
2494                                      foreach));
2495      if (TransformerImpl.S_DEBUG)
2496        getTraceManager().fireTraceEndEvent(sort);
2497     }
2498
2499    return keys;
2500  }
2501
2502  //==========================================================
2503
// SECTION: TransformState implementation
2504
//==========================================================
2505

2506  /**
2507   * Get the stack of ElemTemplateElements.
2508   *
2509   * @return A copy of stack that contains the xsl element instructions,
2510   * the earliest called in index zero, and the latest called in index size()-1.
2511   */

2512  public Vector JavaDoc getElementCallstack()
2513  {
2514    Vector JavaDoc elems = new Vector JavaDoc();
2515    int nStackSize = m_currentTemplateElements.size();
2516    for(int i = 0; i < nStackSize; i++)
2517    {
2518        ElemTemplateElement elem = (ElemTemplateElement) m_currentTemplateElements.elementAt(i);
2519        if(null != elem)
2520        {
2521            elems.addElement(elem);
2522        }
2523    }
2524    return elems;
2525  }
2526  
2527  /**
2528   * Get the count of how many elements are
2529   * active.
2530   * @return The number of active elements on
2531   * the currentTemplateElements stack.
2532   */

2533  public int getCurrentTemplateElementsCount()
2534  {
2535    return m_currentTemplateElements.size();
2536  }
2537  
2538  
2539  /**
2540   * Get the count of how many elements are
2541   * active.
2542   * @return The number of active elements on
2543   * the currentTemplateElements stack.
2544   */

2545  public ObjectStack getCurrentTemplateElements()
2546  {
2547    return m_currentTemplateElements;
2548  }
2549
2550  /**
2551   * Push the current template element.
2552   *
2553   * @param elem The current ElemTemplateElement (may be null, and then
2554   * set via setCurrentElement).
2555   */

2556  public void pushElemTemplateElement(ElemTemplateElement elem)
2557  {
2558    m_currentTemplateElements.push(elem);
2559  }
2560
2561  /**
2562   * Pop the current template element.
2563   */

2564  public void popElemTemplateElement()
2565  {
2566    m_currentTemplateElements.pop();
2567  }
2568
2569  /**
2570   * Set the top of the current template elements
2571   * stack.
2572   *
2573   * @param e The current ElemTemplateElement about to
2574   * be executed.
2575   */

2576  public void setCurrentElement(ElemTemplateElement e)
2577  {
2578    m_currentTemplateElements.setTop(e);
2579  }
2580
2581  /**
2582   * Retrieves the current ElemTemplateElement that is
2583   * being executed.
2584   *
2585   * @return The current ElemTemplateElement that is executing,
2586   * should not normally be null.
2587   */

2588  public ElemTemplateElement getCurrentElement()
2589  {
2590    return (m_currentTemplateElements.size() > 0) ?
2591        (ElemTemplateElement) m_currentTemplateElements.peek() : null;
2592  }
2593
2594  /**
2595   * This method retrieves the current context node
2596   * in the source tree.
2597   *
2598   * @return The current context node (should never be null?).
2599   */

2600  public int getCurrentNode()
2601  {
2602    return m_xcontext.getCurrentNode();
2603  }
2604  
2605  /**
2606   * Get the call stack of xsl:template elements.
2607   *
2608   * @return A copy of stack that contains the xsl:template
2609   * (ElemTemplate) instructions, the earliest called in index
2610   * zero, and the latest called in index size()-1.
2611   */

2612  public Vector JavaDoc getTemplateCallstack()
2613  {
2614    Vector JavaDoc elems = new Vector JavaDoc();
2615    int nStackSize = m_currentTemplateElements.size();
2616    for(int i = 0; i < nStackSize; i++)
2617    {
2618        ElemTemplateElement elem = (ElemTemplateElement) m_currentTemplateElements.elementAt(i);
2619        if(null != elem && (elem.getXSLToken() != Constants.ELEMNAME_TEMPLATE))
2620        {
2621            elems.addElement(elem);
2622        }
2623    }
2624    return elems;
2625  }
2626
2627
2628  /**
2629   * This method retrieves the xsl:template
2630   * that is in effect, which may be a matched template
2631   * or a named template.
2632   *
2633   * <p>Please note that the ElemTemplate returned may
2634   * be a default template, and thus may not have a template
2635   * defined in the stylesheet.</p>
2636   *
2637   * @return The current xsl:template, should not be null.
2638   */

2639  public ElemTemplate getCurrentTemplate()
2640  {
2641
2642    ElemTemplateElement elem = getCurrentElement();
2643
2644    while ((null != elem)
2645           && (elem.getXSLToken() != Constants.ELEMNAME_TEMPLATE))
2646    {
2647      elem = elem.getParentElem();
2648    }
2649
2650    return (ElemTemplate) elem;
2651  }
2652
2653  /**
2654   * Push both the current xsl:template or xsl:for-each onto the
2655   * stack, along with the child node that was matched.
2656   * (Note: should this only be used for xsl:templates?? -sb)
2657   *
2658   * @param template xsl:template or xsl:for-each.
2659   * @param child The child that was matched.
2660   */

2661  public void pushPairCurrentMatched(ElemTemplateElement template, int child)
2662  {
2663    m_currentMatchTemplates.push(template);
2664    m_currentMatchedNodes.push(child);
2665  }
2666
2667  /**
2668   * Pop the elements that were pushed via pushPairCurrentMatched.
2669   */

2670  public void popCurrentMatched()
2671  {
2672    m_currentMatchTemplates.pop();
2673    m_currentMatchedNodes.pop();
2674  }
2675
2676  /**
2677   * This method retrieves the xsl:template
2678   * that was matched. Note that this may not be
2679   * the same thing as the current template (which
2680   * may be from getCurrentElement()), since a named
2681   * template may be in effect.
2682   *
2683   * @return The pushed template that was pushed via pushPairCurrentMatched.
2684   */

2685  public ElemTemplate getMatchedTemplate()
2686  {
2687    return (ElemTemplate) m_currentMatchTemplates.peek();
2688  }
2689
2690  /**
2691   * Retrieves the node in the source tree that matched
2692   * the template obtained via getMatchedTemplate().
2693   *
2694   * @return The matched node that corresponds to the
2695   * match attribute of the current xsl:template.
2696   */

2697  public int getMatchedNode()
2698  {
2699    return m_currentMatchedNodes.peepTail();
2700  }
2701
2702  /**
2703   * Get the current context node list.
2704   *
2705   * @return A reset clone of the context node list.
2706   */

2707  public DTMIterator getContextNodeList()
2708  {
2709
2710    try
2711    {
2712      DTMIterator cnl = m_xcontext.getContextNodeList();
2713
2714      return (cnl == null) ? null : (DTMIterator) cnl.cloneWithReset();
2715    }
2716    catch (CloneNotSupportedException JavaDoc cnse)
2717    {
2718
2719      // should never happen.
2720
return null;
2721    }
2722  }
2723
2724  /**
2725   * Get the TrAX Transformer object in effect.
2726   *
2727   * @return This object.
2728   */

2729  public Transformer JavaDoc getTransformer()
2730  {
2731    return this;
2732  }
2733
2734  //==========================================================
2735
// SECTION: Accessor Functions
2736
//==========================================================
2737

2738  /**
2739   * Set the stylesheet for this processor. If this is set, then the
2740   * process calls that take only the input .xml will use
2741   * this instead of looking for a stylesheet PI. Also,
2742   * setting the stylesheet is needed if you are going
2743   * to use the processor as a SAX ContentHandler.
2744   *
2745   * @param stylesheetRoot A non-null StylesheetRoot object,
2746   * or null if you wish to clear the stylesheet reference.
2747   */

2748  public void setStylesheet(StylesheetRoot stylesheetRoot)
2749  {
2750    m_stylesheetRoot = stylesheetRoot;
2751  }
2752
2753  /**
2754   * Get the current stylesheet for this processor.
2755   *
2756   * @return The stylesheet that is associated with this
2757   * transformer.
2758   */

2759  public final StylesheetRoot getStylesheet()
2760  {
2761    return m_stylesheetRoot;
2762  }
2763
2764  /**
2765   * Get quietConflictWarnings property. If the quietConflictWarnings
2766   * property is set to true, warnings about pattern conflicts won't be
2767   * printed to the diagnostics stream.
2768   *
2769   * @return True if this transformer should not report
2770   * template match conflicts.
2771   */

2772  public boolean getQuietConflictWarnings()
2773  {
2774    return m_quietConflictWarnings;
2775  }
2776
2777  /**
2778   * If the quietConflictWarnings property is set to
2779   * true, warnings about pattern conflicts won't be
2780   * printed to the diagnostics stream.
2781   * False by default.
2782   * (Currently setting this property will have no effect.)
2783   *
2784   * @param b true if conflict warnings should be suppressed.
2785   */

2786  public void setQuietConflictWarnings(boolean b)
2787  {
2788    m_quietConflictWarnings = b;
2789  }
2790
2791  /**
2792   * Set the execution context for XPath.
2793   *
2794   * @param xcontext A non-null reference to the XPathContext
2795   * associated with this transformer.
2796   * @xsl.usage internal
2797   */

2798  public void setXPathContext(XPathContext xcontext)
2799  {
2800    m_xcontext = xcontext;
2801  }
2802
2803  /**
2804   * Get the XPath context associated with this transformer.
2805   *
2806   * @return The XPathContext reference, never null.
2807   */

2808  public final XPathContext getXPathContext()
2809  {
2810    return m_xcontext;
2811  }
2812
2813  /**
2814   * Get the object used to guard the stack from
2815   * recursion.
2816   *
2817   * @return The StackGuard object, which should never be null.
2818   * @xsl.usage internal
2819   */

2820  public StackGuard getStackGuard()
2821  {
2822    return m_stackGuard;
2823  }
2824
2825  /**
2826   * Get the recursion limit.
2827   * Used for infinite loop check. If the value is -1, do not
2828   * check for infinite loops. Anyone who wants to enable that
2829   * check should change the value of this variable to be the
2830   * level of recursion that they want to check. Be careful setting
2831   * this variable, if the number is too low, it may report an
2832   * infinite loop situation, when there is none.
2833   * Post version 1.0.0, we'll make this a runtime feature.
2834   *
2835   * @return The limit on recursion, or -1 if no check is to be made.
2836   */

2837  public int getRecursionLimit()
2838  {
2839    return m_stackGuard.getRecursionLimit();
2840  }
2841
2842  /**
2843   * Set the recursion limit.
2844   * Used for infinite loop check. If the value is -1, do not
2845   * check for infinite loops. Anyone who wants to enable that
2846   * check should change the value of this variable to be the
2847   * level of recursion that they want to check. Be careful setting
2848   * this variable, if the number is too low, it may report an
2849   * infinite loop situation, when there is none.
2850   * Post version 1.0.0, we'll make this a runtime feature.
2851   *
2852   * @param limit A number that represents the limit of recursion,
2853   * or -1 if no checking is to be done.
2854   */

2855  public void setRecursionLimit(int limit)
2856  {
2857    m_stackGuard.setRecursionLimit(limit);
2858  }
2859
2860  /**
2861   * Get the SerializationHandler object.
2862   *
2863   * @return The current SerializationHandler, which may not
2864   * be the main result tree manager.
2865   */

2866  public SerializationHandler getResultTreeHandler()
2867  {
2868    return m_serializationHandler;
2869  }
2870
2871  /**
2872   * Get the SerializationHandler object.
2873   *
2874   * @return The current SerializationHandler, which may not
2875   * be the main result tree manager.
2876   */

2877  public SerializationHandler getSerializationHandler()
2878  {
2879    return m_serializationHandler;
2880  }
2881  
2882  /**
2883   * Get the KeyManager object.
2884   *
2885   * @return A reference to the KeyManager object, which should
2886   * never be null.
2887   */

2888  public KeyManager getKeyManager()
2889  {
2890    return m_keyManager;
2891  }
2892
2893  /**
2894   * Check to see if this is a recursive attribute definition.
2895   *
2896   * @param attrSet A non-null ElemAttributeSet reference.
2897   *
2898   * @return true if the attribute set is recursive.
2899   */

2900  public boolean isRecursiveAttrSet(ElemAttributeSet attrSet)
2901  {
2902
2903    if (null == m_attrSetStack)
2904    {
2905      m_attrSetStack = new Stack JavaDoc();
2906    }
2907
2908    if (!m_attrSetStack.empty())
2909    {
2910      int loc = m_attrSetStack.search(attrSet);
2911
2912      if (loc > -1)
2913      {
2914        return true;
2915      }
2916    }
2917
2918    return false;
2919  }
2920
2921  /**
2922   * Push an executing attribute set, so we can check for
2923   * recursive attribute definitions.
2924   *
2925   * @param attrSet A non-null ElemAttributeSet reference.
2926   */

2927  public void pushElemAttributeSet(ElemAttributeSet attrSet)
2928  {
2929    m_attrSetStack.push(attrSet);
2930  }
2931
2932  /**
2933   * Pop the current executing attribute set.
2934   */

2935  public void popElemAttributeSet()
2936  {
2937    m_attrSetStack.pop();
2938  }
2939
2940  /**
2941   * Get the table of counters, for optimized xsl:number support.
2942   *
2943   * @return The CountersTable, never null.
2944   */

2945  public CountersTable getCountersTable()
2946  {
2947
2948    if (null == m_countersTable)
2949      m_countersTable = new CountersTable();
2950
2951    return m_countersTable;
2952  }
2953
2954  /**
2955   * Tell if the current template rule is null, i.e. if we are
2956   * directly within an apply-templates. Used for xsl:apply-imports.
2957   *
2958   * @return True if the current template rule is null.
2959   */

2960  public boolean currentTemplateRuleIsNull()
2961  {
2962    return ((!m_currentTemplateRuleIsNull.isEmpty())
2963            && (m_currentTemplateRuleIsNull.peek() == true));
2964  }
2965
2966  /**
2967   * Push true if the current template rule is null, false
2968   * otherwise.
2969   *
2970   * @param b True if the we are executing an xsl:for-each
2971   * (or xsl:call-template?).
2972   */

2973  public void pushCurrentTemplateRuleIsNull(boolean b)
2974  {
2975    m_currentTemplateRuleIsNull.push(b);
2976  }
2977
2978  /**
2979   * Push true if the current template rule is null, false
2980   * otherwise.
2981   */

2982  public void popCurrentTemplateRuleIsNull()
2983  {
2984    m_currentTemplateRuleIsNull.pop();
2985  }
2986
2987  /**
2988   * Push a funcion result for the currently active EXSLT
2989   * <code>func:function</code>.
2990   *
2991   * @param val the result of executing an EXSLT
2992   * <code>func:result</code> instruction for the current
2993   * <code>func:function</code>.
2994   */

2995  public void pushCurrentFuncResult(Object JavaDoc val) {
2996    m_currentFuncResult.push(val);
2997  }
2998
2999  /**
3000   * Pops the result of the currently active EXSLT <code>func:function</code>.
3001   *
3002   * @return the value of the <code>func:function</code>
3003   */

3004  public Object JavaDoc popCurrentFuncResult() {
3005    return m_currentFuncResult.pop();
3006  }
3007
3008  /**
3009   * Determines whether an EXSLT <code>func:result</code> instruction has been
3010   * executed for the currently active EXSLT <code>func:function</code>.
3011   *
3012   * @return <code>true</code> if and only if a <code>func:result</code>
3013   * instruction has been executed
3014   */

3015  public boolean currentFuncResultSeen() {
3016    return !m_currentFuncResult.empty()
3017               && m_currentFuncResult.peek() != null;
3018  }
3019
3020  /**
3021   * Return the message manager.
3022   *
3023   * @return The message manager, never null.
3024   */

3025  public MsgMgr getMsgMgr()
3026  {
3027
3028    if (null == m_msgMgr)
3029      m_msgMgr = new MsgMgr(this);
3030
3031    return m_msgMgr;
3032  }
3033
3034  /**
3035   * Set the error event listener.
3036   *
3037   * @param listener The new error listener.
3038   * @throws IllegalArgumentException if
3039   */

3040  public void setErrorListener(ErrorListener JavaDoc listener)
3041          throws IllegalArgumentException JavaDoc
3042  {
3043
3044    synchronized (m_reentryGuard)
3045    {
3046      if (listener == null)
3047        throw new IllegalArgumentException JavaDoc(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler");
3048

3049      m_errorHandler = listener;
3050    }
3051  }
3052
3053  /**
3054   * Get the current error event handler.
3055   *
3056   * @return The current error handler, which should never be null.
3057   */

3058  public ErrorListener JavaDoc getErrorListener()
3059  {
3060    return m_errorHandler;
3061  }
3062
3063  /**
3064   * Get an instance of the trace manager for this transformation.
3065   * This object can be used to set trace listeners on various
3066   * events during the transformation.
3067   *
3068   * @return A reference to the TraceManager, never null.
3069   */

3070  public TraceManager getTraceManager()
3071  {
3072    return m_traceManager;
3073  }
3074
3075  /**
3076   * Look up the value of a feature.
3077   *
3078   * <p>The feature name is any fully-qualified URI. It is
3079   * possible for an TransformerFactory to recognize a feature name but
3080   * to be unable to return its value; this is especially true
3081   * in the case of an adapter for a SAX1 Parser, which has
3082   * no way of knowing whether the underlying parser is
3083   * validating, for example.</p>
3084   *
3085   * <h3>Open issues:</h3>
3086   * <dl>
3087   * <dt><h4>Should getFeature be changed to hasFeature?</h4></dt>
3088   * <dd>Keith Visco writes: Should getFeature be changed to hasFeature?
3089   * It returns a boolean which indicated whether the "state"
3090   * of feature is "true or false". I assume this means whether
3091   * or not a feature is supported? I know SAX is using "getFeature",
3092   * but to me "hasFeature" is cleaner.</dd>
3093   * </dl>
3094   *
3095   * @param name The feature name, which is a fully-qualified
3096   * URI.
3097   * @return The current state of the feature (true or false).
3098   * @throws org.xml.sax.SAXNotRecognizedException When the
3099   * TransformerFactory does not recognize the feature name.
3100   * @throws org.xml.sax.SAXNotSupportedException When the
3101   * TransformerFactory recognizes the feature name but
3102   * cannot determine its value at this time.
3103   *
3104   * @throws SAXNotRecognizedException
3105   * @throws SAXNotSupportedException
3106   */

3107  public boolean getFeature(String JavaDoc name)
3108          throws SAXNotRecognizedException JavaDoc, SAXNotSupportedException JavaDoc
3109  {
3110
3111    if ("http://xml.org/trax/features/sax/input".equals(name))
3112      return true;
3113    else if ("http://xml.org/trax/features/dom/input".equals(name))
3114      return true;
3115
3116    throw new SAXNotRecognizedException JavaDoc(name);
3117  }
3118
3119  // %TODO% Doc
3120

3121  /**
3122   * NEEDSDOC Method getMode
3123   *
3124   *
3125   * NEEDSDOC (getMode) @return
3126   */

3127  public QName getMode()
3128  {
3129    return m_modes.isEmpty() ? null : (QName) m_modes.peek();
3130  }
3131
3132  // %TODO% Doc
3133

3134  /**
3135   * NEEDSDOC Method pushMode
3136   *
3137   *
3138   * NEEDSDOC @param mode
3139   */

3140  public void pushMode(QName mode)
3141  {
3142    m_modes.push(mode);
3143  }
3144
3145  // %TODO% Doc
3146

3147  /**
3148   * NEEDSDOC Method popMode
3149   *
3150   */

3151  public void popMode()
3152  {
3153    m_modes.pop();
3154  }
3155
3156  /**
3157   * Called by SourceTreeHandler to start the transformation
3158   * in a separate thread
3159   *
3160   * NEEDSDOC @param priority
3161   */

3162  public void runTransformThread(int priority)
3163  {
3164
3165    // used in SourceTreeHandler
3166
Thread JavaDoc t = ThreadControllerWrapper.runThread(this, priority);
3167    this.setTransformThread(t);
3168  }
3169
3170  /**
3171   * Called by this.transform() if isParserEventsOnMain()==false.
3172   * Similar with runTransformThread(), but no priority is set
3173   * and setTransformThread is not set.
3174   */

3175  public void runTransformThread()
3176  {
3177    ThreadControllerWrapper.runThread(this, -1);
3178  }
3179  
3180  /**
3181   * Called by CoRoutineSAXParser. Launches the CoroutineSAXParser
3182   * in a thread, and prepares it to invoke the parser from that thread
3183   * upon request.
3184   *
3185   */

3186  public static void runTransformThread(Runnable JavaDoc runnable)
3187  {
3188    ThreadControllerWrapper.runThread(runnable, -1);
3189  }
3190
3191  /**
3192   * Used by SourceTreeHandler to wait until the transform
3193   * completes
3194   *
3195   * @throws SAXException
3196   */

3197  public void waitTransformThread() throws SAXException JavaDoc
3198  {
3199
3200    // This is called to make sure the task is done.
3201
// It is possible that the thread has been reused -
3202
// but for a different transformation. ( what if we
3203
// recycle the transformer ? Not a problem since this is
3204
// still in use. )
3205
Thread JavaDoc transformThread = this.getTransformThread();
3206
3207    if (null != transformThread)
3208    {
3209      try
3210      {
3211        ThreadControllerWrapper.waitThread(transformThread, this);
3212
3213        if (!this.hasTransformThreadErrorCatcher())
3214        {
3215          Exception JavaDoc e = this.getExceptionThrown();
3216
3217          if (null != e)
3218          {
3219            e.printStackTrace();
3220            throw new org.xml.sax.SAXException JavaDoc(e);
3221          }
3222        }
3223
3224        this.setTransformThread(null);
3225      }
3226      catch (InterruptedException JavaDoc ie){}
3227    }
3228  }
3229
3230  /**
3231   * Get the exception thrown by the secondary thread (normally
3232   * the transform thread).
3233   *
3234   * @return The thrown exception, or null if no exception was
3235   * thrown.
3236   */

3237  public Exception JavaDoc getExceptionThrown()
3238  {
3239    return m_exceptionThrown;
3240  }
3241
3242  /**
3243   * Set the exception thrown by the secondary thread (normally
3244   * the transform thread).
3245   *
3246   * @param e The thrown exception, or null if no exception was
3247   * thrown.
3248   */

3249  public void setExceptionThrown(Exception JavaDoc e)
3250  {
3251    m_exceptionThrown = e;
3252  }
3253
3254  /**
3255   * This is just a way to set the document for run().
3256   *
3257   * @param doc A non-null reference to the root of the
3258   * tree to be transformed.
3259   */

3260  public void setSourceTreeDocForThread(int doc)
3261  {
3262    m_doc = doc;
3263  }
3264
3265  /**
3266   * Set the input source for the source tree, which is needed if the
3267   * parse thread is not the main thread, in order for the parse
3268   * thread's run method to get to the input source.
3269   *
3270   * @param source The input source for the source tree.
3271   */

3272  public void setXMLSource(Source JavaDoc source)
3273  {
3274    m_xmlSource = source;
3275  }
3276
3277  /**
3278   * Tell if the transform method is completed.
3279   *
3280   * @return True if transformNode has completed, or
3281   * an exception was thrown.
3282   */

3283  public boolean isTransformDone()
3284  {
3285
3286    synchronized (this)
3287    {
3288      return m_isTransformDone;
3289    }
3290  }
3291
3292  /**
3293   * Set if the transform method is completed.
3294   *
3295   * @param done True if transformNode has completed, or
3296   * an exception was thrown.
3297   */

3298  public void setIsTransformDone(boolean done)
3299  {
3300
3301    synchronized (this)
3302    {
3303      m_isTransformDone = done;
3304    }
3305  }
3306
3307  /**
3308   * From a secondary thread, post the exception, so that
3309   * it can be picked up from the main thread.
3310   *
3311   * @param e The exception that was thrown.
3312   */

3313  void postExceptionFromThread(Exception JavaDoc e)
3314  {
3315
3316    // Commented out in response to problem reported by Nicola Brown <Nicola.Brown@jacobsrimell.com>
3317
// if(m_reportInPostExceptionFromThread)
3318
// {
3319
// // Consider re-throwing the exception if this flag is set.
3320
// e.printStackTrace();
3321
// }
3322
// %REVIEW Need DTM equivelent?
3323
// if (m_inputContentHandler instanceof SourceTreeHandler)
3324
// {
3325
// SourceTreeHandler sth = (SourceTreeHandler) m_inputContentHandler;
3326
//
3327
// sth.setExceptionThrown(e);
3328
// }
3329
// ContentHandler ch = getContentHandler();
3330

3331    // if(ch instanceof SourceTreeHandler)
3332
// {
3333
// SourceTreeHandler sth = (SourceTreeHandler) ch;
3334
// ((TransformerImpl)(sth.getTransformer())).postExceptionFromThread(e);
3335
// }
3336
m_isTransformDone = true;
3337    m_exceptionThrown = e;
3338    ; // should have already been reported via the error handler?
3339

3340    synchronized (this)
3341    {
3342
3343      // See message from me on 3/27/2001 to Patrick Moore.
3344
// String msg = e.getMessage();
3345
// System.out.println(e.getMessage());
3346
// Is this really needed? -sb
3347
notifyAll();
3348
3349      // if (null == msg)
3350
// {
3351
//
3352
// // m_throwNewError = false;
3353
// e.printStackTrace();
3354
// }
3355
// throw new org.apache.xml.utils.WrappedRuntimeException(e);
3356
}
3357  }
3358
3359  /**
3360   * Run the transform thread.
3361   */

3362  public void run()
3363  {
3364
3365    m_hasBeenReset = false;
3366
3367    try
3368    {
3369
3370      // int n = ((SourceTreeHandler)getInputContentHandler()).getDTMRoot();
3371
// transformNode(n);
3372
try
3373      {
3374        m_isTransformDone = false;
3375        
3376        // Should no longer be needed...
3377
// if(m_inputContentHandler instanceof TransformerHandlerImpl)
3378
// {
3379
// TransformerHandlerImpl thi = (TransformerHandlerImpl)m_inputContentHandler;
3380
// thi.waitForInitialEvents();
3381
// }
3382

3383        transformNode(m_doc);
3384        
3385      }
3386      catch (Exception JavaDoc e)
3387      {
3388        // e.printStackTrace();
3389

3390        // Strange that the other catch won't catch this...
3391
if (null != m_transformThread)
3392          postExceptionFromThread(e); // Assume we're on the main thread
3393
else
3394          throw new RuntimeException JavaDoc(e.getMessage());
3395      }
3396      finally
3397      {
3398        m_isTransformDone = true;
3399
3400        if (m_inputContentHandler instanceof TransformerHandlerImpl)
3401        {
3402          ((TransformerHandlerImpl) m_inputContentHandler).clearCoRoutine();
3403        }
3404
3405        // synchronized (this)
3406
// {
3407
// notifyAll();
3408
// }
3409
}
3410    }
3411    catch (Exception JavaDoc e)
3412    {
3413
3414      // e.printStackTrace();
3415
if (null != m_transformThread)
3416        postExceptionFromThread(e);
3417      else
3418        throw new RuntimeException JavaDoc(e.getMessage()); // Assume we're on the main thread.
3419
}
3420  }
3421
3422  // Fragment re-execution interfaces for a tool.
3423

3424  /**
3425   * This will get a snapshot of the current executing context
3426   *
3427   *
3428   * @return TransformSnapshot object, snapshot of executing context
3429   * @deprecated This is an internal tooling API that nobody seems to be using
3430   */

3431  public TransformSnapshot getSnapshot()
3432  {
3433    return new TransformSnapshotImpl(this);
3434  }
3435
3436  /**
3437   * This will execute the following XSLT instructions
3438   * from the snapshot point, after the stylesheet execution
3439   * context has been reset from the snapshot point.
3440   *
3441   * @param ts The snapshot of where to start execution
3442   *
3443   * @throws TransformerException
3444   * @deprecated This is an internal tooling API that nobody seems to be using
3445   */

3446  public void executeFromSnapshot(TransformSnapshot ts)
3447          throws TransformerException JavaDoc
3448  {
3449
3450    ElemTemplateElement template = getMatchedTemplate();
3451    int child = getMatchedNode();
3452
3453    pushElemTemplateElement(template); //needed??
3454
m_xcontext.pushCurrentNode(child); //needed??
3455
this.executeChildTemplates(template, true); // getResultTreeHandler());
3456
}
3457
3458  /**
3459   * This will reset the stylesheet execution context
3460   * from the snapshot point.
3461   *
3462   * @param ts The snapshot of where to start execution
3463   * @deprecated This is an internal tooling API that nobody seems to be using
3464   */

3465  public void resetToStylesheet(TransformSnapshot ts)
3466  {
3467    ((TransformSnapshotImpl) ts).apply(this);
3468  }
3469
3470  /**
3471   * NEEDSDOC Method stopTransformation
3472   *
3473   */

3474  public void stopTransformation(){}
3475
3476  /**
3477   * Test whether whitespace-only text nodes are visible in the logical
3478   * view of <code>DTM</code>. Normally, this function
3479   * will be called by the implementation of <code>DTM</code>;
3480   * it is not normally called directly from
3481   * user code.
3482   *
3483   * @param elementHandle int Handle of the element.
3484   * @return one of NOTSTRIP, STRIP, or INHERIT.
3485   */

3486  public short getShouldStripSpace(int elementHandle, DTM dtm)
3487  {
3488
3489    try
3490    {
3491      org.apache.xalan.templates.WhiteSpaceInfo info =
3492        m_stylesheetRoot.getWhiteSpaceInfo(m_xcontext, elementHandle, dtm);
3493
3494      if (null == info)
3495      {
3496        return DTMWSFilter.INHERIT;
3497      }
3498      else
3499      {
3500
3501        // System.out.println("getShouldStripSpace: "+info.getShouldStripSpace());
3502
return info.getShouldStripSpace()
3503               ? DTMWSFilter.STRIP : DTMWSFilter.NOTSTRIP;
3504      }
3505    }
3506    catch (TransformerException JavaDoc se)
3507    {
3508      return DTMWSFilter.INHERIT;
3509    }
3510  }
3511  /**
3512   * Initializer method.
3513   *
3514   * @param transformer non-null transformer instance
3515   * @param realHandler Content Handler instance
3516   */

3517   public void init(ToXMLSAXHandler h,Transformer JavaDoc transformer, ContentHandler JavaDoc realHandler)
3518   {
3519      h.setTransformer(transformer);
3520      h.setContentHandler(realHandler);
3521   }
3522      
3523   public void setSerializationHandler(SerializationHandler xoh)
3524   {
3525      m_serializationHandler = xoh;
3526   }
3527   
3528   
3529     
3530    /**
3531     * Fire off characters, cdate events.
3532     * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, char[], int, int)
3533     */

3534    public void fireGenerateEvent(
3535        int eventType,
3536        char[] ch,
3537        int start,
3538        int length) {
3539            
3540        GenerateEvent ge = new GenerateEvent(this, eventType, ch, start, length);
3541        m_traceManager.fireGenerateEvent(ge);
3542    }
3543
3544    /**
3545     * Fire off startElement, endElement events.
3546     * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String, Attributes)
3547     */

3548    public void fireGenerateEvent(
3549        int eventType,
3550        String JavaDoc name,
3551        Attributes JavaDoc atts) {
3552            
3553        GenerateEvent ge = new GenerateEvent(this, eventType, name, atts);
3554        m_traceManager.fireGenerateEvent(ge);
3555    }
3556
3557    /**
3558     * Fire off processingInstruction events.
3559     * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String, String)
3560     */

3561    public void fireGenerateEvent(int eventType, String JavaDoc name, String JavaDoc data) {
3562        GenerateEvent ge = new GenerateEvent(this, eventType, name,data);
3563        m_traceManager.fireGenerateEvent(ge);
3564    }
3565
3566    /**
3567     * Fire off comment and entity ref events.
3568     * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String)
3569     */

3570    public void fireGenerateEvent(int eventType, String JavaDoc data) {
3571        GenerateEvent ge = new GenerateEvent(this, eventType, data);
3572        m_traceManager.fireGenerateEvent(ge);
3573    }
3574
3575    /**
3576     * Fire off startDocument, endDocument events.
3577     * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int)
3578     */

3579    public void fireGenerateEvent(int eventType) {
3580        GenerateEvent ge = new GenerateEvent(this, eventType);
3581        m_traceManager.fireGenerateEvent(ge);
3582    }
3583
3584    /**
3585     * @see org.apache.xml.serializer.SerializerTrace#hasTraceListeners()
3586     */

3587    public boolean hasTraceListeners() {
3588        return m_traceManager.hasTraceListeners();
3589    }
3590
3591} // end TransformerImpl class
3592

3593
Popular Tags