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