OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / org / apache / xalan / transformer / TransformerImpl.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: TransformerImpl.java 475979 2006-11-16 23:32:48Z minchau $
20  */
21 package org.apache.xalan.transformer;
22
23 import java.io.IOException;
24 import java.io.StringWriter;
25 import java.util.Enumeration;
26 import java.util.Properties;
27 import java.util.Stack;
28 import java.util.StringTokenizer;
29 import java.util.Vector;
30
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34 import javax.xml.transform.ErrorListener;
35 import javax.xml.transform.OutputKeys;
36 import javax.xml.transform.Result;
37 import javax.xml.transform.Source;
38 import javax.xml.transform.SourceLocator;
39 import javax.xml.transform.Transformer;
40 import javax.xml.transform.TransformerException;
41 import javax.xml.transform.URIResolver;
42 import javax.xml.transform.dom.DOMResult;
43 import javax.xml.transform.dom.DOMSource;
44 import javax.xml.transform.sax.SAXResult;
45 import javax.xml.transform.sax.SAXSource;
46 import javax.xml.transform.stream.StreamResult;
47 import javax.xml.transform.stream.StreamSource;
48
49 import org.apache.xalan.extensions.ExtensionsTable;
50 import org.apache.xalan.res.XSLMessages;
51 import org.apache.xalan.res.XSLTErrorResources;
52 import org.apache.xml.serializer.Method;
53 import org.apache.xml.serializer.Serializer;
54 import org.apache.xml.serializer.SerializerFactory;
55 import org.apache.xalan.templates.AVT;
56 import org.apache.xalan.templates.Constants;
57 import org.apache.xalan.templates.ElemAttributeSet;
58 import org.apache.xalan.templates.ElemForEach;
59 import org.apache.xalan.templates.ElemSort;
60 import org.apache.xalan.templates.ElemTemplate;
61 import org.apache.xalan.templates.ElemTemplateElement;
62 import org.apache.xalan.templates.ElemTextLiteral;
63 import org.apache.xalan.templates.ElemVariable;
64 import org.apache.xalan.templates.OutputProperties;
65 import org.apache.xalan.templates.Stylesheet;
66 import org.apache.xalan.templates.StylesheetComposed;
67 import org.apache.xalan.templates.StylesheetRoot;
68 import org.apache.xalan.templates.XUnresolvedVariable;
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.ToSAXHandler;
74 import org.apache.xml.serializer.ToTextStream;
75 import org.apache.xml.serializer.ToXMLSAXHandler;
76 import org.apache.xml.serializer.SerializationHandler;
77 import org.apache.xml.utils.BoolStack;
78 import org.apache.xml.utils.DOMBuilder;
79 import org.apache.xml.utils.NodeVector;
80 import org.apache.xml.utils.ObjectPool;
81 import org.apache.xml.utils.ObjectStack;
82 import org.apache.xml.utils.QName;
83 import org.apache.xml.utils.SAXSourceLocator;
84 import org.apache.xml.utils.ThreadControllerWrapper;
85 import org.apache.xpath.Arg;
86 import org.apache.xpath.ExtensionsProvider;
87 import org.apache.xpath.VariableStack;
88 import org.apache.xpath.XPathContext;
89 import org.apache.xpath.functions.FuncExtFunction;
90 import org.apache.xpath.objects.XObject;
91 import org.xml.sax.Attributes;
92 import org.xml.sax.ContentHandler;
93 import org.xml.sax.SAXException;
94 import org.xml.sax.SAXNotRecognizedException;
95 import org.xml.sax.SAXNotSupportedException;
96 import org.xml.sax.ext.LexicalHandler;
97
98 /**
99  * This class implements the
100  * {@link javax.xml.transform.Transformer} interface, and is the core
101  * representation of the transformation execution.</p>
102  * @xsl.usage advanced
103  */
104 public class TransformerImpl extends Transformer
105         implements Runnable, DTMWSFilter, ExtensionsProvider, org.apache.xml.serializer.SerializerTrace
106 {
107
108   // Synch object to gaurd against setting values from the TrAX interface 
109   // or reentry while the transform is going on.
110
111   /** NEEDSDOC Field m_reentryGuard          */
112   private Boolean m_reentryGuard = new Boolean(true);
113
114   /**
115    * This is null unless we own the stream.
116    */
117   private java.io.FileOutputStream m_outputStream = null;
118
119   /** The thread that the transformer is running on. */
120   private Thread m_transformThread;
121
122   /** The base URL of the source tree. */
123   private String m_urlOfSource = null;
124
125   /** The Result object at the start of the transform, if any. */
126   private Result m_outputTarget = null;
127
128   /**
129    * The output format object set by the user.  May be null.
130    */
131   private OutputProperties m_outputFormat;
132
133
134   /**
135    * The content handler for the source input tree.
136    */
137   ContentHandler m_inputContentHandler;
138
139   /**
140    * The content handler for the result tree.
141    */
142   private ContentHandler m_outputContentHandler = null;
143
144   //  /*
145   //   * Use member variable to store param variables as they're
146   //   * being created, use member variable so we don't
147   //   * have to create a new vector every time.
148   //   */
149   //  private Vector m_newVars = new Vector();
150
151   /**
152    * A pool of ResultTreeHandlers, for serialization of a subtree to text.
153    *  Please note that each of these also holds onto a Text Serializer.  
154    */
155   private ObjectPool m_textResultHandlerObjectPool =
156     new ObjectPool(ToTextStream.class);
157
158   /**
159    * Related to m_textResultHandlerObjectPool, this is a pool of
160    * StringWriters, which are passed to the Text Serializers.
161    * (I'm not sure if this is really needed any more.  -sb)      
162    */
163   private ObjectPool m_stringWriterObjectPool =
164     new ObjectPool(StringWriter.class);
165
166   /**
167    * A static text format object, which can be used over and
168    * over to create the text serializers.    
169    */
170   private OutputProperties m_textformat = new OutputProperties(Method.TEXT);
171
172   // Commenteded out in response to problem reported by 
173   // Nicola Brown <Nicola.Brown@jacobsrimell.com>
174   //  /**
175   //   * Flag to let us know if an exception should be reported inside the 
176   //   * postExceptionFromThread method.  This is needed if the transform is 
177   //   * being generated from SAX events, and thus there is no central place 
178   //   * to report the exception from.  (An exception is usually picked up in 
179   //   * the main thread from the transform thread in {@link #transform(Source source)} 
180   //   * from {@link #getExceptionThrown()}. )
181   //   */
182   //  private boolean m_reportInPostExceptionFromThread = false;
183
184   /**
185    * A node vector used as a stack to track the current
186    * ElemTemplateElement.  Needed for the
187    * org.apache.xalan.transformer.TransformState interface,
188    * so a tool can discover the calling template. Note the use of an array 
189    * for this limits the recursion depth to 4K.
190    */
191   ObjectStack m_currentTemplateElements 
192       = new ObjectStack(XPathContext.RECURSIONLIMIT);
193   
194   /** The top of the currentTemplateElements stack. */
195   //int m_currentTemplateElementsTop = 0;
196
197   /**
198    * A node vector used as a stack to track the current
199    * ElemTemplate that was matched.
200    * Needed for the
201    * org.apache.xalan.transformer.TransformState interface,
202    * so a tool can discover the matched template
203    */
204   Stack m_currentMatchTemplates = new Stack();
205
206   /**
207    * A node vector used as a stack to track the current
208    * node that was matched.
209    * Needed for the
210    * org.apache.xalan.transformer.TransformState interface,
211    * so a tool can discover the matched
212    * node. 
213    */
214   NodeVector m_currentMatchedNodes = new NodeVector();
215
216   /**
217    * The root of a linked set of stylesheets.
218    */
219   private StylesheetRoot m_stylesheetRoot = null;
220
221   /**
222    * If this is set to true, do not warn about pattern
223    * match conflicts.
224    */
225   private boolean m_quietConflictWarnings = true;
226
227   /**
228    * The liason to the XML parser, so the XSL processor
229    * can handle included files, and the like, and do the
230    * initial parse of the XSL document.
231    */
232   private XPathContext m_xcontext;
233
234   /**
235    * Output handler to bottleneck SAX events.
236    */
237   private SerializationHandler m_serializationHandler;  
238
239   /** The key manager, which manages xsl:keys. */
240   private KeyManager m_keyManager = new KeyManager();
241
242   /**
243    * Stack for the purposes of flagging infinite recursion with
244    * attribute sets.
245    */
246   Stack m_attrSetStack = null;
247
248   /**
249    * The table of counters for xsl:number support.
250    */
251   CountersTable m_countersTable = null;
252
253   /**
254    * Is > 0 when we're processing a for-each.
255    */
256   BoolStack m_currentTemplateRuleIsNull = new BoolStack();
257
258   /**
259    * Keeps track of the result delivered by any EXSLT <code>func:result</code>
260    * instruction that has been executed for the currently active EXSLT
261    * <code>func:function</code>
262    */
263   ObjectStack m_currentFuncResult = new ObjectStack();
264   
265   /**
266    * The message manager, which manages error messages, warning
267    * messages, and other types of message events.   
268    */
269   private MsgMgr m_msgMgr;
270
271   /**
272    * The flag for the setting of the optimize feature;
273    * This flag should have the same value as the FEATURE_OPTIMIZE feature
274    * which is set by the TransformerFactory.setAttribut() method before a
275    * Transformer is created
276    */    
277   private boolean m_optimizer = true;
278
279   /**
280    * The flag for the setting of the incremental feature;
281    * This flag should have the same value as the FEATURE_INCREMENTAL feature
282    * which is set by the TransformerFactory.setAttribut() method before a
283    * Transformer is created
284    */    
285   private boolean m_incremental = false;
286
287   /**
288    * The flag for the setting of the source_location feature;
289    * This flag should have the same value as the FEATURE_SOURCE_LOCATION feature
290    * which is set by the TransformerFactory.setAttribut() method before a
291    * Transformer is created
292    */  
293   private boolean m_source_location = false;
294     
295   /**
296    * The SAX error handler, where errors and warnings are sent.
297    */
298   private ErrorListener m_errorHandler =
299     new org.apache.xml.utils.DefaultErrorHandler(false);
300
301   /**
302    * If the transform thread throws an exception, the exception needs to
303    * be stashed away so that the main thread can pass it on to the
304    * client. 
305    */
306   private Exception m_exceptionThrown = null;
307
308   /**
309    * This is needed for support of setSourceTreeDocForThread(Node doc),
310    * which must be called in order for the transform thread's run
311    * method to obtain the root of the source tree to be transformed.     
312    */
313   private int m_doc;
314
315   /** Flag to to tell if the tranformer needs to be reset. */
316   private boolean m_hasBeenReset = false;
317
318   /** NEEDSDOC Field m_shouldReset          */
319   private boolean m_shouldReset = true;
320
321   /**
322    * A stack of current template modes.
323    */
324   private Stack m_modes = new Stack();
325
326   //==========================================================
327   // SECTION: Constructor
328   //==========================================================
329
330   /**
331    * Construct a TransformerImpl.
332    *
333    * @param stylesheet The root of the stylesheet tree.
334    */
335   public TransformerImpl(StylesheetRoot stylesheet)
336    // throws javax.xml.transform.TransformerException    
337   {
338     m_optimizer = stylesheet.getOptimizer();
339     m_incremental = stylesheet.getIncremental();
340     m_source_location = stylesheet.getSource_location();        
341     setStylesheet(stylesheet);
342     XPathContext xPath = new XPathContext(this);
343     xPath.setIncremental(m_incremental);
344     xPath.getDTMManager().setIncremental(m_incremental);
345     xPath.setSource_location(m_source_location);
346     xPath.getDTMManager().setSource_location(m_source_location);
347     
348     if (stylesheet.isSecureProcessing())
349       xPath.setSecureProcessing(true);
350     
351     setXPathContext(xPath);
352     getXPathContext().setNamespaceContext(stylesheet);
353   }
354   
355   // ================ ExtensionsTable ===================
356
357   /**
358    * The table of ExtensionHandlers.
359    */
360   private ExtensionsTable m_extensionsTable = null;
361
362   /**
363    * Get the extensions table object. 
364    *
365    * @return The extensions table.
366    */
367   public ExtensionsTable getExtensionsTable()
368   {
369     return m_extensionsTable;
370   }
371
372   /**
373    * If the stylesheet contains extensions, set the extensions table object.
374    *
375    *
376    * @param sroot The stylesheet.
377    * @throws javax.xml.transform.TransformerException
378    */
379   void setExtensionsTable(StylesheetRoot sroot)
380        throws javax.xml.transform.TransformerException
381   {
382     try
383     {
384       if (sroot.getExtensions() != null)
385         m_extensionsTable = new ExtensionsTable(sroot);
386     }
387     catch (javax.xml.transform.TransformerException te)
388     {te.printStackTrace();}
389   }
390   
391   //== Implementation of the XPath ExtensionsProvider interface.
392   
393   public boolean functionAvailable(String ns, String funcName)
394           throws javax.xml.transform.TransformerException
395   {
396     return getExtensionsTable().functionAvailable(ns, funcName);
397   }
398   
399   public boolean elementAvailable(String ns, String elemName)
400           throws javax.xml.transform.TransformerException
401   {
402     return getExtensionsTable().elementAvailable(ns, elemName);   
403   }
404    
405   public Object extFunction(String ns, String funcName, 
406                             Vector argVec, Object methodKey)
407             throws javax.xml.transform.TransformerException
408   {//System.out.println("TransImpl.extFunction() " + ns + " " + funcName +" " + getExtensionsTable());
409     return getExtensionsTable().extFunction(ns, funcName, 
410                                         argVec, methodKey,
411                                         getXPathContext().getExpressionContext());   
412   }
413
414   public Object extFunction(FuncExtFunction extFunction, Vector argVec)
415             throws javax.xml.transform.TransformerException
416   {
417     return getExtensionsTable().extFunction(extFunction, argVec,
418                                             getXPathContext().getExpressionContext());   
419   }
420   
421   //=========================
422
423   /**
424    * Reset the state.  This needs to be called after a process() call
425    * is invoked, if the processor is to be used again.
426    */
427   public void reset()
428   {
429
430     if (!m_hasBeenReset && m_shouldReset)
431     {
432       m_hasBeenReset = true;
433
434       if (this.m_outputStream != null)
435       {
436         try
437         {
438           m_outputStream.close();
439         }
440         catch (java.io.IOException ioe){}
441       }
442
443       m_outputStream = null;
444
445       // I need to look more carefully at which of these really
446       // needs to be reset.
447       m_countersTable = null;
448
449       m_xcontext.reset();
450       
451       m_xcontext.getVarStack().reset();
452       resetUserParameters();
453       
454
455       m_currentTemplateElements.removeAllElements();     
456       m_currentMatchTemplates.removeAllElements();
457       m_currentMatchedNodes.removeAllElements();
458       
459       m_serializationHandler = null;      
460       m_outputTarget = null;
461       m_keyManager = new KeyManager();
462       m_attrSetStack = null;
463       m_countersTable = null;
464       m_currentTemplateRuleIsNull = new BoolStack();
465       // m_xmlSource = null; // android-removed
466       m_doc = DTM.NULL;
467       // m_isTransformDone = false; // android-removed
468       m_transformThread = null;
469
470       // m_inputContentHandler = null;
471       // For now, reset the document cache each time.
472       m_xcontext.getSourceTreeManager().reset();
473     }
474
475     //    m_reportInPostExceptionFromThread = false;
476   }
477
478   // ========= Transformer Interface Implementation ==========
479
480   /**
481    * Get the thread that the transform process is on.
482    *
483    * @return The thread that the transform process is on, or null.
484    * @xsl.usage internal
485    */
486   public Thread getTransformThread()
487   {
488     return m_transformThread;
489   }
490
491   /**
492    * Get the thread that the transform process is on.
493    *
494    * @param t The transform thread, may be null.
495    * @xsl.usage internal
496    */
497   public void setTransformThread(Thread t)
498   {
499     m_transformThread = t;
500   }
501
502   /** NEEDSDOC Field m_hasTransformThreadErrorCatcher          */
503   private boolean m_hasTransformThreadErrorCatcher = false;
504
505   /**
506    * Return true if the transform was initiated from the transform method,
507    * otherwise it was probably done from a pure parse events.
508    *
509    * NEEDSDOC ($objectName$) @return
510    */
511   public boolean hasTransformThreadErrorCatcher()
512   {
513     return m_hasTransformThreadErrorCatcher;
514   }
515         
516         /**
517    * Process the source tree to SAX parse events.
518    * @param source  The input for the source tree.
519    *
520    * @throws TransformerException
521    */
522   public void transform(Source source) throws TransformerException
523   {
524                 transform(source, true); 
525         }
526
527   /**
528    * Process the source tree to SAX parse events.
529    * @param source  The input for the source tree.
530    * @param shouldRelease  Flag indicating whether to release DTMManager.
531    *
532    * @throws TransformerException
533    */
534   public void transform(Source source, boolean shouldRelease) throws TransformerException
535   {
536
537     try
538     {
539         
540       // Patch for bugzilla #13863.  If we don't reset the namespaceContext
541       // then we will get a NullPointerException if transformer is reused 
542       // (for stylesheets that use xsl:key).  Not sure if this should go 
543       // here or in reset(). -is  
544       if(getXPathContext().getNamespaceContext() == null){
545          getXPathContext().setNamespaceContext(getStylesheet());
546       }
547       String base = source.getSystemId();
548       
549       // If no systemID of the source, use the base of the stylesheet.
550       if(null == base)
551       {
552         base = m_stylesheetRoot.getBaseIdentifier();
553       }
554
555       // As a last resort, use the current user dir.
556       if(null == base)
557       {
558         String currentDir = "";
559         try {
560           currentDir = System.getProperty("user.dir");
561         }
562         catch (SecurityException se) {}// user.dir not accessible from applet
563               
564         if (currentDir.startsWith(java.io.File.separator))
565           base = "file://" + currentDir;
566         else
567           base = "file:///" + currentDir;
568         
569         base = base + java.io.File.separatorChar
570                + source.getClass().getName();
571       }
572       setBaseURLOfSource(base);
573       DTMManager mgr = m_xcontext.getDTMManager();
574       /*
575        * According to JAXP1.2, new SAXSource()/StreamSource()
576        * should create an empty input tree, with a default root node. 
577        * new DOMSource()creates an empty document using DocumentBuilder.
578        * newDocument(); Use DocumentBuilder.newDocument() for all 3 situations,
579        * since there is no clear spec. how to create an empty tree when
580        * both SAXSource() and StreamSource() are used.
581        */
582       if ((source instanceof StreamSource && source.getSystemId()==null &&
583          ((StreamSource)source).getInputStream()==null &&
584          ((StreamSource)source).getReader()==null)||
585          (source instanceof SAXSource &&
586          ((SAXSource)source).getInputSource()==null &&
587          ((SAXSource)source).getXMLReader()==null )||
588          (source instanceof DOMSource && ((DOMSource)source).getNode()==null)){
589         try {
590           DocumentBuilderFactory builderF = 
591                    DocumentBuilderFactory.newInstance();
592           DocumentBuilder builder = builderF.newDocumentBuilder();
593           String systemID = source.getSystemId();
594           source = new DOMSource(builder.newDocument());
595
596           // Copy system ID from original, empty Source to new Source
597           if (systemID != null) {
598             source.setSystemId(systemID);
599           }
600         } catch (ParserConfigurationException e) {
601           fatalError(e);
602         }           
603       }
604       DTM dtm = mgr.getDTM(source, false, this, true, true);
605       dtm.setDocumentBaseURI(base);
606       
607       boolean hardDelete = true;  // %REVIEW% I have to think about this. -sb
608
609       try
610       {
611         // NOTE: This will work because this is _NOT_ a shared DTM, and thus has
612         // only a single Document node. If it could ever be an RTF or other
613         // shared DTM, look at dtm.getDocumentRoot(nodeHandle).
614         this.transformNode(dtm.getDocument());
615       }
616       finally
617       {
618         if (shouldRelease)
619           mgr.release(dtm, hardDelete);
620       }
621
622       // Kick off the parse.  When the ContentHandler gets 
623       // the startDocument event, it will call transformNode( node ).
624       // reader.parse( xmlSource );
625       // This has to be done to catch exceptions thrown from 
626       // the transform thread spawned by the STree handler.
627       Exception e = getExceptionThrown();
628
629       if (null != e)
630       {
631         if (e instanceof javax.xml.transform.TransformerException)
632         {
633           throw (javax.xml.transform.TransformerException) e;
634         }
635         else if (e instanceof org.apache.xml.utils.WrappedRuntimeException)
636         {
637           fatalError(
638               ((org.apache.xml.utils.WrappedRuntimeException) e).getException());
639         }
640         else
641         {
642           throw new javax.xml.transform.TransformerException(e);
643         }
644       }
645       else if (null != m_serializationHandler)
646       {
647         m_serializationHandler.endDocument();
648       }
649     }
650     catch (org.apache.xml.utils.WrappedRuntimeException wre)
651     {
652       Throwable throwable = wre.getException();
653
654       while (throwable
655              instanceof org.apache.xml.utils.WrappedRuntimeException)
656       {
657         throwable =
658           ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException();
659       }
660
661       fatalError(throwable);
662     }
663
664     // Patch attributed to David Eisenberg <david@catcode.com>
665     catch (org.xml.sax.SAXParseException spe)
666     {
667       fatalError(spe);
668     }
669     catch (org.xml.sax.SAXException se)
670     {
671       m_errorHandler.fatalError(new TransformerException(se));
672     }
673     finally
674     {
675       m_hasTransformThreadErrorCatcher = false;
676
677       // This looks to be redundent to the one done in TransformNode.
678       reset();
679     }
680   }
681   
682   private void fatalError(Throwable throwable) throws TransformerException
683   {
684     if (throwable instanceof org.xml.sax.SAXParseException)
685       m_errorHandler.fatalError(new TransformerException(throwable.getMessage(),new SAXSourceLocator((org.xml.sax.SAXParseException)throwable)));
686     else
687       m_errorHandler.fatalError(new TransformerException(throwable));
688     
689   }
690
691   /**
692    * Get the base URL of the source.
693    *
694    *
695    * NEEDSDOC @param base
696    * @return The base URL of the source tree, or null.
697    */
698   public void setBaseURLOfSource(String base)
699   {
700     m_urlOfSource = base;
701   }
702
703   /**
704    * Get an output property that is in effect for the
705    * transformation.  The property specified may be a property
706    * that was set with setOutputProperty, or it may be a
707    * property specified in the stylesheet.
708    *
709    * NEEDSDOC @param qnameString
710    *
711    * @return The string value of the output property, or null
712    * if no property was found.
713    *
714    * @throws IllegalArgumentException If the property is not supported.
715    *
716    * @see javax.xml.transform.OutputKeys
717    */
718   public String getOutputProperty(String qnameString)
719           throws IllegalArgumentException
720   {
721
722     String value = null;
723     OutputProperties props = getOutputFormat();
724
725     value = props.getProperty(qnameString);
726
727     if (null == value)
728     {
729       if (!OutputProperties.isLegalPropertyKey(qnameString))
730         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: "
731                                            //+ qnameString);
732     }
733
734     return value;
735   }
736
737   /**
738    * Get the value of a property, without using the default properties.  This
739    * can be used to test if a property has been explicitly set by the stylesheet
740    * or user.
741    *
742    * NEEDSDOC @param qnameString
743    *
744    * @return The value of the property, or null if not found.
745    *
746    * @throws IllegalArgumentException If the property is not supported,
747    * and is not namespaced.
748    */
749   public String getOutputPropertyNoDefault(String qnameString)
750           throws IllegalArgumentException
751   {
752
753     String value = null;
754     OutputProperties props = getOutputFormat();
755
756     value = (String) props.getProperties().get(qnameString);
757
758     if (null == value)
759     {
760       if (!OutputProperties.isLegalPropertyKey(qnameString))
761         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: "
762                                           // + qnameString);
763     }
764
765     return value;
766   }
767
768   /**
769    * This method is used to set or override the value
770    * of the effective xsl:output attribute values
771    * specified in the stylesheet.
772    * <p>
773    * The recognized standard output properties are:
774    * <ul>
775    * <li>cdata-section-elements
776    * <li>doctype-system
777    * <li>doctype-public
778    * <li>indent
779    * <li>media-type
780    * <li>method
781    * <li>omit-xml-declaration
782    * <li>standalone
783    * <li>version
784    * </ul>
785    * <p>
786    * For example:
787    * <pre>
788    *   tran.setOutputProperty("standalone", "yes");
789    * </pre>
790    * <p>
791    * In the case of the cdata-section-elements property,
792    * the value should be a whitespace separated list of
793    * element names.  The element name is the local name
794    * of the element, if it is in no namespace, or, the URI
795    * in braces followed immediately by the local name
796    * if the element is in that namespace. For example: 
797    * <pre>
798    * tran.setOutputProperty(
799    *   "cdata-section-elements", 
800    *   "elem1 {http://example.uri}elem2 elem3");
801    * </pre>
802    * <p>
803    * The recognized Xalan extension elements are: 
804    * <ul>
805    * <li>content-handler
806    * <li>entities
807    * <li>indent-amount
808    * <li>line-separator
809    * <li>omit-meta-tag
810    * <li>use-url-escaping
811    * </ul>
812    * <p>
813    * These must be in the extension namespace of
814    * "http://xml.apache.org/xalan".  This is accomplished
815    * by putting the namespace URI in braces before the 
816    * property name, for example:
817    * <pre>
818    *   tran.setOutputProperty(
819    *     "{http://xml.apache.org/xalan}line-separator" ,
820    *     "\n");
821    * </pre> 
822    *
823    * @param name The property name.
824    * @param value The requested value for the property.
825    * @throws IllegalArgumentException if the property name is not legal.
826    */
827   public void setOutputProperty(String name, String value)
828           throws IllegalArgumentException
829   {
830
831     synchronized (m_reentryGuard)
832     {
833
834       // Get the output format that was set by the user, otherwise get the 
835       // output format from the stylesheet.
836       if (null == m_outputFormat)
837       {
838         m_outputFormat =
839           (OutputProperties) getStylesheet().getOutputComposed().clone();
840       }
841
842       if (!OutputProperties.isLegalPropertyKey(name))
843         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{name})); //"output property not recognized: "
844                                            //+ name);
845
846       m_outputFormat.setProperty(name, value);
847     }
848   }
849
850   /**
851    * Set the output properties for the transformation.  These
852    * properties will override properties set in the templates
853    * with xsl:output.
854    *
855    * <p>If argument to this function is null, any properties
856    * previously set will be removed.</p>
857    *
858    * @param oformat A set of output properties that will be
859    * used to override any of the same properties in effect
860    * for the transformation.
861    *
862    * @see javax.xml.transform.OutputKeys
863    * @see java.util.Properties
864    *
865    * @throws IllegalArgumentException if any of the argument keys are not
866    * recognized and are not namespace qualified.   
867    */
868   public void setOutputProperties(Properties oformat)
869                 throws IllegalArgumentException
870   {
871
872     synchronized (m_reentryGuard)
873     {
874       if (null != oformat)
875       {
876
877         // See if an *explicit* method was set.
878         String method = (String) oformat.get(OutputKeys.METHOD);
879
880         if (null != method)
881           m_outputFormat = new OutputProperties(method);
882         else if(m_outputFormat==null)
883           m_outputFormat = new OutputProperties();
884
885         m_outputFormat.copyFrom(oformat);
886         // copyFrom does not set properties that have been already set, so 
887         // this must be called after, which is a bit in the reverse from 
888         // what one might think.
889         m_outputFormat.copyFrom(m_stylesheetRoot.getOutputProperties());
890       }
891       else {
892         // if oformat is null JAXP says that any props previously set are removed
893         // and we are to revert back to those in the templates object (i.e. Stylesheet).
894         m_outputFormat = null;
895       }
896     }
897   }
898
899   /**
900    * Get a copy of the output properties for the transformation.  These
901    * properties will override properties set in the templates
902    * with xsl:output.
903    *
904    * <p>Note that mutation of the Properties object returned will not
905    * effect the properties that the transformation contains.</p>
906    *
907    * @return  A copy of the set of output properties in effect
908    * for the next transformation.
909    *
910    * NEEDSDOC ($objectName$) @return
911    */
912   public Properties getOutputProperties()
913   {
914     return (Properties) getOutputFormat().getProperties().clone();
915   }
916
917     /**
918      * Create a result ContentHandler from a Result object, based
919      * on the current OutputProperties.
920      *
921      * @param outputTarget Where the transform result should go,
922      * should not be null.
923      *
924      * @return A valid ContentHandler that will create the
925      * result tree when it is fed SAX events.
926      *
927      * @throws TransformerException
928      */
929     public SerializationHandler createSerializationHandler(Result outputTarget)
930             throws TransformerException
931     {
932        SerializationHandler xoh =
933         createSerializationHandler(outputTarget, getOutputFormat());
934        return xoh;
935     }
936
937     /**
938      * Create a ContentHandler from a Result object and an OutputProperties.
939      *
940      * @param outputTarget Where the transform result should go,
941      * should not be null.
942      * @param format The OutputProperties object that will contain
943      * instructions on how to serialize the output.
944      *
945      * @return A valid ContentHandler that will create the
946      * result tree when it is fed SAX events.
947      *
948      * @throws TransformerException
949      */
950     public SerializationHandler createSerializationHandler(
951             Result outputTarget, OutputProperties format)
952               throws TransformerException
953     {
954
955       SerializationHandler xoh;
956
957       // If the Result object contains a Node, then create
958       // a ContentHandler that will add nodes to the input node.
959       org.w3c.dom.Node outputNode = null;
960
961       if (outputTarget instanceof DOMResult)
962       {
963         outputNode = ((DOMResult) outputTarget).getNode();
964         org.w3c.dom.Node nextSibling = ((DOMResult)outputTarget).getNextSibling();
965
966         org.w3c.dom.Document doc;
967         short type;
968
969         if (null != outputNode)
970         {
971           type = outputNode.getNodeType();
972           doc = (org.w3c.dom.Node.DOCUMENT_NODE == type)
973                 ? (org.w3c.dom.Document) outputNode
974                 : outputNode.getOwnerDocument();
975         }
976         else
977         {
978           boolean isSecureProcessing = m_stylesheetRoot.isSecureProcessing();
979           doc = org.apache.xml.utils.DOMHelper.createDocument(isSecureProcessing);
980           outputNode = doc;
981           type = outputNode.getNodeType();
982
983           ((DOMResult) outputTarget).setNode(outputNode);
984         }
985
986         DOMBuilder handler =
987           (org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE == type)
988           ? new DOMBuilder(doc, (org.w3c.dom.DocumentFragment) outputNode)
989           : new DOMBuilder(doc, outputNode);
990         
991         if (nextSibling != null)
992           handler.setNextSibling(nextSibling);
993         
994           String encoding = format.getProperty(OutputKeys.ENCODING);          
995           xoh = new ToXMLSAXHandler(handler, (LexicalHandler)handler, encoding);
996       }
997       else if (outputTarget instanceof SAXResult)
998       {
999         ContentHandler handler = ((SAXResult) outputTarget).getHandler();
1000         
1001         if (null == handler)
1002            throw new IllegalArgumentException(
1003              "handler can not be null for a SAXResult"); 
1004              
1005         LexicalHandler lexHandler;
1006         if (handler instanceof LexicalHandler)     
1007             lexHandler = (LexicalHandler)  handler;
1008         else
1009             lexHandler = null;
1010             
1011         String encoding = format.getProperty(OutputKeys.ENCODING); 
1012         String method = format.getProperty(OutputKeys.METHOD);
1013
1014         ToXMLSAXHandler toXMLSAXHandler = new ToXMLSAXHandler(handler, lexHandler, encoding);
1015         toXMLSAXHandler.setShouldOutputNSAttr(false);
1016         xoh = toXMLSAXHandler;   
1017
1018
1019         String publicID = format.getProperty(OutputKeys.DOCTYPE_PUBLIC); 
1020         String systemID = format.getProperty(OutputKeys.DOCTYPE_SYSTEM); 
1021         if (systemID != null)
1022             xoh.setDoctypeSystem(systemID);
1023         if (publicID != null)
1024             xoh.setDoctypePublic(publicID);
1025         
1026         if (handler instanceof TransformerClient) {
1027             XalanTransformState state = new XalanTransformState();
1028             ((TransformerClient)handler).setTransformState(state);
1029             ((ToSAXHandler)xoh).setTransformState(state);
1030         }
1031
1032  
1033       }
1034
1035       // Otherwise, create a ContentHandler that will serialize the
1036       // result tree to either a stream or a writer.
1037       else if (outputTarget instanceof StreamResult)
1038       {
1039         StreamResult sresult = (StreamResult) outputTarget;
1040
1041         try
1042         {
1043           SerializationHandler serializer =
1044             (SerializationHandler) SerializerFactory.getSerializer(format.getProperties());
1045
1046           if (null != sresult.getWriter())
1047             serializer.setWriter(sresult.getWriter());
1048           else if (null != sresult.getOutputStream())
1049             serializer.setOutputStream(sresult.getOutputStream());
1050           else if (null != sresult.getSystemId())
1051           {
1052             String fileURL = sresult.getSystemId();
1053
1054             if (fileURL.startsWith("file:///"))
1055             {
1056               if (fileURL.substring(8).indexOf(":") >0)
1057                 fileURL = fileURL.substring(8);
1058               else
1059                 fileURL = fileURL.substring(7);
1060             }
1061             else if (fileURL.startsWith("file:/"))
1062             {
1063                 if (fileURL.substring(6).indexOf(":") >0)
1064                     fileURL = fileURL.substring(6);
1065                   else
1066                     fileURL = fileURL.substring(5);             
1067             }
1068
1069             m_outputStream = new java.io.FileOutputStream(fileURL);
1070
1071             serializer.setOutputStream(m_outputStream);
1072             
1073             xoh = serializer;
1074           }
1075           else
1076             throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_OUTPUT_SPECIFIED, null)); //"No output specified!");
1077
1078           // handler = serializer.asContentHandler();
1079
1080         //  this.setSerializer(serializer);
1081
1082           xoh = serializer;  
1083         }
1084 //        catch (UnsupportedEncodingException uee)
1085 //        {
1086 //          throw new TransformerException(uee);
1087 //        }
1088         catch (IOException ioe)
1089         {
1090           throw new TransformerException(ioe);
1091         }
1092       }
1093       else
1094       {
1095         throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_TRANSFORM_TO_RESULT_TYPE, new Object[]{outputTarget.getClass().getName()})); //"Can't transform to a Result of type "
1096                                        //+ outputTarget.getClass().getName()
1097                                        //+ "!");
1098       }
1099       
1100       // before we forget, lets make the created handler hold a reference
1101       // to the current TransformImpl object
1102       xoh.setTransformer(this);
1103
1104       SourceLocator srcLocator = getStylesheet();
1105       xoh.setSourceLocator(srcLocator);
1106       
1107       
1108       return xoh;
1109
1110    
1111     }
1112         
1113         /**
1114    * Process the source tree to the output result.
1115    * @param xmlSource  The input for the source tree.
1116    * @param outputTarget The output source target.
1117    *
1118    * @throws TransformerException
1119    */
1120   public void transform(Source xmlSource, Result outputTarget)
1121           throws TransformerException
1122   {
1123                 transform(xmlSource, outputTarget, true);
1124         }
1125
1126   /**
1127    * Process the source tree to the output result.
1128    * @param xmlSource  The input for the source tree.
1129    * @param outputTarget The output source target.
1130    * @param shouldRelease  Flag indicating whether to release DTMManager. 
1131    *
1132    * @throws TransformerException
1133    */
1134   public void transform(Source xmlSource, Result outputTarget, boolean shouldRelease)
1135           throws TransformerException
1136   {
1137
1138     synchronized (m_reentryGuard)
1139     {
1140       SerializationHandler xoh = createSerializationHandler(outputTarget);
1141       this.setSerializationHandler(xoh);        
1142
1143       m_outputTarget = outputTarget;
1144
1145       transform(xmlSource, shouldRelease);
1146     }
1147   }
1148
1149   /**
1150    * Process the source node to the output result, if the
1151    * processor supports the "http://xml.org/trax/features/dom/input"
1152    * feature.
1153    * %REVIEW% Do we need a Node version of this?
1154    * @param node  The input source node, which can be any valid DTM node.
1155    * @param outputTarget The output source target.
1156    *
1157    * @throws TransformerException
1158    */
1159   public void transformNode(int node, Result outputTarget)
1160           throws TransformerException
1161   {
1162     
1163
1164     SerializationHandler xoh = createSerializationHandler(outputTarget);
1165     this.setSerializationHandler(xoh);
1166
1167     m_outputTarget = outputTarget;
1168
1169     transformNode(node);
1170   }
1171
1172   /**
1173    * Process the source node to the output result, if the
1174    * processor supports the "http://xml.org/trax/features/dom/input"
1175    * feature.
1176    * %REVIEW% Do we need a Node version of this?
1177    * @param node  The input source node, which can be any valid DTM node.
1178    *
1179    * @throws TransformerException
1180    */
1181   public void transformNode(int node) throws TransformerException
1182   {
1183     //dml
1184     setExtensionsTable(getStylesheet());
1185     // Make sure we're not writing to the same output content handler.
1186     synchronized (m_serializationHandler)
1187     {
1188       m_hasBeenReset = false;
1189       
1190       XPathContext xctxt = getXPathContext();
1191       DTM dtm = xctxt.getDTM(node);
1192
1193       try
1194       {
1195         pushGlobalVars(node);
1196
1197         // ==========
1198         // Give the top-level templates a chance to pass information into 
1199         // the context (this is mainly for setting up tables for extensions).
1200         StylesheetRoot stylesheet = this.getStylesheet();
1201         int n = stylesheet.getGlobalImportCount();
1202
1203         for (int i = 0; i < n; i++)
1204         {
1205           StylesheetComposed imported = stylesheet.getGlobalImport(i);
1206           int includedCount = imported.getIncludeCountComposed();
1207
1208           for (int j = -1; j < includedCount; j++)
1209           {
1210             Stylesheet included = imported.getIncludeComposed(j);
1211
1212             included.runtimeInit(this);
1213
1214             for (ElemTemplateElement child = included.getFirstChildElem();
1215                     child != null; child = child.getNextSiblingElem())
1216             {
1217               child.runtimeInit(this);
1218             }
1219           }
1220         }
1221         // ===========        
1222         // System.out.println("Calling applyTemplateToNode - "+Thread.currentThread().getName());
1223         DTMIterator dtmIter = new org.apache.xpath.axes.SelfIteratorNoPredicate();
1224         dtmIter.setRoot(node, xctxt);
1225         xctxt.pushContextNodeList(dtmIter);
1226         try
1227         {
1228           this.applyTemplateToNode(null, null, node);
1229         }
1230         finally
1231         {
1232           xctxt.popContextNodeList();
1233         }
1234         // m_stylesheetRoot.getStartRule().execute(this);
1235
1236         // System.out.println("Done with applyTemplateToNode - "+Thread.currentThread().getName());
1237         if (null != m_serializationHandler)
1238         {
1239           m_serializationHandler.endDocument();
1240         }
1241       }
1242       catch (Exception se)
1243       {
1244
1245         // System.out.println(Thread.currentThread().getName()+" threw an exception! "
1246         //                   +se.getMessage());
1247         // If an exception was thrown, we need to make sure that any waiting 
1248         // handlers can terminate, which I guess is best done by sending 
1249         // an endDocument.
1250         
1251         // SAXSourceLocator
1252         while(se instanceof org.apache.xml.utils.WrappedRuntimeException)
1253         {
1254           Exception e = ((org.apache.xml.utils.WrappedRuntimeException)se).getException();
1255           if(null != e)
1256             se = e;
1257         }
1258         
1259         if (null != m_serializationHandler)
1260         {
1261           try
1262           {
1263             if(se instanceof org.xml.sax.SAXParseException)
1264               m_serializationHandler.fatalError((org.xml.sax.SAXParseException)se);
1265             else if(se instanceof TransformerException)
1266             {
1267               TransformerException te = ((TransformerException)se);
1268               SAXSourceLocator sl = new SAXSourceLocator( te.getLocator() );
1269               m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(te.getMessage(), sl, te)); 
1270             }
1271             else
1272             {
1273               m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(se.getMessage(), new SAXSourceLocator(), se)); 
1274             }             
1275           }
1276           catch (Exception e){}
1277         }        
1278         
1279         if(se instanceof TransformerException)
1280         {
1281           m_errorHandler.fatalError((TransformerException)se);
1282         }
1283         else if(se instanceof org.xml.sax.SAXParseException)
1284         {
1285           m_errorHandler.fatalError(new TransformerException(se.getMessage(), 
1286                       new SAXSourceLocator((org.xml.sax.SAXParseException)se), 
1287                       se));
1288         }
1289         else
1290         {
1291           m_errorHandler.fatalError(new TransformerException(se));
1292         }
1293         
1294       }
1295       finally
1296       {
1297         this.reset();
1298       }
1299     }
1300   }
1301
1302   /**
1303    * Get a SAX2 ContentHandler for the input.
1304    *
1305    * @return A valid ContentHandler, which should never be null, as
1306    * long as getFeature("http://xml.org/trax/features/sax/input")
1307    * returns true.
1308    */
1309   public ContentHandler getInputContentHandler()
1310   {
1311     return getInputContentHandler(false);
1312   }
1313
1314   /**
1315    * Get a SAX2 ContentHandler for the input.
1316    *
1317    * @param doDocFrag true if a DocumentFragment should be created as
1318    * the root, rather than a Document.
1319    *
1320    * @return A valid ContentHandler, which should never be null, as
1321    * long as getFeature("http://xml.org/trax/features/sax/input")
1322    * returns true.
1323    */
1324   public ContentHandler getInputContentHandler(boolean doDocFrag)
1325   {
1326
1327     if (null == m_inputContentHandler)
1328     {
1329
1330       //      if(null == m_urlOfSource && null != m_stylesheetRoot)
1331       //        m_urlOfSource = m_stylesheetRoot.getBaseIdentifier();
1332       m_inputContentHandler = new TransformerHandlerImpl(this, doDocFrag,
1333               m_urlOfSource);
1334     }
1335
1336     return m_inputContentHandler;
1337   }
1338
1339   /**
1340    * Set the output properties for the transformation.  These
1341    * properties will override properties set in the templates
1342    * with xsl:output.
1343    *
1344    * @param oformat A valid OutputProperties object (which will
1345    * not be mutated), or null.
1346    */
1347   public void setOutputFormat(OutputProperties oformat)
1348   {
1349     m_outputFormat = oformat;
1350   }
1351
1352   /**
1353    * Get the output properties used for the transformation.
1354    *
1355    * @return the output format that was set by the user,
1356    * otherwise the output format from the stylesheet.
1357    */
1358   public OutputProperties getOutputFormat()
1359   {
1360
1361     // Get the output format that was set by the user, otherwise get the 
1362     // output format from the stylesheet.
1363     OutputProperties format = (null == m_outputFormat)
1364                               ? getStylesheet().getOutputComposed()
1365                               : m_outputFormat;
1366
1367     return format;
1368   }
1369
1370   /**
1371    * Set a parameter for the templates.
1372    * 
1373    * @param name The name of the parameter.
1374    * @param namespace The namespace of the parameter.
1375    * @param value The value object.  This can be any valid Java object
1376    * -- it's up to the processor to provide the proper
1377    * coersion to the object, or simply pass it on for use
1378    * in extensions.
1379    */
1380   public void setParameter(String name, String namespace, Object value)
1381   {
1382
1383     VariableStack varstack = getXPathContext().getVarStack();
1384     QName qname = new QName(namespace, name);
1385     XObject xobject = XObject.create(value, getXPathContext());
1386     
1387     StylesheetRoot sroot = m_stylesheetRoot;
1388     Vector vars = sroot.getVariablesAndParamsComposed();
1389     int i = vars.size();
1390     while (--i >= 0)
1391     {
1392       ElemVariable variable = (ElemVariable)vars.elementAt(i);
1393       if(variable.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE && 
1394          variable.getName().equals(qname))
1395       {
1396           varstack.setGlobalVariable(i, xobject);
1397       }
1398     }
1399   }
1400
1401   /** NEEDSDOC Field m_userParams          */
1402   Vector m_userParams;
1403
1404   /**
1405    * Set a parameter for the transformation.
1406    *
1407    * @param name The name of the parameter,
1408    *             which may have a namespace URI.
1409    * @param value The value object.  This can be any valid Java object
1410    * -- it's up to the processor to provide the proper
1411    * coersion to the object, or simply pass it on for use
1412    * in extensions.
1413    */
1414   public void setParameter(String name, Object value)
1415   {
1416     
1417     if (value == null) {
1418       throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_SET_PARAM_VALUE, new Object[]{name}));
1419     }    
1420
1421     StringTokenizer tokenizer = new StringTokenizer(name, "{}", false);
1422
1423     try
1424     {
1425
1426       // The first string might be the namespace, or it might be 
1427       // the local name, if the namespace is null.
1428       String s1 = tokenizer.nextToken();
1429       String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
1430
1431       if (null == m_userParams)
1432         m_userParams = new Vector();
1433
1434       if (null == s2)
1435       {
1436         replaceOrPushUserParam(new QName(s1), XObject.create(value, getXPathContext()));
1437         setParameter(s1, null, value);
1438       }
1439       else
1440       {
1441         replaceOrPushUserParam(new QName(s1, s2), XObject.create(value, getXPathContext()));
1442         setParameter(s2, s1, value);
1443       }
1444     }
1445     catch (java.util.NoSuchElementException nsee)
1446     {
1447
1448       // Should throw some sort of an error.
1449     }
1450   }
1451
1452   /**
1453    * NEEDSDOC Method replaceOrPushUserParam 
1454    *
1455    *
1456    * NEEDSDOC @param qname
1457    * NEEDSDOC @param xval
1458    */
1459   private void replaceOrPushUserParam(QName qname, XObject xval)
1460   {
1461
1462     int n = m_userParams.size();
1463
1464     for (int i = n - 1; i >= 0; i--)
1465     {
1466       Arg arg = (Arg) m_userParams.elementAt(i);
1467
1468       if (arg.getQName().equals(qname))
1469       {
1470         m_userParams.setElementAt(new Arg(qname, xval, true), i);
1471
1472         return;
1473       }
1474     }
1475
1476     m_userParams.addElement(new Arg(qname, xval, true));
1477   }
1478
1479   /**
1480    * Get a parameter that was explicitly set with setParameter
1481    * or setParameters.
1482    *
1483    *
1484    * NEEDSDOC @param name
1485    * @return A parameter that has been set with setParameter
1486    * or setParameters,
1487    * *not* all the xsl:params on the stylesheet (which require
1488    * a transformation Source to be evaluated).
1489    */
1490   public Object getParameter(String name)
1491   {
1492
1493     try
1494     {
1495
1496       // VariableStack varstack = getXPathContext().getVarStack();
1497       // The first string might be the namespace, or it might be 
1498       // the local name, if the namespace is null.
1499       QName qname = QName.getQNameFromString(name);
1500
1501       if (null == m_userParams)
1502         return null;
1503
1504       int n = m_userParams.size();
1505
1506       for (int i = n - 1; i >= 0; i--)
1507       {
1508         Arg arg = (Arg) m_userParams.elementAt(i);
1509
1510         if (arg.getQName().equals(qname))
1511         {
1512           return arg.getVal().object();
1513         }
1514       }
1515
1516       return null;
1517     }
1518     catch (java.util.NoSuchElementException nsee)
1519     {
1520
1521       // Should throw some sort of an error.
1522       return null;
1523     }
1524   }
1525   
1526   /**
1527    * Reset parameters that the user specified for the transformation.
1528    * Called during transformer.reset() after we have cleared the 
1529    * variable stack. We need to make sure that user params are
1530    * reset so that the transformer object can be reused. 
1531    */
1532   private void resetUserParameters()
1533   {
1534
1535     try
1536     {
1537       
1538       if (null == m_userParams)
1539         return;
1540
1541       int n = m_userParams.size();
1542       for (int i = n - 1; i >= 0; i--)
1543       {
1544         Arg arg = (Arg) m_userParams.elementAt(i);
1545         QName name = arg.getQName();
1546         // The first string might be the namespace, or it might be 
1547         // the local name, if the namespace is null.
1548         String s1 = name.getNamespace();
1549         String s2 = name.getLocalPart();
1550
1551         setParameter(s2, s1, arg.getVal().object());
1552         
1553       }
1554       
1555     }
1556     catch (java.util.NoSuchElementException nsee)
1557     {
1558       // Should throw some sort of an error.
1559       
1560     }
1561   }
1562
1563   /**
1564    * Set a bag of parameters for the transformation. Note that
1565    * these will not be additive, they will replace the existing
1566    * set of parameters.
1567    *
1568    * NEEDSDOC @param params
1569    */
1570   public void setParameters(Properties params)
1571   {
1572
1573     clearParameters();
1574
1575     Enumeration names = params.propertyNames();
1576
1577     while (names.hasMoreElements())
1578     {
1579       String name = params.getProperty((String) names.nextElement());
1580       StringTokenizer tokenizer = new StringTokenizer(name, "{}", false);
1581
1582       try
1583       {
1584
1585         // The first string might be the namespace, or it might be 
1586         // the local name, if the namespace is null.
1587         String s1 = tokenizer.nextToken();
1588         String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
1589
1590         if (null == s2)
1591           setParameter(s1, null, params.getProperty(name));
1592         else
1593           setParameter(s2, s1, params.getProperty(name));
1594       }
1595       catch (java.util.NoSuchElementException nsee)
1596       {
1597
1598         // Should throw some sort of an error.
1599       }
1600     }
1601   }
1602
1603   /**
1604    * Reset the parameters to a null list.
1605    */
1606   public void clearParameters()
1607   {
1608
1609     synchronized (m_reentryGuard)
1610     {
1611       VariableStack varstack = new VariableStack();
1612
1613       m_xcontext.setVarStack(varstack);
1614
1615       m_userParams = null;
1616     }
1617   }
1618
1619
1620   /**
1621    * Internal -- push the global variables from the Stylesheet onto
1622    * the context's runtime variable stack.
1623    * <p>If we encounter a variable
1624    * that is already defined in the variable stack, we ignore it.  This
1625    * is because the second variable definition will be at a lower import
1626    * precedence.  Presumably, global"variables at the same import precedence
1627    * with the same name will have been caught during the recompose process.
1628    * <p>However, if we encounter a parameter that is already defined in the
1629    * variable stack, we need to see if this is a parameter whose value was
1630    * supplied by a setParameter call.  If so, we need to "receive" the one
1631    * already in the stack, ignoring this one.  If it is just an earlier
1632    * xsl:param or xsl:variable definition, we ignore it using the same
1633    * reasoning as explained above for the variable.
1634    *
1635    * @param contextNode The root of the source tree, can't be null.
1636    *
1637    * @throws TransformerException
1638    */
1639   protected void pushGlobalVars(int contextNode) throws TransformerException
1640   {
1641
1642     XPathContext xctxt = m_xcontext;
1643     VariableStack vs = xctxt.getVarStack();
1644     StylesheetRoot sr = getStylesheet();
1645     Vector vars = sr.getVariablesAndParamsComposed();
1646     
1647     int i = vars.size();
1648     vs.link(i);
1649
1650     while (--i >= 0)
1651     {
1652       ElemVariable v = (ElemVariable) vars.elementAt(i);
1653
1654       // XObject xobj = v.getValue(this, contextNode);
1655       XObject xobj = new XUnresolvedVariable(v, contextNode, this,
1656                                      vs.getStackFrame(), 0, true);
1657       
1658       if(null == vs.elementAt(i))                               
1659         vs.setGlobalVariable(i, xobj);
1660     }
1661
1662   }
1663
1664   /**
1665    * Set an object that will be used to resolve URIs used in
1666    * document(), etc.
1667    * @param resolver An object that implements the URIResolver interface,
1668    * or null.
1669    */
1670   public void setURIResolver(URIResolver resolver)
1671   {
1672
1673     synchronized (m_reentryGuard)
1674     {
1675       m_xcontext.getSourceTreeManager().setURIResolver(resolver);
1676     }
1677   }
1678
1679   /**
1680    * Get an object that will be used to resolve URIs used in
1681    * document(), etc.
1682    *
1683    * @return An object that implements the URIResolver interface,
1684    * or null.
1685    */
1686   public URIResolver getURIResolver()
1687   {
1688     return m_xcontext.getSourceTreeManager().getURIResolver();
1689   }
1690
1691   // ======== End Transformer Implementation ========  
1692
1693   /**
1694    * Set the content event handler.
1695    *
1696    * NEEDSDOC @param handler
1697    * @throws java.lang.NullPointerException If the handler
1698    *            is null.
1699    * @see org.xml.sax.XMLReader#setContentHandler
1700    */
1701   public void setContentHandler(ContentHandler handler)
1702   {
1703
1704     if (handler == null)
1705     {
1706       throw new NullPointerException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_CONTENT_HANDLER, null)); //"Null content handler");
1707     }
1708     else
1709     {
1710       m_outputContentHandler = handler;
1711
1712       if (null == m_serializationHandler)
1713       {
1714         ToXMLSAXHandler h = new ToXMLSAXHandler();
1715         h.setContentHandler(handler);
1716         h.setTransformer(this);
1717         
1718         m_serializationHandler = h;
1719       }
1720       else
1721         m_serializationHandler.setContentHandler(handler);
1722     }
1723   }
1724
1725   /**
1726    * Get the content event handler.
1727    *
1728    * @return The current content handler, or null if none was set.
1729    * @see org.xml.sax.XMLReader#getContentHandler
1730    */
1731   public ContentHandler getContentHandler()
1732   {
1733     return m_outputContentHandler;
1734   }
1735
1736   /**
1737    * Given a stylesheet element, create a result tree fragment from it's
1738    * contents. The fragment will be built within the shared RTF DTM system
1739    * used as a variable stack.
1740    * @param templateParent The template element that holds the fragment.
1741    * @return the NodeHandle for the root node of the resulting RTF.
1742    *
1743    * @throws TransformerException
1744    * @xsl.usage advanced
1745    */
1746   public int transformToRTF(ElemTemplateElement templateParent)
1747           throws TransformerException
1748   {
1749     // Retrieve a DTM to contain the RTF. At this writing, this may be a
1750     // multi-document DTM (SAX2RTFDTM).
1751     DTM dtmFrag = m_xcontext.getRTFDTM();
1752     return transformToRTF(templateParent,dtmFrag);
1753   }
1754   
1755   /**
1756    * Given a stylesheet element, create a result tree fragment from it's
1757    * contents. The fragment will also use the shared DTM system, but will
1758    * obtain its space from the global variable pool rather than the dynamic
1759    * variable stack. This allows late binding of XUnresolvedVariables without
1760    * the risk that their content will be discarded when the variable stack
1761    * is popped.
1762    * 
1763    * @param templateParent The template element that holds the fragment.
1764    * @return the NodeHandle for the root node of the resulting RTF.
1765    *
1766    * @throws TransformerException
1767    * @xsl.usage advanced
1768    */
1769   public int transformToGlobalRTF(ElemTemplateElement templateParent)
1770           throws TransformerException
1771   {
1772     // Retrieve a DTM to contain the RTF. At this writing, this may be a
1773     // multi-document DTM (SAX2RTFDTM).
1774     DTM dtmFrag = m_xcontext.getGlobalRTFDTM();
1775     return transformToRTF(templateParent,dtmFrag);
1776   }
1777   
1778   /**
1779    * Given a stylesheet element, create a result tree fragment from it's
1780    * contents.
1781    * @param templateParent The template element that holds the fragment.
1782    * @param dtmFrag The DTM to write the RTF into
1783    * @return the NodeHandle for the root node of the resulting RTF.
1784    *
1785    * @throws TransformerException
1786    * @xsl.usage advanced
1787    */
1788   private int transformToRTF(ElemTemplateElement templateParent,DTM dtmFrag)
1789           throws TransformerException
1790   {
1791
1792     XPathContext xctxt = m_xcontext;
1793     
1794     ContentHandler rtfHandler = dtmFrag.getContentHandler();
1795
1796     // Obtain the ResultTreeFrag's root node.
1797     // NOTE: In SAX2RTFDTM, this value isn't available until after
1798     // the startDocument has been issued, so assignment has been moved
1799     // down a bit in the code.
1800     int resultFragment; // not yet reliably = dtmFrag.getDocument();
1801
1802     // Save the current result tree handler.
1803     SerializationHandler savedRTreeHandler = this.m_serializationHandler;
1804  
1805
1806     // And make a new handler for the RTF.
1807     ToSAXHandler h = new ToXMLSAXHandler();
1808     h.setContentHandler(rtfHandler);
1809     h.setTransformer(this);
1810     
1811     // Replace the old handler (which was already saved)
1812     m_serializationHandler = h;
1813  
1814     // use local variable for the current handler
1815     SerializationHandler rth = m_serializationHandler;
1816
1817     try
1818     {
1819       rth.startDocument();
1820       
1821       // startDocument is "bottlenecked" in RTH. We need it acted upon immediately,
1822       // to set the DTM's state as in-progress, so that if the xsl:variable's body causes
1823       // further RTF activity we can keep that from bashing this DTM.
1824       rth.flushPending(); 
1825  
1826       try
1827       {
1828
1829         // Do the transformation of the child elements.
1830         executeChildTemplates(templateParent, true);
1831
1832         // Make sure everything is flushed!
1833         rth.flushPending();
1834         
1835         // Get the document ID. May not exist until the RTH has not only
1836         // received, but flushed, the startDocument, and may be invalid
1837         // again after the document has been closed (still debating that)
1838         // ... so waiting until just before the end seems simplest/safest. 
1839         resultFragment = dtmFrag.getDocument();      
1840       }
1841       finally
1842       {
1843         rth.endDocument();
1844       }
1845     }
1846     catch (org.xml.sax.SAXException se)
1847     {
1848       throw new TransformerException(se);
1849     }
1850     finally
1851     {
1852
1853       // Restore the previous result tree handler.
1854       this.m_serializationHandler = savedRTreeHandler;
1855     }
1856
1857     return resultFragment;
1858   }
1859
1860   /**
1861    * Take the contents of a template element, process it, and
1862    * convert it to a string.
1863    *
1864    * @param elem The parent element whose children will be output
1865    * as a string.
1866    *
1867    * @return The stringized result of executing the elements children.
1868    *
1869    * @throws TransformerException
1870    * @xsl.usage advanced
1871    */
1872   public String transformToString(ElemTemplateElement elem)
1873           throws TransformerException
1874   {
1875     ElemTemplateElement firstChild = elem.getFirstChildElem();
1876     if(null == firstChild)
1877       return "";
1878     if(elem.hasTextLitOnly() && m_optimizer)
1879     {
1880       return ((ElemTextLiteral)firstChild).getNodeValue();
1881     }
1882
1883     // Save the current result tree handler.
1884     SerializationHandler savedRTreeHandler = this.m_serializationHandler;
1885
1886     // Create a Serializer object that will handle the SAX events 
1887     // and build the ResultTreeFrag nodes.
1888     StringWriter sw = (StringWriter) m_stringWriterObjectPool.getInstance();
1889
1890     m_serializationHandler =
1891         (ToTextStream) m_textResultHandlerObjectPool.getInstance();
1892
1893       if (null == m_serializationHandler)
1894       {
1895         // if we didn't get one from the pool, go make a new one
1896
1897         
1898         Serializer serializer = org.apache.xml.serializer.SerializerFactory.getSerializer(
1899             m_textformat.getProperties());
1900         m_serializationHandler = (SerializationHandler) serializer;
1901       } 
1902
1903         m_serializationHandler.setTransformer(this);
1904         m_serializationHandler.setWriter(sw);
1905  
1906  
1907     String result;
1908
1909     try
1910     {
1911         /* Don't call startDocument, the SerializationHandler  will
1912          * generate its own internal startDocument call anyways
1913          */
1914       // this.m_serializationHandler.startDocument();
1915
1916       // Do the transformation of the child elements.
1917       executeChildTemplates(elem, true);
1918         this.m_serializationHandler.endDocument();
1919
1920       result = sw.toString();
1921     }
1922     catch (org.xml.sax.SAXException se)
1923     {
1924       throw new TransformerException(se);
1925     }
1926     finally
1927     {
1928       sw.getBuffer().setLength(0);
1929
1930       try
1931       {
1932         sw.close();
1933       }
1934       catch (Exception ioe){}
1935
1936       m_stringWriterObjectPool.freeInstance(sw);
1937       m_serializationHandler.reset();
1938       m_textResultHandlerObjectPool.freeInstance(m_serializationHandler);
1939
1940       // Restore the previous result tree handler.
1941       m_serializationHandler = savedRTreeHandler;
1942     }
1943
1944     return result;
1945   }
1946
1947   /**
1948    * Given an element and mode, find the corresponding
1949    * template and process the contents.
1950    *
1951    * @param xslInstruction The calling element.
1952    * @param template The template to use if xsl:for-each, current template for apply-imports, or null.
1953    * @param child The source context node.
1954    * @throws TransformerException
1955    * @return true if applied a template, false if not.
1956    * @xsl.usage advanced
1957    */
1958   public boolean applyTemplateToNode(ElemTemplateElement xslInstruction,  // xsl:apply-templates or xsl:for-each
1959                                      ElemTemplate template, int child)
1960                                              throws TransformerException
1961   {
1962
1963     DTM dtm = m_xcontext.getDTM(child);
1964     short nodeType = dtm.getNodeType(child);
1965     boolean isDefaultTextRule = false;
1966     boolean isApplyImports = false;
1967     
1968     isApplyImports = ((xslInstruction == null)
1969                                 ? false
1970                                 : xslInstruction.getXSLToken()
1971                                   == Constants.ELEMNAME_APPLY_IMPORTS);        
1972
1973     if (null == template || isApplyImports)
1974     {
1975       int maxImportLevel, endImportLevel=0;
1976
1977       if (isApplyImports)
1978       {
1979         maxImportLevel =
1980           template.getStylesheetComposed().getImportCountComposed() - 1;
1981         endImportLevel =
1982           template.getStylesheetComposed().getEndImportCountComposed();
1983       }
1984       else
1985       {
1986         maxImportLevel = -1;
1987       }
1988
1989       // If we're trying an xsl:apply-imports at the top level (ie there are no
1990       // imported stylesheets), we need to indicate that there is no matching template.
1991       // The above logic will calculate a maxImportLevel of -1 which indicates
1992       // that we should find any template.  This is because a value of -1 for
1993       // maxImportLevel has a special meaning.  But we don't want that.
1994       // We want to match -no- templates. See bugzilla bug 1170.
1995       if (isApplyImports && (maxImportLevel == -1))
1996       {
1997         template = null;
1998       }
1999       else
2000       {
2001
2002         // Find the XSL template that is the best match for the 
2003         // element.        
2004         XPathContext xctxt = m_xcontext;
2005
2006         try
2007         {
2008           xctxt.pushNamespaceContext(xslInstruction);
2009
2010           QName mode = this.getMode();
2011           
2012           if (isApplyImports)
2013             template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode,
2014                   maxImportLevel, endImportLevel, m_quietConflictWarnings, dtm);
2015           else
2016             template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode,
2017                   m_quietConflictWarnings, dtm);
2018           
2019         }
2020         finally
2021         {
2022           xctxt.popNamespaceContext();
2023         }
2024       }
2025
2026       // If that didn't locate a node, fall back to a default template rule.
2027       // See http://www.w3.org/TR/xslt#built-in-rule.
2028       if (null == template)
2029       {
2030         switch (nodeType)
2031         {
2032         case DTM.DOCUMENT_FRAGMENT_NODE :
2033         case DTM.ELEMENT_NODE :
2034           template = m_stylesheetRoot.getDefaultRule();
2035           break;
2036         case DTM.CDATA_SECTION_NODE :
2037         case DTM.TEXT_NODE :
2038         case DTM.ATTRIBUTE_NODE :
2039           template = m_stylesheetRoot.getDefaultTextRule();
2040           isDefaultTextRule = true;
2041           break;
2042         case DTM.DOCUMENT_NODE :
2043           template = m_stylesheetRoot.getDefaultRootRule();
2044           break;
2045         default :
2046
2047           // No default rules for processing instructions and the like.
2048           return false;
2049         }
2050       }
2051     }
2052
2053     // If we are processing the default text rule, then just clone 
2054     // the value directly to the result tree.
2055     try
2056     {
2057       pushElemTemplateElement(template);
2058       m_xcontext.pushCurrentNode(child);
2059       pushPairCurrentMatched(template, child);
2060       
2061       // Fix copy copy29 test.
2062       if (!isApplyImports) {
2063           DTMIterator cnl = new org.apache.xpath.NodeSetDTM(child, m_xcontext.getDTMManager());
2064           m_xcontext.pushContextNodeList(cnl);
2065       }
2066
2067       if (isDefaultTextRule)
2068       {
2069         switch (nodeType)
2070         {
2071         case DTM.CDATA_SECTION_NODE :
2072         case DTM.TEXT_NODE :
2073           ClonerToResultTree.cloneToResultTree(child, nodeType, 
2074                                         dtm, getResultTreeHandler(), false);
2075           break;
2076         case DTM.ATTRIBUTE_NODE :
2077           dtm.dispatchCharactersEvents(child, getResultTreeHandler(), false);
2078           break;
2079         }
2080       }
2081       else
2082       {
2083
2084         // And execute the child templates.
2085         // 9/11/00: If template has been compiled, hand off to it
2086         // since much (most? all?) of the processing has been inlined.
2087         // (It would be nice if there was a single entry point that
2088         // worked for both... but the interpretive system works by
2089         // having the Tranformer execute the children, while the
2090         // compiled obviously has to run its own code. It's
2091         // also unclear that "execute" is really the right name for
2092         // that entry point.)
2093         m_xcontext.setSAXLocator(template);
2094         // m_xcontext.getVarStack().link();
2095         m_xcontext.getVarStack().link(template.m_frameSize);
2096         executeChildTemplates(template, true);
2097       }
2098     }
2099     catch (org.xml.sax.SAXException se)
2100     {
2101       throw new TransformerException(se);
2102     }
2103     finally
2104     {
2105       if (!isDefaultTextRule)
2106         m_xcontext.getVarStack().unlink();
2107       m_xcontext.popCurrentNode();
2108       if (!isApplyImports) {
2109           m_xcontext.popContextNodeList();
2110       }
2111       popCurrentMatched();
2112       
2113       popElemTemplateElement();
2114     }
2115
2116     return true;
2117   }
2118   
2119   
2120   /**
2121    * Execute each of the children of a template element.  This method
2122    * is only for extension use.
2123    *
2124    * @param elem The ElemTemplateElement that contains the children
2125    * that should execute.
2126    * NEEDSDOC @param context
2127    * @param mode The current mode.
2128    * @param handler The ContentHandler to where the result events
2129    * should be fed.
2130    *
2131    * @throws TransformerException
2132    * @xsl.usage advanced
2133    */
2134   public void executeChildTemplates(
2135           ElemTemplateElement elem, org.w3c.dom.Node context, QName mode, ContentHandler handler)
2136             throws TransformerException
2137   {
2138
2139     XPathContext xctxt = m_xcontext;
2140
2141     try
2142     {
2143       if(null != mode)
2144         pushMode(mode);
2145       xctxt.pushCurrentNode(xctxt.getDTMHandleFromNode(context));
2146       executeChildTemplates(elem, handler);
2147     }
2148     finally
2149     {
2150       xctxt.popCurrentNode();
2151       
2152       // I'm not sure where or why this was here.  It is clearly in 
2153       // error though, without a corresponding pushMode().
2154       if (null != mode)
2155         popMode();
2156     }
2157   }
2158
2159   /**
2160    * Execute each of the children of a template element.
2161    *
2162    * @param elem The ElemTemplateElement that contains the children
2163    * that should execute.
2164    * @param shouldAddAttrs true if xsl:attributes should be executed.
2165    *
2166    * @throws TransformerException
2167    * @xsl.usage advanced
2168    */
2169   public void executeChildTemplates(
2170           ElemTemplateElement elem, boolean shouldAddAttrs)
2171             throws TransformerException
2172   {
2173
2174     // Does this element have any children?
2175     ElemTemplateElement t = elem.getFirstChildElem();
2176
2177     if (null == t)
2178       return;      
2179     
2180     if(elem.hasTextLitOnly() && m_optimizer)
2181     {      
2182       char[] chars = ((ElemTextLiteral)t).getChars();
2183       try
2184       {
2185         // Have to push stuff on for tooling...
2186         this.pushElemTemplateElement(t);
2187         m_serializationHandler.characters(chars, 0, chars.length);
2188       }
2189       catch(SAXException se)
2190       {
2191         throw new TransformerException(se);
2192       }
2193       finally
2194       {
2195         this.popElemTemplateElement();
2196       }
2197       return;
2198     }
2199
2200 //    // Check for infinite loops if we have to.
2201 //    boolean check = (m_stackGuard.m_recursionLimit > -1);
2202 //
2203 //    if (check)
2204 //      getStackGuard().push(elem, xctxt.getCurrentNode());
2205
2206     XPathContext xctxt = m_xcontext;
2207     xctxt.pushSAXLocatorNull();
2208     int currentTemplateElementsTop = m_currentTemplateElements.size();
2209     m_currentTemplateElements.push(null);
2210
2211     try
2212     {
2213       // Loop through the children of the template, calling execute on 
2214       // each of them.
2215       for (; t != null; t = t.getNextSiblingElem())
2216       {
2217         if (!shouldAddAttrs
2218                 && t.getXSLToken() == Constants.ELEMNAME_ATTRIBUTE)
2219           continue;
2220
2221         xctxt.setSAXLocator(t);
2222         m_currentTemplateElements.setElementAt(t,currentTemplateElementsTop);
2223         t.execute(this);
2224       }
2225     }
2226     catch(RuntimeException re)
2227     {
2228         TransformerException te = new TransformerException(re);
2229         te.setLocator(t);
2230         throw te;
2231     }
2232     finally
2233     {
2234       m_currentTemplateElements.pop();
2235       xctxt.popSAXLocator();
2236     }
2237
2238     // Check for infinite loops if we have to
2239 //    if (check)
2240 //      getStackGuard().pop();
2241   }
2242     /**
2243       * Execute each of the children of a template element.
2244       *
2245       * @param elem The ElemTemplateElement that contains the children
2246       * that should execute.
2247       * @param handler The ContentHandler to where the result events
2248       * should be fed.
2249       *
2250       * @throws TransformerException
2251       * @xsl.usage advanced
2252       */
2253      public void executeChildTemplates(
2254              ElemTemplateElement elem, ContentHandler handler)
2255                throws TransformerException
2256      {
2257
2258        SerializationHandler xoh = this.getSerializationHandler();
2259
2260        // These may well not be the same!  In this case when calling
2261        // the Redirect extension, it has already set the ContentHandler
2262        // in the Transformer.
2263        SerializationHandler savedHandler = xoh;
2264
2265        try
2266        {
2267          xoh.flushPending();
2268
2269          // %REVIEW% Make sure current node is being pushed.
2270          LexicalHandler lex = null;
2271          if (handler instanceof LexicalHandler) {
2272             lex = (LexicalHandler) handler;
2273          }
2274          m_serializationHandler = new ToXMLSAXHandler(handler, lex, savedHandler.getEncoding());
2275          m_serializationHandler.setTransformer(this);
2276          executeChildTemplates(elem, true);
2277        }
2278        catch (TransformerException e)
2279        {
2280          throw e;
2281        }
2282        catch (SAXException se) {
2283          throw new TransformerException(se);
2284        }
2285        finally
2286        {
2287          m_serializationHandler = savedHandler;
2288     }
2289   }
2290
2291   /**
2292    * Get the keys for the xsl:sort elements.
2293    * Note: Should this go into ElemForEach?
2294    *
2295    * @param foreach Valid ElemForEach element, not null.
2296    * @param sourceNodeContext The current node context in the source tree,
2297    * needed to evaluate the Attribute Value Templates.
2298    *
2299    * @return A Vector of NodeSortKeys, or null.
2300    *
2301    * @throws TransformerException
2302    * @xsl.usage advanced
2303    */
2304   public Vector processSortKeys(ElemForEach foreach, int sourceNodeContext)
2305           throws TransformerException
2306   {
2307
2308     Vector keys = null;
2309     XPathContext xctxt = m_xcontext;
2310     int nElems = foreach.getSortElemCount();
2311
2312     if (nElems > 0)
2313       keys = new Vector();
2314
2315     // March backwards, collecting the sort keys.
2316     for (int i = 0; i < nElems; i++)
2317     {
2318       ElemSort sort = foreach.getSortElem(i);
2319       
2320       String langString =
2321         (null != sort.getLang())
2322         ? sort.getLang().evaluate(xctxt, sourceNodeContext, foreach) : null;
2323       String dataTypeString = sort.getDataType().evaluate(xctxt,
2324                                 sourceNodeContext, foreach);
2325
2326       if (dataTypeString.indexOf(":") >= 0)
2327         System.out.println(
2328           "TODO: Need to write the hooks for QNAME sort data type");
2329       else if (!(dataTypeString.equalsIgnoreCase(Constants.ATTRVAL_DATATYPE_TEXT))
2330                &&!(dataTypeString.equalsIgnoreCase(
2331                  Constants.ATTRVAL_DATATYPE_NUMBER)))
2332         foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2333                       new Object[]{ Constants.ATTRNAME_DATATYPE,
2334                                     dataTypeString });
2335
2336       boolean treatAsNumbers =
2337         ((null != dataTypeString) && dataTypeString.equals(
2338         Constants.ATTRVAL_DATATYPE_NUMBER)) ? true : false;
2339       String orderString = sort.getOrder().evaluate(xctxt, sourceNodeContext,
2340                              foreach);
2341
2342       if (!(orderString.equalsIgnoreCase(Constants.ATTRVAL_ORDER_ASCENDING))
2343               &&!(orderString.equalsIgnoreCase(
2344                 Constants.ATTRVAL_ORDER_DESCENDING)))
2345         foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2346                       new Object[]{ Constants.ATTRNAME_ORDER,
2347                                     orderString });
2348
2349       boolean descending =
2350         ((null != orderString) && orderString.equals(
2351         Constants.ATTRVAL_ORDER_DESCENDING)) ? true : false;
2352       AVT caseOrder = sort.getCaseOrder();
2353       boolean caseOrderUpper;
2354
2355       if (null != caseOrder)
2356       {
2357         String caseOrderString = caseOrder.evaluate(xctxt, sourceNodeContext,
2358                                                     foreach);
2359
2360         if (!(caseOrderString.equalsIgnoreCase(Constants.ATTRVAL_CASEORDER_UPPER))
2361                 &&!(caseOrderString.equalsIgnoreCase(
2362                   Constants.ATTRVAL_CASEORDER_LOWER)))
2363           foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2364                         new Object[]{ Constants.ATTRNAME_CASEORDER,
2365                                       caseOrderString });
2366
2367         caseOrderUpper =
2368           ((null != caseOrderString) && caseOrderString.equals(
2369           Constants.ATTRVAL_CASEORDER_UPPER)) ? true : false;
2370       }
2371       else
2372       {
2373         caseOrderUpper = false;
2374       }
2375
2376       keys.addElement(new NodeSortKey(this, sort.getSelect(), treatAsNumbers,
2377                                       descending, langString, caseOrderUpper,
2378                                       foreach));
2379      }
2380
2381     return keys;
2382   }
2383
2384   //==========================================================
2385   // SECTION: TransformState implementation
2386   //==========================================================
2387   
2388   /**
2389    * Get the count of how many elements are 
2390    * active.
2391    * @return The number of active elements on 
2392    * the currentTemplateElements stack.
2393    */
2394   public int getCurrentTemplateElementsCount()
2395   {
2396         return m_currentTemplateElements.size();
2397   }
2398   
2399   
2400   /**
2401    * Get the count of how many elements are 
2402    * active.
2403    * @return The number of active elements on 
2404    * the currentTemplateElements stack.
2405    */
2406   public ObjectStack getCurrentTemplateElements()
2407   {
2408         return m_currentTemplateElements;
2409   }
2410
2411   /**
2412    * Push the current template element.
2413    *
2414    * @param elem The current ElemTemplateElement (may be null, and then
2415    * set via setCurrentElement).
2416    */
2417   public void pushElemTemplateElement(ElemTemplateElement elem)
2418   {
2419     m_currentTemplateElements.push(elem);
2420   }
2421
2422   /**
2423    * Pop the current template element.
2424    */
2425   public void popElemTemplateElement()
2426   {
2427     m_currentTemplateElements.pop();
2428   }
2429
2430   /**
2431    * Set the top of the current template elements
2432    * stack.
2433    *
2434    * @param e The current ElemTemplateElement about to
2435    * be executed.
2436    */
2437   public void setCurrentElement(ElemTemplateElement e)
2438   {
2439     m_currentTemplateElements.setTop(e);
2440   }
2441
2442   /**
2443    * Retrieves the current ElemTemplateElement that is
2444    * being executed.
2445    *
2446    * @return The current ElemTemplateElement that is executing,
2447    * should not normally be null.
2448    */
2449   public ElemTemplateElement getCurrentElement()
2450   {
2451     return (m_currentTemplateElements.size() > 0) ? 
2452         (ElemTemplateElement) m_currentTemplateElements.peek() : null;
2453   }
2454
2455   /**
2456    * This method retrieves the current context node
2457    * in the source tree.
2458    *
2459    * @return The current context node (should never be null?).
2460    */
2461   public int getCurrentNode()
2462   {
2463     return m_xcontext.getCurrentNode();
2464   }
2465   
2466   /**
2467    * This method retrieves the xsl:template
2468    * that is in effect, which may be a matched template
2469    * or a named template.
2470    *
2471    * <p>Please note that the ElemTemplate returned may
2472    * be a default template, and thus may not have a template
2473    * defined in the stylesheet.</p>
2474    *
2475    * @return The current xsl:template, should not be null.
2476    */
2477   public ElemTemplate getCurrentTemplate()
2478   {
2479
2480     ElemTemplateElement elem = getCurrentElement();
2481
2482     while ((null != elem)
2483            && (elem.getXSLToken() != Constants.ELEMNAME_TEMPLATE))
2484     {
2485       elem = elem.getParentElem();
2486     }
2487
2488     return (ElemTemplate) elem;
2489   }
2490
2491   /**
2492    * Push both the current xsl:template or xsl:for-each onto the
2493    * stack, along with the child node that was matched.
2494    * (Note: should this only be used for xsl:templates?? -sb)
2495    *
2496    * @param template xsl:template or xsl:for-each.
2497    * @param child The child that was matched.
2498    */
2499   public void pushPairCurrentMatched(ElemTemplateElement template, int child)
2500   {
2501     m_currentMatchTemplates.push(template);
2502     m_currentMatchedNodes.push(child);
2503   }
2504
2505   /**
2506    * Pop the elements that were pushed via pushPairCurrentMatched.
2507    */
2508   public void popCurrentMatched()
2509   {
2510     m_currentMatchTemplates.pop();
2511     m_currentMatchedNodes.pop();
2512   }
2513
2514   /**
2515    * This method retrieves the xsl:template
2516    * that was matched.  Note that this may not be
2517    * the same thing as the current template (which
2518    * may be from getCurrentElement()), since a named
2519    * template may be in effect.
2520    *
2521    * @return The pushed template that was pushed via pushPairCurrentMatched.
2522    */
2523   public ElemTemplate getMatchedTemplate()
2524   {
2525     return (ElemTemplate) m_currentMatchTemplates.peek();
2526   }
2527
2528   /**
2529    * Retrieves the node in the source tree that matched
2530    * the template obtained via getMatchedTemplate().
2531    *
2532    * @return The matched node that corresponds to the
2533    * match attribute of the current xsl:template.
2534    */
2535   public int getMatchedNode()
2536   {
2537     return m_currentMatchedNodes.peepTail();
2538   }
2539
2540   /**
2541    * Get the current context node list.
2542    *
2543    * @return A reset clone of the context node list.
2544    */
2545   public DTMIterator getContextNodeList()
2546   {
2547
2548     try
2549     {
2550       DTMIterator cnl = m_xcontext.getContextNodeList();
2551
2552       return (cnl == null) ? null : (DTMIterator) cnl.cloneWithReset();
2553     }
2554     catch (CloneNotSupportedException cnse)
2555     {
2556
2557       // should never happen.
2558       return null;
2559     }
2560   }
2561
2562   /**
2563    * Get the TrAX Transformer object in effect.
2564    *
2565    * @return This object.
2566    */
2567   public Transformer getTransformer()
2568   {
2569     return this;
2570   }
2571
2572   //==========================================================
2573   // SECTION: Accessor Functions
2574   //==========================================================
2575
2576   /**
2577    * Set the stylesheet for this processor.  If this is set, then the
2578    * process calls that take only the input .xml will use
2579    * this instead of looking for a stylesheet PI.  Also,
2580    * setting the stylesheet is needed if you are going
2581    * to use the processor as a SAX ContentHandler.
2582    *
2583    * @param stylesheetRoot A non-null StylesheetRoot object,
2584    * or null if you wish to clear the stylesheet reference.
2585    */
2586   public void setStylesheet(StylesheetRoot stylesheetRoot)
2587   {
2588     m_stylesheetRoot = stylesheetRoot;
2589   }
2590
2591   /**
2592    * Get the current stylesheet for this processor.
2593    *
2594    * @return The stylesheet that is associated with this
2595    * transformer.
2596    */
2597   public final StylesheetRoot getStylesheet()
2598   {
2599     return m_stylesheetRoot;
2600   }
2601
2602   /**
2603    * Get quietConflictWarnings property. If the quietConflictWarnings
2604    * property is set to true, warnings about pattern conflicts won't be
2605    * printed to the diagnostics stream.
2606    *
2607    * @return True if this transformer should not report
2608    * template match conflicts.
2609    */
2610   public boolean getQuietConflictWarnings()
2611   {
2612     return m_quietConflictWarnings;
2613   }
2614
2615   /**
2616    * Set the execution context for XPath.
2617    *
2618    * @param xcontext A non-null reference to the XPathContext
2619    * associated with this transformer.
2620    * @xsl.usage internal
2621    */
2622   public void setXPathContext(XPathContext xcontext)
2623   {
2624     m_xcontext = xcontext;
2625   }
2626
2627   /**
2628    * Get the XPath context associated with this transformer.
2629    *
2630    * @return The XPathContext reference, never null.
2631    */
2632   public final XPathContext getXPathContext()
2633   {
2634     return m_xcontext;
2635   }
2636
2637   /**
2638    * Get the SerializationHandler object.
2639    *
2640    * @return The current SerializationHandler, which may not
2641    * be the main result tree manager.
2642    */
2643   public SerializationHandler getResultTreeHandler()
2644   {
2645     return m_serializationHandler;
2646   }
2647
2648   /**
2649    * Get the SerializationHandler object.
2650    *
2651    * @return The current SerializationHandler, which may not
2652    * be the main result tree manager.
2653    */
2654   public SerializationHandler getSerializationHandler()
2655   {
2656     return m_serializationHandler;
2657   }
2658   
2659   /**
2660    * Get the KeyManager object.
2661    *
2662    * @return A reference to the KeyManager object, which should
2663    * never be null.
2664    */
2665   public KeyManager getKeyManager()
2666   {
2667     return m_keyManager;
2668   }
2669
2670   /**
2671    * Check to see if this is a recursive attribute definition.
2672    *
2673    * @param attrSet A non-null ElemAttributeSet reference.
2674    *
2675    * @return true if the attribute set is recursive.
2676    */
2677   public boolean isRecursiveAttrSet(ElemAttributeSet attrSet)
2678   {
2679
2680     if (null == m_attrSetStack)
2681     {
2682       m_attrSetStack = new Stack();
2683     }
2684
2685     if (!m_attrSetStack.empty())
2686     {
2687       int loc = m_attrSetStack.search(attrSet);
2688
2689       if (loc > -1)
2690       {
2691         return true;
2692       }
2693     }
2694
2695     return false;
2696   }
2697
2698   /**
2699    * Push an executing attribute set, so we can check for
2700    * recursive attribute definitions.
2701    *
2702    * @param attrSet A non-null ElemAttributeSet reference.
2703    */
2704   public void pushElemAttributeSet(ElemAttributeSet attrSet)
2705   {
2706     m_attrSetStack.push(attrSet);
2707   }
2708
2709   /**
2710    * Pop the current executing attribute set.
2711    */
2712   public void popElemAttributeSet()
2713   {
2714     m_attrSetStack.pop();
2715   }
2716
2717   /**
2718    * Get the table of counters, for optimized xsl:number support.
2719    *
2720    * @return The CountersTable, never null.
2721    */
2722   public CountersTable getCountersTable()
2723   {
2724
2725     if (null == m_countersTable)
2726       m_countersTable = new CountersTable();
2727
2728     return m_countersTable;
2729   }
2730
2731   /**
2732    * Tell if the current template rule is null, i.e. if we are
2733    * directly within an apply-templates.  Used for xsl:apply-imports.
2734    *
2735    * @return True if the current template rule is null.
2736    */
2737   public boolean currentTemplateRuleIsNull()
2738   {
2739     return ((!m_currentTemplateRuleIsNull.isEmpty())
2740             && (m_currentTemplateRuleIsNull.peek() == true));
2741   }
2742
2743   /**
2744    * Push true if the current template rule is null, false
2745    * otherwise.
2746    *
2747    * @param b True if the we are executing an xsl:for-each
2748    * (or xsl:call-template?).
2749    */
2750   public void pushCurrentTemplateRuleIsNull(boolean b)
2751   {
2752     m_currentTemplateRuleIsNull.push(b);
2753   }
2754
2755   /**
2756    * Push true if the current template rule is null, false
2757    * otherwise.
2758    */
2759   public void popCurrentTemplateRuleIsNull()
2760   {
2761     m_currentTemplateRuleIsNull.pop();
2762   }
2763
2764   /**
2765    * Push a funcion result for the currently active EXSLT
2766    * <code>func:function</code>.
2767    * 
2768    * @param val the result of executing an EXSLT
2769    * <code>func:result</code> instruction for the current
2770    * <code>func:function</code>.
2771    */
2772   public void pushCurrentFuncResult(Object val) {
2773     m_currentFuncResult.push(val);
2774   }
2775
2776   /**
2777    * Pops the result of the currently active EXSLT <code>func:function</code>.
2778    * 
2779    * @return the value of the <code>func:function</code>
2780    */
2781   public Object popCurrentFuncResult() {
2782     return m_currentFuncResult.pop();
2783   }
2784
2785   /**
2786    * Determines whether an EXSLT <code>func:result</code> instruction has been
2787    * executed for the currently active EXSLT <code>func:function</code>.
2788    * 
2789    * @return <code>true</code> if and only if a <code>func:result</code>
2790    * instruction has been executed
2791    */
2792   public boolean currentFuncResultSeen() {
2793     return !m_currentFuncResult.empty()
2794                && m_currentFuncResult.peek() != null;
2795   }
2796
2797   /**
2798    * Return the message manager.
2799    *
2800    * @return The message manager, never null.
2801    */
2802   public MsgMgr getMsgMgr()
2803   {
2804
2805     if (null == m_msgMgr)
2806       m_msgMgr = new MsgMgr(this);
2807
2808     return m_msgMgr;
2809   }
2810
2811   /**
2812    * Set the error event listener.
2813    *
2814    * @param listener The new error listener.
2815    * @throws IllegalArgumentException if
2816    */
2817   public void setErrorListener(ErrorListener listener)
2818           throws IllegalArgumentException
2819   {
2820
2821     synchronized (m_reentryGuard)
2822     {
2823       if (listener == null)
2824         throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler");
2825
2826       m_errorHandler = listener;
2827     }
2828   }
2829
2830   /**
2831    * Get the current error event handler.
2832    *
2833    * @return The current error handler, which should never be null.
2834    */
2835   public ErrorListener getErrorListener()
2836   {
2837     return m_errorHandler;
2838   }
2839
2840   /**
2841    * Look up the value of a feature.
2842    *
2843    * <p>The feature name is any fully-qualified URI.  It is
2844    * possible for an TransformerFactory to recognize a feature name but
2845    * to be unable to return its value; this is especially true
2846    * in the case of an adapter for a SAX1 Parser, which has
2847    * no way of knowing whether the underlying parser is
2848    * validating, for example.</p>
2849    *
2850    * <h3>Open issues:</h3>
2851    * <dl>
2852    *    <dt><h4>Should getFeature be changed to hasFeature?</h4></dt>
2853    *    <dd>Keith Visco writes: Should getFeature be changed to hasFeature?
2854    *        It returns a boolean which indicated whether the "state"
2855    *        of feature is "true or false". I assume this means whether
2856    *        or not a feature is supported? I know SAX is using "getFeature",
2857    *        but to me "hasFeature" is cleaner.</dd>
2858    * </dl>
2859    *
2860    * @param name The feature name, which is a fully-qualified
2861    *        URI.
2862    * @return The current state of the feature (true or false).
2863    * @throws org.xml.sax.SAXNotRecognizedException When the
2864    *            TransformerFactory does not recognize the feature name.
2865    * @throws org.xml.sax.SAXNotSupportedException When the
2866    *            TransformerFactory recognizes the feature name but
2867    *            cannot determine its value at this time.
2868    *
2869    * @throws SAXNotRecognizedException
2870    * @throws SAXNotSupportedException
2871    */
2872   public boolean getFeature(String name)
2873           throws SAXNotRecognizedException, SAXNotSupportedException
2874   {
2875
2876     if ("http://xml.org/trax/features/sax/input".equals(name))
2877       return true;
2878     else if ("http://xml.org/trax/features/dom/input".equals(name))
2879       return true;
2880
2881     throw new SAXNotRecognizedException(name);
2882   }
2883
2884   // %TODO% Doc
2885
2886   /**
2887    * NEEDSDOC Method getMode 
2888    *
2889    *
2890    * NEEDSDOC (getMode) @return
2891    */
2892   public QName getMode()
2893   {
2894     return m_modes.isEmpty() ? null : (QName) m_modes.peek();
2895   }
2896
2897   // %TODO% Doc
2898
2899   /**
2900    * NEEDSDOC Method pushMode 
2901    *
2902    *
2903    * NEEDSDOC @param mode
2904    */
2905   public void pushMode(QName mode)
2906   {
2907     m_modes.push(mode);
2908   }
2909
2910   // %TODO% Doc
2911
2912   /**
2913    * NEEDSDOC Method popMode 
2914    *
2915    */
2916   public void popMode()
2917   {
2918     m_modes.pop();
2919   }
2920
2921   /**
2922    * Called by SourceTreeHandler to start the transformation
2923    *  in a separate thread
2924    *
2925    * NEEDSDOC @param priority
2926    */
2927   public void runTransformThread(int priority)
2928   {
2929
2930     // used in SourceTreeHandler
2931     Thread t = ThreadControllerWrapper.runThread(this, priority);
2932     this.setTransformThread(t);
2933   }
2934
2935   /**
2936    * Called by this.transform() if isParserEventsOnMain()==false.
2937    *  Similar with runTransformThread(), but no priority is set
2938    *  and setTransformThread is not set.
2939    */
2940   public void runTransformThread()
2941   {
2942     ThreadControllerWrapper.runThread(this, -1);
2943   }
2944   
2945   /**
2946    * Called by CoRoutineSAXParser. Launches the CoroutineSAXParser
2947    * in a thread, and prepares it to invoke the parser from that thread
2948    * upon request. 
2949    *  
2950    */
2951   public static void runTransformThread(Runnable runnable)
2952   {
2953     ThreadControllerWrapper.runThread(runnable, -1);
2954   }
2955
2956   /**
2957    * Used by SourceTreeHandler to wait until the transform
2958    *   completes
2959    *
2960    * @throws SAXException
2961    */
2962   public void waitTransformThread() throws SAXException
2963   {
2964
2965     // This is called to make sure the task is done.
2966     // It is possible that the thread has been reused -
2967     // but for a different transformation. ( what if we 
2968     // recycle the transformer ? Not a problem since this is
2969     // still in use. )
2970     Thread transformThread = this.getTransformThread();
2971
2972     if (null != transformThread)
2973     {
2974       try
2975       {
2976         ThreadControllerWrapper.waitThread(transformThread, this);
2977
2978         if (!this.hasTransformThreadErrorCatcher())
2979         {
2980           Exception e = this.getExceptionThrown();
2981
2982           if (null != e)
2983           {
2984             e.printStackTrace();
2985             throw new org.xml.sax.SAXException(e);
2986           }
2987         }
2988
2989         this.setTransformThread(null);
2990       }
2991       catch (InterruptedException ie){}
2992     }
2993   }
2994
2995   /**
2996    * Get the exception thrown by the secondary thread (normally
2997    * the transform thread).
2998    *
2999    * @return The thrown exception, or null if no exception was
3000    * thrown.
3001    */
3002   public Exception getExceptionThrown()
3003   {
3004     return m_exceptionThrown;
3005   }
3006
3007   /**
3008    * Set the exception thrown by the secondary thread (normally
3009    * the transform thread).
3010    *
3011    * @param e The thrown exception, or null if no exception was
3012    * thrown.
3013    */
3014   public void setExceptionThrown(Exception e)
3015   {
3016     m_exceptionThrown = e;
3017   }
3018
3019   /**
3020    * This is just a way to set the document for run().
3021    *
3022    * @param doc A non-null reference to the root of the
3023    * tree to be transformed.
3024    */
3025   public void setSourceTreeDocForThread(int doc)
3026   {
3027     m_doc = doc;
3028   }
3029
3030   /**
3031    * From a secondary thread, post the exception, so that
3032    * it can be picked up from the main thread.
3033    *
3034    * @param e The exception that was thrown.
3035    */
3036   void postExceptionFromThread(Exception e)
3037   {
3038
3039     // Commented out in response to problem reported by Nicola Brown <Nicola.Brown@jacobsrimell.com>
3040     //    if(m_reportInPostExceptionFromThread)
3041     //    {
3042     //      // Consider re-throwing the exception if this flag is set.
3043     //      e.printStackTrace();
3044     //    }
3045     // %REVIEW Need DTM equivelent?    
3046     //    if (m_inputContentHandler instanceof SourceTreeHandler)
3047     //    {
3048     //      SourceTreeHandler sth = (SourceTreeHandler) m_inputContentHandler;
3049     //
3050     //      sth.setExceptionThrown(e);
3051     //    }
3052  //   ContentHandler ch = getContentHandler();
3053
3054     //    if(ch instanceof SourceTreeHandler)
3055     //    {
3056     //      SourceTreeHandler sth = (SourceTreeHandler) ch;
3057     //      ((TransformerImpl)(sth.getTransformer())).postExceptionFromThread(e);
3058     //    }
3059     // m_isTransformDone = true; // android-removed
3060     m_exceptionThrown = e;
3061     ;  // should have already been reported via the error handler?
3062
3063     synchronized (this)
3064     {
3065
3066       // See message from me on 3/27/2001 to Patrick Moore.
3067       //      String msg = e.getMessage();
3068       // System.out.println(e.getMessage());
3069       // Is this really needed?  -sb
3070       notifyAll();
3071
3072       //      if (null == msg)
3073       //      {
3074       //
3075       //        // m_throwNewError = false;
3076       //        e.printStackTrace();
3077       //      }
3078       // throw new org.apache.xml.utils.WrappedRuntimeException(e);
3079     }
3080   }
3081
3082   /**
3083    * Run the transform thread.
3084    */
3085   public void run()
3086   {
3087
3088     m_hasBeenReset = false;
3089
3090     try
3091     {
3092
3093       // int n = ((SourceTreeHandler)getInputContentHandler()).getDTMRoot();
3094       // transformNode(n);
3095       try
3096       {
3097         // m_isTransformDone = false; // android-removed
3098         
3099         // Should no longer be needed...
3100 //          if(m_inputContentHandler instanceof TransformerHandlerImpl)
3101 //          {
3102 //            TransformerHandlerImpl thi = (TransformerHandlerImpl)m_inputContentHandler;
3103 //            thi.waitForInitialEvents();
3104 //          }
3105
3106         transformNode(m_doc);
3107         
3108       }
3109       catch (Exception e)
3110       {
3111         // e.printStackTrace();
3112
3113         // Strange that the other catch won't catch this...
3114         if (null != m_transformThread)
3115           postExceptionFromThread(e);   // Assume we're on the main thread
3116         else 
3117           throw new RuntimeException(e.getMessage());
3118       }
3119       finally
3120       {
3121         // m_isTransformDone = true; // android-removed
3122
3123         if (m_inputContentHandler instanceof TransformerHandlerImpl)
3124         {
3125           ((TransformerHandlerImpl) m_inputContentHandler).clearCoRoutine();
3126         }
3127
3128         //        synchronized (this)
3129         //        {
3130         //          notifyAll();
3131         //        }
3132       }
3133     }
3134     catch (Exception e)
3135     {
3136
3137       // e.printStackTrace();
3138       if (null != m_transformThread)
3139         postExceptionFromThread(e);
3140       else 
3141         throw new RuntimeException(e.getMessage());         // Assume we're on the main thread.
3142     }
3143   }
3144
3145   // Fragment re-execution interfaces for a tool.
3146
3147   /**
3148    * Test whether whitespace-only text nodes are visible in the logical
3149    * view of <code>DTM</code>. Normally, this function
3150    * will be called by the implementation of <code>DTM</code>;
3151    * it is not normally called directly from
3152    * user code.
3153    *
3154    * @param elementHandle int Handle of the element.
3155    * @return one of NOTSTRIP, STRIP, or INHERIT.
3156    */
3157   public short getShouldStripSpace(int elementHandle, DTM dtm)
3158   {
3159
3160     try
3161     {
3162       org.apache.xalan.templates.WhiteSpaceInfo info =
3163         m_stylesheetRoot.getWhiteSpaceInfo(m_xcontext, elementHandle, dtm);
3164
3165       if (null == info)
3166       {
3167         return DTMWSFilter.INHERIT;
3168       }
3169       else
3170       {
3171
3172         // System.out.println("getShouldStripSpace: "+info.getShouldStripSpace());
3173         return info.getShouldStripSpace()
3174                ? DTMWSFilter.STRIP : DTMWSFilter.NOTSTRIP;
3175       }
3176     }
3177     catch (TransformerException se)
3178     {
3179       return DTMWSFilter.INHERIT;
3180     }
3181   }
3182   /**
3183    * Initializer method.
3184    *
3185    * @param transformer non-null transformer instance
3186    * @param realHandler Content Handler instance
3187    */
3188    public void init(ToXMLSAXHandler h,Transformer transformer, ContentHandler realHandler)
3189    {
3190       h.setTransformer(transformer);
3191       h.setContentHandler(realHandler);
3192    }
3193       
3194    public void setSerializationHandler(SerializationHandler xoh)
3195    {
3196       m_serializationHandler = xoh;
3197    }
3198    
3199    
3200      
3201         /**
3202          * Fire off characters, cdate events.
3203          * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, char[], int, int)
3204          */
3205         public void fireGenerateEvent(
3206                 int eventType,
3207                 char[] ch,
3208                 int start,
3209                 int length) {
3210         }
3211
3212         /**
3213          * Fire off startElement, endElement events.
3214          * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String, Attributes)
3215          */
3216         public void fireGenerateEvent(
3217                 int eventType,
3218                 String name,
3219                 Attributes atts) {
3220         }
3221
3222         /**
3223          * Fire off processingInstruction events.
3224          */
3225         public void fireGenerateEvent(int eventType, String name, String data) {
3226         }
3227
3228         /**
3229          * Fire off comment and entity ref events.
3230          * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String)
3231          */
3232         public void fireGenerateEvent(int eventType, String data) {
3233         }
3234
3235         /**
3236          * Fire off startDocument, endDocument events.
3237          * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int)
3238          */
3239         public void fireGenerateEvent(int eventType) {
3240         }
3241
3242     /**
3243      * @see org.apache.xml.serializer.SerializerTrace#hasTraceListeners()
3244      */
3245     public boolean hasTraceListeners() {
3246         return false;
3247     }
3248
3249     /**
3250      * @return Incremental flag
3251      */
3252     public boolean getIncremental() {
3253         return m_incremental;
3254     }
3255
3256     /**
3257      * @return Optimization flag
3258      */
3259     public boolean getOptimize() {
3260         return m_optimizer;
3261     }
3262
3263     /**
3264      * @return Source location flag
3265      */
3266     public boolean getSource_location() {
3267         return m_source_location;
3268     }
3269
3270 }  // end TransformerImpl class
3271