1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: TransformerImpl.java 475979 2006-11-16 23:32:48Z minchau $
20  */
21 package org.apache.xalan.transformer;
22 
23 import java.io.IOException;
24 import java.io.StringWriter;
25 import java.util.Enumeration;
26 import java.util.Properties;
27 import java.util.Stack;
28 import java.util.StringTokenizer;
29 import java.util.Vector;
30 
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34 import javax.xml.transform.ErrorListener;
35 import javax.xml.transform.OutputKeys;
36 import javax.xml.transform.Result;
37 import javax.xml.transform.Source;
38 import javax.xml.transform.SourceLocator;
39 import javax.xml.transform.Transformer;
40 import javax.xml.transform.TransformerException;
41 import javax.xml.transform.URIResolver;
42 import javax.xml.transform.dom.DOMResult;
43 import javax.xml.transform.dom.DOMSource;
44 import javax.xml.transform.sax.SAXResult;
45 import javax.xml.transform.sax.SAXSource;
46 import javax.xml.transform.stream.StreamResult;
47 import javax.xml.transform.stream.StreamSource;
48 
49 import org.apache.xalan.extensions.ExtensionsTable;
50 import org.apache.xalan.res.XSLMessages;
51 import org.apache.xalan.res.XSLTErrorResources;
52 import org.apache.xml.serializer.Method;
53 import org.apache.xml.serializer.Serializer;
54 import org.apache.xml.serializer.SerializerFactory;
55 import org.apache.xalan.templates.AVT;
56 import org.apache.xalan.templates.Constants;
57 import org.apache.xalan.templates.ElemAttributeSet;
58 import org.apache.xalan.templates.ElemForEach;
59 import org.apache.xalan.templates.ElemSort;
60 import org.apache.xalan.templates.ElemTemplate;
61 import org.apache.xalan.templates.ElemTemplateElement;
62 import org.apache.xalan.templates.ElemTextLiteral;
63 import org.apache.xalan.templates.ElemVariable;
64 import org.apache.xalan.templates.OutputProperties;
65 import org.apache.xalan.templates.Stylesheet;
66 import org.apache.xalan.templates.StylesheetComposed;
67 import org.apache.xalan.templates.StylesheetRoot;
68 import org.apache.xalan.templates.XUnresolvedVariable;
69 import org.apache.xml.dtm.DTM;
70 import org.apache.xml.dtm.DTMIterator;
71 import org.apache.xml.dtm.DTMManager;
72 import org.apache.xml.dtm.DTMWSFilter;
73 import org.apache.xml.serializer.ToSAXHandler;
74 import org.apache.xml.serializer.ToTextStream;
75 import org.apache.xml.serializer.ToXMLSAXHandler;
76 import org.apache.xml.serializer.SerializationHandler;
77 import org.apache.xml.utils.BoolStack;
78 import org.apache.xml.utils.DOMBuilder;
79 import org.apache.xml.utils.NodeVector;
80 import org.apache.xml.utils.ObjectPool;
81 import org.apache.xml.utils.ObjectStack;
82 import org.apache.xml.utils.QName;
83 import org.apache.xml.utils.SAXSourceLocator;
84 import org.apache.xml.utils.ThreadControllerWrapper;
85 import org.apache.xpath.Arg;
86 import org.apache.xpath.ExtensionsProvider;
87 import org.apache.xpath.VariableStack;
88 import org.apache.xpath.XPathContext;
89 import org.apache.xpath.functions.FuncExtFunction;
90 import org.apache.xpath.objects.XObject;
91 import org.xml.sax.Attributes;
92 import org.xml.sax.ContentHandler;
93 import org.xml.sax.SAXException;
94 import org.xml.sax.SAXNotRecognizedException;
95 import org.xml.sax.SAXNotSupportedException;
96 import org.xml.sax.ext.LexicalHandler;
97 
98 /**
99  * This class implements the
100  * {@link javax.xml.transform.Transformer} interface, and is the core
101  * representation of the transformation execution.</p>
102  * @xsl.usage advanced
103  */
104 public class TransformerImpl extends Transformer
105         implements Runnable, DTMWSFilter, ExtensionsProvider, org.apache.xml.serializer.SerializerTrace
106 {
107 
108   // Synch object to gaurd against setting values from the TrAX interface
109   // or reentry while the transform is going on.
110 
111   /** NEEDSDOC Field m_reentryGuard          */
112   private Boolean m_reentryGuard = new Boolean(true);
113 
114   /**
115    * This is null unless we own the stream.
116    */
117   private java.io.FileOutputStream m_outputStream = null;
118 
119   /** The thread that the transformer is running on. */
120   private Thread m_transformThread;
121 
122   /** The base URL of the source tree. */
123   private String m_urlOfSource = null;
124 
125   /** The Result object at the start of the transform, if any. */
126   private Result m_outputTarget = null;
127 
128   /**
129    * The output format object set by the user.  May be null.
130    */
131   private OutputProperties m_outputFormat;
132 
133 
134   /**
135    * The content handler for the source input tree.
136    */
137   ContentHandler m_inputContentHandler;
138 
139   /**
140    * The content handler for the result tree.
141    */
142   private ContentHandler m_outputContentHandler = null;
143 
144   //  /*
145   //   * Use member variable to store param variables as they're
146   //   * being created, use member variable so we don't
147   //   * have to create a new vector every time.
148   //   */
149   //  private Vector m_newVars = new Vector();
150 
151   /**
152    * A pool of ResultTreeHandlers, for serialization of a subtree to text.
153    *  Please note that each of these also holds onto a Text Serializer.
154    */
155   private ObjectPool m_textResultHandlerObjectPool =
156     new ObjectPool(ToTextStream.class);
157 
158   /**
159    * Related to m_textResultHandlerObjectPool, this is a pool of
160    * StringWriters, which are passed to the Text Serializers.
161    * (I'm not sure if this is really needed any more.  -sb)
162    */
163   private ObjectPool m_stringWriterObjectPool =
164     new ObjectPool(StringWriter.class);
165 
166   /**
167    * A static text format object, which can be used over and
168    * over to create the text serializers.
169    */
170   private OutputProperties m_textformat = new OutputProperties(Method.TEXT);
171 
172   // Commenteded out in response to problem reported by
173   // Nicola Brown <Nicola.Brown@jacobsrimell.com>
174   //  /**
175   //   * Flag to let us know if an exception should be reported inside the
176   //   * postExceptionFromThread method.  This is needed if the transform is
177   //   * being generated from SAX events, and thus there is no central place
178   //   * to report the exception from.  (An exception is usually picked up in
179   //   * the main thread from the transform thread in {@link #transform(Source source)}
180   //   * from {@link #getExceptionThrown()}. )
181   //   */
182   //  private boolean m_reportInPostExceptionFromThread = false;
183 
184   /**
185    * A node vector used as a stack to track the current
186    * ElemTemplateElement.  Needed for the
187    * org.apache.xalan.transformer.TransformState interface,
188    * so a tool can discover the calling template. Note the use of an array
189    * for this limits the recursion depth to 4K.
190    */
191   ObjectStack m_currentTemplateElements
192       = new ObjectStack(XPathContext.RECURSIONLIMIT);
193 
194   /** The top of the currentTemplateElements stack. */
195   //int m_currentTemplateElementsTop = 0;
196 
197   /**
198    * A node vector used as a stack to track the current
199    * ElemTemplate that was matched.
200    * Needed for the
201    * org.apache.xalan.transformer.TransformState interface,
202    * so a tool can discover the matched template
203    */
204   Stack m_currentMatchTemplates = new Stack();
205 
206   /**
207    * A node vector used as a stack to track the current
208    * node that was matched.
209    * Needed for the
210    * org.apache.xalan.transformer.TransformState interface,
211    * so a tool can discover the matched
212    * node.
213    */
214   NodeVector m_currentMatchedNodes = new NodeVector();
215 
216   /**
217    * The root of a linked set of stylesheets.
218    */
219   private StylesheetRoot m_stylesheetRoot = null;
220 
221   /**
222    * If this is set to true, do not warn about pattern
223    * match conflicts.
224    */
225   private boolean m_quietConflictWarnings = true;
226 
227   /**
228    * The liason to the XML parser, so the XSL processor
229    * can handle included files, and the like, and do the
230    * initial parse of the XSL document.
231    */
232   private XPathContext m_xcontext;
233 
234   /**
235    * Output handler to bottleneck SAX events.
236    */
237   private SerializationHandler m_serializationHandler;
238 
239   /** The key manager, which manages xsl:keys. */
240   private KeyManager m_keyManager = new KeyManager();
241 
242   /**
243    * Stack for the purposes of flagging infinite recursion with
244    * attribute sets.
245    */
246   Stack m_attrSetStack = null;
247 
248   /**
249    * The table of counters for xsl:number support.
250    */
251   CountersTable m_countersTable = null;
252 
253   /**
254    * Is > 0 when we're processing a for-each.
255    */
256   BoolStack m_currentTemplateRuleIsNull = new BoolStack();
257 
258   /**
259    * Keeps track of the result delivered by any EXSLT <code>func:result</code>
260    * instruction that has been executed for the currently active EXSLT
261    * <code>func:function</code>
262    */
263   ObjectStack m_currentFuncResult = new ObjectStack();
264 
265   /**
266    * The message manager, which manages error messages, warning
267    * messages, and other types of message events.
268    */
269   private MsgMgr m_msgMgr;
270 
271   /**
272    * The flag for the setting of the optimize feature;
273    * This flag should have the same value as the FEATURE_OPTIMIZE feature
274    * which is set by the TransformerFactory.setAttribut() method before a
275    * Transformer is created
276    */
277   private boolean m_optimizer = true;
278 
279   /**
280    * The flag for the setting of the incremental feature;
281    * This flag should have the same value as the FEATURE_INCREMENTAL feature
282    * which is set by the TransformerFactory.setAttribut() method before a
283    * Transformer is created
284    */
285   private boolean m_incremental = false;
286 
287   /**
288    * The flag for the setting of the source_location feature;
289    * This flag should have the same value as the FEATURE_SOURCE_LOCATION feature
290    * which is set by the TransformerFactory.setAttribut() method before a
291    * Transformer is created
292    */
293   private boolean m_source_location = false;
294 
295   /**
296    * The SAX error handler, where errors and warnings are sent.
297    */
298   private ErrorListener m_errorHandler =
299     new org.apache.xml.utils.DefaultErrorHandler(false);
300 
301   /**
302    * If the transform thread throws an exception, the exception needs to
303    * be stashed away so that the main thread can pass it on to the
304    * client.
305    */
306   private Exception m_exceptionThrown = null;
307 
308   /**
309    * This is needed for support of setSourceTreeDocForThread(Node doc),
310    * which must be called in order for the transform thread's run
311    * method to obtain the root of the source tree to be transformed.
312    */
313   private int m_doc;
314 
315   /** Flag to to tell if the tranformer needs to be reset. */
316   private boolean m_hasBeenReset = false;
317 
318   /** NEEDSDOC Field m_shouldReset          */
319   private boolean m_shouldReset = true;
320 
321   /**
322    * A stack of current template modes.
323    */
324   private Stack m_modes = new Stack();
325 
326   //==========================================================
327   // SECTION: Constructor
328   //==========================================================
329 
330   /**
331    * Construct a TransformerImpl.
332    *
333    * @param stylesheet The root of the stylesheet tree.
334    */
TransformerImpl(StylesheetRoot stylesheet)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    */
getExtensionsTable()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    */
setExtensionsTable(StylesheetRoot sroot)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 
functionAvailable(String ns, String funcName)395   public boolean functionAvailable(String ns, String funcName)
396           throws javax.xml.transform.TransformerException
397   {
398     return getExtensionsTable().functionAvailable(ns, funcName);
399   }
400 
elementAvailable(String ns, String elemName)401   public boolean elementAvailable(String ns, String elemName)
402           throws javax.xml.transform.TransformerException
403   {
404     return getExtensionsTable().elementAvailable(ns, elemName);
405   }
406 
extFunction(String ns, String funcName, Vector argVec, Object methodKey)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 
extFunction(FuncExtFunction extFunction, Vector argVec)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    */
reset()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    */
getTransformThread()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    */
setTransformThread(Thread t)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    */
hasTransformThreadErrorCatcher()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    */
transform(Source source)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    */
transform(Source source, boolean shouldRelease)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@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 
fatalError(Throwable throwable)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    */
setBaseURLOfSource(String base)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    */
getOutputProperty(String qnameString)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    */
getOutputPropertyNoDefault(String qnameString)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    */
setOutputProperty(String name, String value)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    */
setOutputProperties(Properties oformat)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    */
getOutputProperties()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      */
createSerializationHandler(Result outputTarget)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      */
createSerializationHandler( Result outputTarget, OutputProperties format)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    */
transform(Source xmlSource, Result outputTarget)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    */
transform(Source xmlSource, Result outputTarget, boolean shouldRelease)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    */
transformNode(int node, Result outputTarget)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    */
transformNode(int node)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    */
getInputContentHandler()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    */
getInputContentHandler(boolean doDocFrag)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    */
setOutputFormat(OutputProperties oformat)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    */
getOutputFormat()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    */
setParameter(String name, String namespace, Object value)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    */
setParameter(String name, Object value)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    */
replaceOrPushUserParam(QName qname, XObject xval)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    */
getParameter(String name)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    */
resetUserParameters()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    */
setParameters(Properties params)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    */
clearParameters()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    */
pushGlobalVars(int contextNode)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    */
setURIResolver(URIResolver resolver)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    */
getURIResolver()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    */
setContentHandler(ContentHandler handler)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    */
getContentHandler()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    */
transformToRTF(ElemTemplateElement templateParent)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    */
transformToGlobalRTF(ElemTemplateElement templateParent)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    */
transformToRTF(ElemTemplateElement templateParent,DTM dtmFrag)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    */
transformToString(ElemTemplateElement elem)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    */
applyTemplateToNode(ElemTemplateElement xslInstruction, ElemTemplate template, int child)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    */
executeChildTemplates( ElemTemplateElement elem, org.w3c.dom.Node context, QName mode, ContentHandler handler)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    */
executeChildTemplates( ElemTemplateElement elem, boolean shouldAddAttrs)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       */
executeChildTemplates( ElemTemplateElement elem, ContentHandler handler)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    */
processSortKeys(ElemForEach foreach, int sourceNodeContext)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    */
getCurrentTemplateElementsCount()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    */
getCurrentTemplateElements()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    */
pushElemTemplateElement(ElemTemplateElement elem)2419   public void pushElemTemplateElement(ElemTemplateElement elem)
2420   {
2421     m_currentTemplateElements.push(elem);
2422   }
2423 
2424   /**
2425    * Pop the current template element.
2426    */
popElemTemplateElement()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    */
setCurrentElement(ElemTemplateElement e)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    */
getCurrentElement()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    */
getCurrentNode()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    */
getCurrentTemplate()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    */
pushPairCurrentMatched(ElemTemplateElement template, int child)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    */
popCurrentMatched()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    */
getMatchedTemplate()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    */
getMatchedNode()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    */
getContextNodeList()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    */
getTransformer()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    */
setStylesheet(StylesheetRoot stylesheetRoot)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    */
getStylesheet()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    */
getQuietConflictWarnings()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    */
setXPathContext(XPathContext xcontext)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    */
getXPathContext()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    */
getResultTreeHandler()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    */
getSerializationHandler()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    */
getKeyManager()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    */
isRecursiveAttrSet(ElemAttributeSet attrSet)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    */
pushElemAttributeSet(ElemAttributeSet attrSet)2706   public void pushElemAttributeSet(ElemAttributeSet attrSet)
2707   {
2708     m_attrSetStack.push(attrSet);
2709   }
2710 
2711   /**
2712    * Pop the current executing attribute set.
2713    */
popElemAttributeSet()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    */
getCountersTable()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    */
currentTemplateRuleIsNull()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    */
pushCurrentTemplateRuleIsNull(boolean b)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    */
popCurrentTemplateRuleIsNull()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    */
pushCurrentFuncResult(Object val)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    */
popCurrentFuncResult()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    */
currentFuncResultSeen()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    */
getMsgMgr()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    */
setErrorListener(ErrorListener listener)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    */
getErrorListener()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    */
getFeature(String name)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    */
getMode()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    */
pushMode(QName mode)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    */
popMode()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    */
runTransformThread(int priority)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    */
runTransformThread()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    */
runTransformThread(Runnable runnable)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    */
waitTransformThread()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    */
getExceptionThrown()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    */
setExceptionThrown(Exception e)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    */
setSourceTreeDocForThread(int doc)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    */
postExceptionFromThread(Exception e)3038   void postExceptionFromThread(Exception e)
3039   {
3040 
3041     // Commented out in response to problem reported by Nicola Brown <Nicola.Brown@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    */
run()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    */
getShouldStripSpace(int elementHandle, DTM dtm)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    */
init(ToXMLSAXHandler h,Transformer transformer, ContentHandler realHandler)3190    public void init(ToXMLSAXHandler h,Transformer transformer, ContentHandler realHandler)
3191    {
3192       h.setTransformer(transformer);
3193       h.setContentHandler(realHandler);
3194    }
3195 
setSerializationHandler(SerializationHandler xoh)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 	 */
fireGenerateEvent( int eventType, char[] ch, int start, int length)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 	 */
fireGenerateEvent( int eventType, String name, Attributes atts)3218 	public void fireGenerateEvent(
3219 		int eventType,
3220 		String name,
3221 		Attributes atts) {
3222 	}
3223 
3224 	/**
3225 	 * Fire off processingInstruction events.
3226 	 */
fireGenerateEvent(int eventType, String name, String data)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 	 */
fireGenerateEvent(int eventType, String data)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 	 */
fireGenerateEvent(int eventType)3241 	public void fireGenerateEvent(int eventType) {
3242 	}
3243 
3244     /**
3245      * @see org.apache.xml.serializer.SerializerTrace#hasTraceListeners()
3246      */
hasTraceListeners()3247     public boolean hasTraceListeners() {
3248         return false;
3249     }
3250 
3251     /**
3252      * @return Incremental flag
3253      */
getIncremental()3254     public boolean getIncremental() {
3255         return m_incremental;
3256     }
3257 
3258     /**
3259      * @return Optimization flag
3260      */
getOptimize()3261     public boolean getOptimize() {
3262         return m_optimizer;
3263     }
3264 
3265     /**
3266      * @return Source location flag
3267      */
getSource_location()3268     public boolean getSource_location() {
3269         return m_source_location;
3270     }
3271 
3272 }  // end TransformerImpl class
3273 
3274