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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * $Id: TransformerImpl.java 475979 2006-11-16 23:32:48Z minchau $
21 package org.apache.xalan.transformer;
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;
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;
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;
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
104 public class TransformerImpl extends Transformer
105 implements Runnable, DTMWSFilter, ExtensionsProvider, org.apache.xml.serializer.SerializerTrace
108 // Synch object to gaurd against setting values from the TrAX interface
109 // or reentry while the transform is going on.
111 /** NEEDSDOC Field m_reentryGuard */
112 private Boolean m_reentryGuard = new Boolean(true);
115 * This is null unless we own the stream.
117 private java.io.FileOutputStream m_outputStream = null;
119 /** The thread that the transformer is running on. */
120 private Thread m_transformThread;
122 /** The base URL of the source tree. */
123 private String m_urlOfSource = null;
125 /** The Result object at the start of the transform, if any. */
126 private Result m_outputTarget = null;
129 * The output format object set by the user. May be null.
131 private OutputProperties m_outputFormat;
135 * The content handler for the source input tree.
137 ContentHandler m_inputContentHandler;
140 * The content handler for the result tree.
142 private ContentHandler m_outputContentHandler = null;
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.
149 // private Vector m_newVars = new Vector();
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.
155 private ObjectPool m_textResultHandlerObjectPool =
156 new ObjectPool(ToTextStream.class);
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)
163 private ObjectPool m_stringWriterObjectPool =
164 new ObjectPool(StringWriter.class);
167 * A static text format object, which can be used over and
168 * over to create the text serializers.
170 private OutputProperties m_textformat = new OutputProperties(Method.TEXT);
172 // Commenteded out in response to problem reported by
173 // Nicola Brown <Nicola.Brown@jacobsrimell.com>
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()}. )
182 // private boolean m_reportInPostExceptionFromThread = false;
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.
191 ObjectStack m_currentTemplateElements
192 = new ObjectStack(XPathContext.RECURSIONLIMIT);
194 /** The top of the currentTemplateElements stack. */
195 //int m_currentTemplateElementsTop = 0;
198 * A node vector used as a stack to track the current
199 * ElemTemplate that was matched.
201 * org.apache.xalan.transformer.TransformState interface,
202 * so a tool can discover the matched template
204 Stack m_currentMatchTemplates = new Stack();
207 * A node vector used as a stack to track the current
208 * node that was matched.
210 * org.apache.xalan.transformer.TransformState interface,
211 * so a tool can discover the matched
214 NodeVector m_currentMatchedNodes = new NodeVector();
217 * The root of a linked set of stylesheets.
219 private StylesheetRoot m_stylesheetRoot = null;
222 * If this is set to true, do not warn about pattern
225 private boolean m_quietConflictWarnings = true;
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.
232 private XPathContext m_xcontext;
235 * Output handler to bottleneck SAX events.
237 private SerializationHandler m_serializationHandler;
239 /** The key manager, which manages xsl:keys. */
240 private KeyManager m_keyManager = new KeyManager();
243 * Stack for the purposes of flagging infinite recursion with
246 Stack m_attrSetStack = null;
249 * The table of counters for xsl:number support.
251 CountersTable m_countersTable = null;
254 * Is > 0 when we're processing a for-each.
256 BoolStack m_currentTemplateRuleIsNull = new BoolStack();
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>
263 ObjectStack m_currentFuncResult = new ObjectStack();
266 * The message manager, which manages error messages, warning
267 * messages, and other types of message events.
269 private MsgMgr m_msgMgr;
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
277 private boolean m_optimizer = true;
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
285 private boolean m_incremental = false;
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
293 private boolean m_source_location = false;
296 * The SAX error handler, where errors and warnings are sent.
298 private ErrorListener m_errorHandler =
299 new org.apache.xml.utils.DefaultErrorHandler(false);
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
306 private Exception m_exceptionThrown = null;
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.
315 /** Flag to to tell if the tranformer needs to be reset. */
316 private boolean m_hasBeenReset = false;
318 /** NEEDSDOC Field m_shouldReset */
319 private boolean m_shouldReset = true;
322 * A stack of current template modes.
324 private Stack m_modes = new Stack();
326 //==========================================================
327 // SECTION: Constructor
328 //==========================================================
331 * Construct a TransformerImpl.
333 * @param stylesheet The root of the stylesheet tree.
335 public TransformerImpl(StylesheetRoot stylesheet)
336 // throws javax.xml.transform.TransformerException
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);
348 if (stylesheet.isSecureProcessing())
349 xPath.setSecureProcessing(true);
351 setXPathContext(xPath);
352 getXPathContext().setNamespaceContext(stylesheet);
355 // ================ ExtensionsTable ===================
358 * The table of ExtensionHandlers.
360 private ExtensionsTable m_extensionsTable = null;
363 * Get the extensions table object.
365 * @return The extensions table.
367 public ExtensionsTable getExtensionsTable()
369 return m_extensionsTable;
373 * If the stylesheet contains extensions, set the extensions table object.
376 * @param sroot The stylesheet.
377 * @throws javax.xml.transform.TransformerException
379 void setExtensionsTable(StylesheetRoot sroot)
380 throws javax.xml.transform.TransformerException
384 if (sroot.getExtensions() != null)
385 m_extensionsTable = new ExtensionsTable(sroot);
387 catch (javax.xml.transform.TransformerException te)
388 {te.printStackTrace();}
391 //== Implementation of the XPath ExtensionsProvider interface.
393 public boolean functionAvailable(String ns, String funcName)
394 throws javax.xml.transform.TransformerException
396 return getExtensionsTable().functionAvailable(ns, funcName);
399 public boolean elementAvailable(String ns, String elemName)
400 throws javax.xml.transform.TransformerException
402 return getExtensionsTable().elementAvailable(ns, elemName);
405 public Object extFunction(String ns, String funcName,
406 Vector argVec, Object methodKey)
407 throws javax.xml.transform.TransformerException
408 {//System.out.println("TransImpl.extFunction() " + ns + " " + funcName +" " + getExtensionsTable());
409 return getExtensionsTable().extFunction(ns, funcName,
411 getXPathContext().getExpressionContext());
414 public Object extFunction(FuncExtFunction extFunction, Vector argVec)
415 throws javax.xml.transform.TransformerException
417 return getExtensionsTable().extFunction(extFunction, argVec,
418 getXPathContext().getExpressionContext());
421 //=========================
424 * Reset the state. This needs to be called after a process() call
425 * is invoked, if the processor is to be used again.
430 if (!m_hasBeenReset && m_shouldReset)
432 m_hasBeenReset = true;
434 if (this.m_outputStream != null)
438 m_outputStream.close();
440 catch (java.io.IOException ioe){}
443 m_outputStream = null;
445 // I need to look more carefully at which of these really
446 // needs to be reset.
447 m_countersTable = null;
451 m_xcontext.getVarStack().reset();
452 resetUserParameters();
455 m_currentTemplateElements.removeAllElements();
456 m_currentMatchTemplates.removeAllElements();
457 m_currentMatchedNodes.removeAllElements();
459 m_serializationHandler = null;
460 m_outputTarget = null;
461 m_keyManager = new KeyManager();
462 m_attrSetStack = null;
463 m_countersTable = null;
464 m_currentTemplateRuleIsNull = new BoolStack();
465 // m_xmlSource = null; // android-removed
467 // m_isTransformDone = false; // android-removed
468 m_transformThread = null;
470 // m_inputContentHandler = null;
471 // For now, reset the document cache each time.
472 m_xcontext.getSourceTreeManager().reset();
475 // m_reportInPostExceptionFromThread = false;
478 // ========= Transformer Interface Implementation ==========
481 * Get the thread that the transform process is on.
483 * @return The thread that the transform process is on, or null.
484 * @xsl.usage internal
486 public Thread getTransformThread()
488 return m_transformThread;
492 * Get the thread that the transform process is on.
494 * @param t The transform thread, may be null.
495 * @xsl.usage internal
497 public void setTransformThread(Thread t)
499 m_transformThread = t;
502 /** NEEDSDOC Field m_hasTransformThreadErrorCatcher */
503 private boolean m_hasTransformThreadErrorCatcher = false;
506 * Return true if the transform was initiated from the transform method,
507 * otherwise it was probably done from a pure parse events.
509 * NEEDSDOC ($objectName$) @return
511 public boolean hasTransformThreadErrorCatcher()
513 return m_hasTransformThreadErrorCatcher;
517 * Process the source tree to SAX parse events.
518 * @param source The input for the source tree.
520 * @throws TransformerException
522 public void transform(Source source) throws TransformerException
524 transform(source, true);
528 * Process the source tree to SAX parse events.
529 * @param source The input for the source tree.
530 * @param shouldRelease Flag indicating whether to release DTMManager.
532 * @throws TransformerException
534 public void transform(Source source, boolean shouldRelease) throws TransformerException
540 // Patch for bugzilla #13863. If we don't reset the namespaceContext
541 // then we will get a NullPointerException if transformer is reused
542 // (for stylesheets that use xsl:key). Not sure if this should go
543 // here or in reset(). -is
544 if(getXPathContext().getNamespaceContext() == null){
545 getXPathContext().setNamespaceContext(getStylesheet());
547 String base = source.getSystemId();
549 // If no systemID of the source, use the base of the stylesheet.
552 base = m_stylesheetRoot.getBaseIdentifier();
555 // As a last resort, use the current user dir.
558 String currentDir = "";
560 currentDir = System.getProperty("user.dir");
562 catch (SecurityException se) {}// user.dir not accessible from applet
564 if (currentDir.startsWith(java.io.File.separator))
565 base = "file://" + currentDir;
567 base = "file:///" + currentDir;
569 base = base + java.io.File.separatorChar
570 + source.getClass().getName();
572 setBaseURLOfSource(base);
573 DTMManager mgr = m_xcontext.getDTMManager();
575 * According to JAXP1.2, new SAXSource()/StreamSource()
576 * should create an empty input tree, with a default root node.
577 * new DOMSource()creates an empty document using DocumentBuilder.
578 * newDocument(); Use DocumentBuilder.newDocument() for all 3 situations,
579 * since there is no clear spec. how to create an empty tree when
580 * both SAXSource() and StreamSource() are used.
582 if ((source instanceof StreamSource && source.getSystemId()==null &&
583 ((StreamSource)source).getInputStream()==null &&
584 ((StreamSource)source).getReader()==null)||
585 (source instanceof SAXSource &&
586 ((SAXSource)source).getInputSource()==null &&
587 ((SAXSource)source).getXMLReader()==null )||
588 (source instanceof DOMSource && ((DOMSource)source).getNode()==null)){
590 DocumentBuilderFactory builderF =
591 DocumentBuilderFactory.newInstance();
592 DocumentBuilder builder = builderF.newDocumentBuilder();
593 String systemID = source.getSystemId();
594 source = new DOMSource(builder.newDocument());
596 // Copy system ID from original, empty Source to new Source
597 if (systemID != null) {
598 source.setSystemId(systemID);
600 } catch (ParserConfigurationException e) {
604 DTM dtm = mgr.getDTM(source, false, this, true, true);
605 dtm.setDocumentBaseURI(base);
607 boolean hardDelete = true; // %REVIEW% I have to think about this. -sb
611 // NOTE: This will work because this is _NOT_ a shared DTM, and thus has
612 // only a single Document node. If it could ever be an RTF or other
613 // shared DTM, look at dtm.getDocumentRoot(nodeHandle).
614 this.transformNode(dtm.getDocument());
619 mgr.release(dtm, hardDelete);
622 // Kick off the parse. When the ContentHandler gets
623 // the startDocument event, it will call transformNode( node ).
624 // reader.parse( xmlSource );
625 // This has to be done to catch exceptions thrown from
626 // the transform thread spawned by the STree handler.
627 Exception e = getExceptionThrown();
631 if (e instanceof javax.xml.transform.TransformerException)
633 throw (javax.xml.transform.TransformerException) e;
635 else if (e instanceof org.apache.xml.utils.WrappedRuntimeException)
638 ((org.apache.xml.utils.WrappedRuntimeException) e).getException());
642 throw new javax.xml.transform.TransformerException(e);
645 else if (null != m_serializationHandler)
647 m_serializationHandler.endDocument();
650 catch (org.apache.xml.utils.WrappedRuntimeException wre)
652 Throwable throwable = wre.getException();
655 instanceof org.apache.xml.utils.WrappedRuntimeException)
658 ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException();
661 fatalError(throwable);
664 // Patch attributed to David Eisenberg <david@catcode.com>
665 catch (org.xml.sax.SAXParseException spe)
669 catch (org.xml.sax.SAXException se)
671 m_errorHandler.fatalError(new TransformerException(se));
675 m_hasTransformThreadErrorCatcher = false;
677 // This looks to be redundent to the one done in TransformNode.
682 private void fatalError(Throwable throwable) throws TransformerException
684 if (throwable instanceof org.xml.sax.SAXParseException)
685 m_errorHandler.fatalError(new TransformerException(throwable.getMessage(),new SAXSourceLocator((org.xml.sax.SAXParseException)throwable)));
687 m_errorHandler.fatalError(new TransformerException(throwable));
692 * Get the base URL of the source.
695 * NEEDSDOC @param base
696 * @return The base URL of the source tree, or null.
698 public void setBaseURLOfSource(String base)
700 m_urlOfSource = base;
704 * Get an output property that is in effect for the
705 * transformation. The property specified may be a property
706 * that was set with setOutputProperty, or it may be a
707 * property specified in the stylesheet.
709 * NEEDSDOC @param qnameString
711 * @return The string value of the output property, or null
712 * if no property was found.
714 * @throws IllegalArgumentException If the property is not supported.
716 * @see javax.xml.transform.OutputKeys
718 public String getOutputProperty(String qnameString)
719 throws IllegalArgumentException
723 OutputProperties props = getOutputFormat();
725 value = props.getProperty(qnameString);
729 if (!OutputProperties.isLegalPropertyKey(qnameString))
730 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: "
738 * Get the value of a property, without using the default properties. This
739 * can be used to test if a property has been explicitly set by the stylesheet
742 * NEEDSDOC @param qnameString
744 * @return The value of the property, or null if not found.
746 * @throws IllegalArgumentException If the property is not supported,
747 * and is not namespaced.
749 public String getOutputPropertyNoDefault(String qnameString)
750 throws IllegalArgumentException
754 OutputProperties props = getOutputFormat();
756 value = (String) props.getProperties().get(qnameString);
760 if (!OutputProperties.isLegalPropertyKey(qnameString))
761 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: "
769 * This method is used to set or override the value
770 * of the effective xsl:output attribute values
771 * specified in the stylesheet.
773 * The recognized standard output properties are:
775 * <li>cdata-section-elements
781 * <li>omit-xml-declaration
788 * tran.setOutputProperty("standalone", "yes");
791 * In the case of the cdata-section-elements property,
792 * the value should be a whitespace separated list of
793 * element names. The element name is the local name
794 * of the element, if it is in no namespace, or, the URI
795 * in braces followed immediately by the local name
796 * if the element is in that namespace. For example:
798 * tran.setOutputProperty(
799 * "cdata-section-elements",
800 * "elem1 {http://example.uri}elem2 elem3");
803 * The recognized Xalan extension elements are:
805 * <li>content-handler
810 * <li>use-url-escaping
813 * These must be in the extension namespace of
814 * "http://xml.apache.org/xalan". This is accomplished
815 * by putting the namespace URI in braces before the
816 * property name, for example:
818 * tran.setOutputProperty(
819 * "{http://xml.apache.org/xalan}line-separator" ,
823 * @param name The property name.
824 * @param value The requested value for the property.
825 * @throws IllegalArgumentException if the property name is not legal.
827 public void setOutputProperty(String name, String value)
828 throws IllegalArgumentException
831 synchronized (m_reentryGuard)
834 // Get the output format that was set by the user, otherwise get the
835 // output format from the stylesheet.
836 if (null == m_outputFormat)
839 (OutputProperties) getStylesheet().getOutputComposed().clone();
842 if (!OutputProperties.isLegalPropertyKey(name))
843 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{name})); //"output property not recognized: "
846 m_outputFormat.setProperty(name, value);
851 * Set the output properties for the transformation. These
852 * properties will override properties set in the templates
855 * <p>If argument to this function is null, any properties
856 * previously set will be removed.</p>
858 * @param oformat A set of output properties that will be
859 * used to override any of the same properties in effect
860 * for the transformation.
862 * @see javax.xml.transform.OutputKeys
863 * @see java.util.Properties
865 * @throws IllegalArgumentException if any of the argument keys are not
866 * recognized and are not namespace qualified.
868 public void setOutputProperties(Properties oformat)
869 throws IllegalArgumentException
872 synchronized (m_reentryGuard)
877 // See if an *explicit* method was set.
878 String method = (String) oformat.get(OutputKeys.METHOD);
881 m_outputFormat = new OutputProperties(method);
882 else if(m_outputFormat==null)
883 m_outputFormat = new OutputProperties();
885 m_outputFormat.copyFrom(oformat);
886 // copyFrom does not set properties that have been already set, so
887 // this must be called after, which is a bit in the reverse from
888 // what one might think.
889 m_outputFormat.copyFrom(m_stylesheetRoot.getOutputProperties());
892 // if oformat is null JAXP says that any props previously set are removed
893 // and we are to revert back to those in the templates object (i.e. Stylesheet).
894 m_outputFormat = null;
900 * Get a copy of the output properties for the transformation. These
901 * properties will override properties set in the templates
904 * <p>Note that mutation of the Properties object returned will not
905 * effect the properties that the transformation contains.</p>
907 * @return A copy of the set of output properties in effect
908 * for the next transformation.
910 * NEEDSDOC ($objectName$) @return
912 public Properties getOutputProperties()
914 return (Properties) getOutputFormat().getProperties().clone();
918 * Create a result ContentHandler from a Result object, based
919 * on the current OutputProperties.
921 * @param outputTarget Where the transform result should go,
922 * should not be null.
924 * @return A valid ContentHandler that will create the
925 * result tree when it is fed SAX events.
927 * @throws TransformerException
929 public SerializationHandler createSerializationHandler(Result outputTarget)
930 throws TransformerException
932 SerializationHandler xoh =
933 createSerializationHandler(outputTarget, getOutputFormat());
938 * Create a ContentHandler from a Result object and an OutputProperties.
940 * @param outputTarget Where the transform result should go,
941 * should not be null.
942 * @param format The OutputProperties object that will contain
943 * instructions on how to serialize the output.
945 * @return A valid ContentHandler that will create the
946 * result tree when it is fed SAX events.
948 * @throws TransformerException
950 public SerializationHandler createSerializationHandler(
951 Result outputTarget, OutputProperties format)
952 throws TransformerException
955 SerializationHandler xoh;
957 // If the Result object contains a Node, then create
958 // a ContentHandler that will add nodes to the input node.
959 org.w3c.dom.Node outputNode = null;
961 if (outputTarget instanceof DOMResult)
963 outputNode = ((DOMResult) outputTarget).getNode();
964 org.w3c.dom.Node nextSibling = ((DOMResult)outputTarget).getNextSibling();
966 org.w3c.dom.Document doc;
969 if (null != outputNode)
971 type = outputNode.getNodeType();
972 doc = (org.w3c.dom.Node.DOCUMENT_NODE == type)
973 ? (org.w3c.dom.Document) outputNode
974 : outputNode.getOwnerDocument();
978 boolean isSecureProcessing = m_stylesheetRoot.isSecureProcessing();
979 doc = org.apache.xml.utils.DOMHelper.createDocument(isSecureProcessing);
981 type = outputNode.getNodeType();
983 ((DOMResult) outputTarget).setNode(outputNode);
987 (org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE == type)
988 ? new DOMBuilder(doc, (org.w3c.dom.DocumentFragment) outputNode)
989 : new DOMBuilder(doc, outputNode);
991 if (nextSibling != null)
992 handler.setNextSibling(nextSibling);
994 String encoding = format.getProperty(OutputKeys.ENCODING);
995 xoh = new ToXMLSAXHandler(handler, (LexicalHandler)handler, encoding);
997 else if (outputTarget instanceof SAXResult)
999 ContentHandler handler = ((SAXResult) outputTarget).getHandler();
1001 if (null == handler)
1002 throw new IllegalArgumentException(
1003 "handler can not be null for a SAXResult");
1005 LexicalHandler lexHandler;
1006 if (handler instanceof LexicalHandler)
1007 lexHandler = (LexicalHandler) handler;
1011 String encoding = format.getProperty(OutputKeys.ENCODING);
1012 String method = format.getProperty(OutputKeys.METHOD);
1014 ToXMLSAXHandler toXMLSAXHandler = new ToXMLSAXHandler(handler, lexHandler, encoding);
1015 toXMLSAXHandler.setShouldOutputNSAttr(false);
1016 xoh = toXMLSAXHandler;
1019 String publicID = format.getProperty(OutputKeys.DOCTYPE_PUBLIC);
1020 String systemID = format.getProperty(OutputKeys.DOCTYPE_SYSTEM);
1021 if (systemID != null)
1022 xoh.setDoctypeSystem(systemID);
1023 if (publicID != null)
1024 xoh.setDoctypePublic(publicID);
1026 if (handler instanceof TransformerClient) {
1027 XalanTransformState state = new XalanTransformState();
1028 ((TransformerClient)handler).setTransformState(state);
1029 ((ToSAXHandler)xoh).setTransformState(state);
1035 // Otherwise, create a ContentHandler that will serialize the
1036 // result tree to either a stream or a writer.
1037 else if (outputTarget instanceof StreamResult)
1039 StreamResult sresult = (StreamResult) outputTarget;
1043 SerializationHandler serializer =
1044 (SerializationHandler) SerializerFactory.getSerializer(format.getProperties());
1046 if (null != sresult.getWriter())
1047 serializer.setWriter(sresult.getWriter());
1048 else if (null != sresult.getOutputStream())
1049 serializer.setOutputStream(sresult.getOutputStream());
1050 else if (null != sresult.getSystemId())
1052 String fileURL = sresult.getSystemId();
1054 if (fileURL.startsWith("file:///"))
1056 if (fileURL.substring(8).indexOf(":") >0)
1057 fileURL = fileURL.substring(8);
1059 fileURL = fileURL.substring(7);
1061 else if (fileURL.startsWith("file:/"))
1063 if (fileURL.substring(6).indexOf(":") >0)
1064 fileURL = fileURL.substring(6);
1066 fileURL = fileURL.substring(5);
1069 m_outputStream = new java.io.FileOutputStream(fileURL);
1071 serializer.setOutputStream(m_outputStream);
1076 throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_OUTPUT_SPECIFIED, null)); //"No output specified!");
1078 // handler = serializer.asContentHandler();
1080 // this.setSerializer(serializer);
1084 // catch (UnsupportedEncodingException uee)
1086 // throw new TransformerException(uee);
1088 catch (IOException ioe)
1090 throw new TransformerException(ioe);
1095 throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_CANNOT_TRANSFORM_TO_RESULT_TYPE, new Object[]{outputTarget.getClass().getName()})); //"Can't transform to a Result of type "
1096 //+ outputTarget.getClass().getName()
1100 // before we forget, lets make the created handler hold a reference
1101 // to the current TransformImpl object
1102 xoh.setTransformer(this);
1104 SourceLocator srcLocator = getStylesheet();
1105 xoh.setSourceLocator(srcLocator);
1114 * Process the source tree to the output result.
1115 * @param xmlSource The input for the source tree.
1116 * @param outputTarget The output source target.
1118 * @throws TransformerException
1120 public void transform(Source xmlSource, Result outputTarget)
1121 throws TransformerException
1123 transform(xmlSource, outputTarget, true);
1127 * Process the source tree to the output result.
1128 * @param xmlSource The input for the source tree.
1129 * @param outputTarget The output source target.
1130 * @param shouldRelease Flag indicating whether to release DTMManager.
1132 * @throws TransformerException
1134 public void transform(Source xmlSource, Result outputTarget, boolean shouldRelease)
1135 throws TransformerException
1138 synchronized (m_reentryGuard)
1140 SerializationHandler xoh = createSerializationHandler(outputTarget);
1141 this.setSerializationHandler(xoh);
1143 m_outputTarget = outputTarget;
1145 transform(xmlSource, shouldRelease);
1150 * Process the source node to the output result, if the
1151 * processor supports the "http://xml.org/trax/features/dom/input"
1153 * %REVIEW% Do we need a Node version of this?
1154 * @param node The input source node, which can be any valid DTM node.
1155 * @param outputTarget The output source target.
1157 * @throws TransformerException
1159 public void transformNode(int node, Result outputTarget)
1160 throws TransformerException
1164 SerializationHandler xoh = createSerializationHandler(outputTarget);
1165 this.setSerializationHandler(xoh);
1167 m_outputTarget = outputTarget;
1169 transformNode(node);
1173 * Process the source node to the output result, if the
1174 * processor supports the "http://xml.org/trax/features/dom/input"
1176 * %REVIEW% Do we need a Node version of this?
1177 * @param node The input source node, which can be any valid DTM node.
1179 * @throws TransformerException
1181 public void transformNode(int node) throws TransformerException
1184 setExtensionsTable(getStylesheet());
1185 // Make sure we're not writing to the same output content handler.
1186 synchronized (m_serializationHandler)
1188 m_hasBeenReset = false;
1190 XPathContext xctxt = getXPathContext();
1191 DTM dtm = xctxt.getDTM(node);
1195 pushGlobalVars(node);
1198 // Give the top-level templates a chance to pass information into
1199 // the context (this is mainly for setting up tables for extensions).
1200 StylesheetRoot stylesheet = this.getStylesheet();
1201 int n = stylesheet.getGlobalImportCount();
1203 for (int i = 0; i < n; i++)
1205 StylesheetComposed imported = stylesheet.getGlobalImport(i);
1206 int includedCount = imported.getIncludeCountComposed();
1208 for (int j = -1; j < includedCount; j++)
1210 Stylesheet included = imported.getIncludeComposed(j);
1212 included.runtimeInit(this);
1214 for (ElemTemplateElement child = included.getFirstChildElem();
1215 child != null; child = child.getNextSiblingElem())
1217 child.runtimeInit(this);
1222 // System.out.println("Calling applyTemplateToNode - "+Thread.currentThread().getName());
1223 DTMIterator dtmIter = new org.apache.xpath.axes.SelfIteratorNoPredicate();
1224 dtmIter.setRoot(node, xctxt);
1225 xctxt.pushContextNodeList(dtmIter);
1228 this.applyTemplateToNode(null, null, node);
1232 xctxt.popContextNodeList();
1234 // m_stylesheetRoot.getStartRule().execute(this);
1236 // System.out.println("Done with applyTemplateToNode - "+Thread.currentThread().getName());
1237 if (null != m_serializationHandler)
1239 m_serializationHandler.endDocument();
1242 catch (Exception se)
1245 // System.out.println(Thread.currentThread().getName()+" threw an exception! "
1246 // +se.getMessage());
1247 // If an exception was thrown, we need to make sure that any waiting
1248 // handlers can terminate, which I guess is best done by sending
1252 while(se instanceof org.apache.xml.utils.WrappedRuntimeException)
1254 Exception e = ((org.apache.xml.utils.WrappedRuntimeException)se).getException();
1259 if (null != m_serializationHandler)
1263 if(se instanceof org.xml.sax.SAXParseException)
1264 m_serializationHandler.fatalError((org.xml.sax.SAXParseException)se);
1265 else if(se instanceof TransformerException)
1267 TransformerException te = ((TransformerException)se);
1268 SAXSourceLocator sl = new SAXSourceLocator( te.getLocator() );
1269 m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(te.getMessage(), sl, te));
1273 m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(se.getMessage(), new SAXSourceLocator(), se));
1276 catch (Exception e){}
1279 if(se instanceof TransformerException)
1281 m_errorHandler.fatalError((TransformerException)se);
1283 else if(se instanceof org.xml.sax.SAXParseException)
1285 m_errorHandler.fatalError(new TransformerException(se.getMessage(),
1286 new SAXSourceLocator((org.xml.sax.SAXParseException)se),
1291 m_errorHandler.fatalError(new TransformerException(se));
1303 * Get a SAX2 ContentHandler for the input.
1305 * @return A valid ContentHandler, which should never be null, as
1306 * long as getFeature("http://xml.org/trax/features/sax/input")
1309 public ContentHandler getInputContentHandler()
1311 return getInputContentHandler(false);
1315 * Get a SAX2 ContentHandler for the input.
1317 * @param doDocFrag true if a DocumentFragment should be created as
1318 * the root, rather than a Document.
1320 * @return A valid ContentHandler, which should never be null, as
1321 * long as getFeature("http://xml.org/trax/features/sax/input")
1324 public ContentHandler getInputContentHandler(boolean doDocFrag)
1327 if (null == m_inputContentHandler)
1330 // if(null == m_urlOfSource && null != m_stylesheetRoot)
1331 // m_urlOfSource = m_stylesheetRoot.getBaseIdentifier();
1332 m_inputContentHandler = new TransformerHandlerImpl(this, doDocFrag,
1336 return m_inputContentHandler;
1340 * Set the output properties for the transformation. These
1341 * properties will override properties set in the templates
1344 * @param oformat A valid OutputProperties object (which will
1345 * not be mutated), or null.
1347 public void setOutputFormat(OutputProperties oformat)
1349 m_outputFormat = oformat;
1353 * Get the output properties used for the transformation.
1355 * @return the output format that was set by the user,
1356 * otherwise the output format from the stylesheet.
1358 public OutputProperties getOutputFormat()
1361 // Get the output format that was set by the user, otherwise get the
1362 // output format from the stylesheet.
1363 OutputProperties format = (null == m_outputFormat)
1364 ? getStylesheet().getOutputComposed()
1371 * Set a parameter for the templates.
1373 * @param name The name of the parameter.
1374 * @param namespace The namespace of the parameter.
1375 * @param value The value object. This can be any valid Java object
1376 * -- it's up to the processor to provide the proper
1377 * coersion to the object, or simply pass it on for use
1380 public void setParameter(String name, String namespace, Object value)
1383 VariableStack varstack = getXPathContext().getVarStack();
1384 QName qname = new QName(namespace, name);
1385 XObject xobject = XObject.create(value, getXPathContext());
1387 StylesheetRoot sroot = m_stylesheetRoot;
1388 Vector vars = sroot.getVariablesAndParamsComposed();
1389 int i = vars.size();
1392 ElemVariable variable = (ElemVariable)vars.elementAt(i);
1393 if(variable.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE &&
1394 variable.getName().equals(qname))
1396 varstack.setGlobalVariable(i, xobject);
1401 /** NEEDSDOC Field m_userParams */
1402 Vector m_userParams;
1405 * Set a parameter for the transformation.
1407 * @param name The name of the parameter,
1408 * which may have a namespace URI.
1409 * @param value The value object. This can be any valid Java object
1410 * -- it's up to the processor to provide the proper
1411 * coersion to the object, or simply pass it on for use
1414 public void setParameter(String name, Object value)
1417 if (value == null) {
1418 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_SET_PARAM_VALUE, new Object[]{name}));
1421 StringTokenizer tokenizer = new StringTokenizer(name, "{}", false);
1426 // The first string might be the namespace, or it might be
1427 // the local name, if the namespace is null.
1428 String s1 = tokenizer.nextToken();
1429 String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
1431 if (null == m_userParams)
1432 m_userParams = new Vector();
1436 replaceOrPushUserParam(new QName(s1), XObject.create(value, getXPathContext()));
1437 setParameter(s1, null, value);
1441 replaceOrPushUserParam(new QName(s1, s2), XObject.create(value, getXPathContext()));
1442 setParameter(s2, s1, value);
1445 catch (java.util.NoSuchElementException nsee)
1448 // Should throw some sort of an error.
1453 * NEEDSDOC Method replaceOrPushUserParam
1456 * NEEDSDOC @param qname
1457 * NEEDSDOC @param xval
1459 private void replaceOrPushUserParam(QName qname, XObject xval)
1462 int n = m_userParams.size();
1464 for (int i = n - 1; i >= 0; i--)
1466 Arg arg = (Arg) m_userParams.elementAt(i);
1468 if (arg.getQName().equals(qname))
1470 m_userParams.setElementAt(new Arg(qname, xval, true), i);
1476 m_userParams.addElement(new Arg(qname, xval, true));
1480 * Get a parameter that was explicitly set with setParameter
1484 * NEEDSDOC @param name
1485 * @return A parameter that has been set with setParameter
1487 * *not* all the xsl:params on the stylesheet (which require
1488 * a transformation Source to be evaluated).
1490 public Object getParameter(String name)
1496 // VariableStack varstack = getXPathContext().getVarStack();
1497 // The first string might be the namespace, or it might be
1498 // the local name, if the namespace is null.
1499 QName qname = QName.getQNameFromString(name);
1501 if (null == m_userParams)
1504 int n = m_userParams.size();
1506 for (int i = n - 1; i >= 0; i--)
1508 Arg arg = (Arg) m_userParams.elementAt(i);
1510 if (arg.getQName().equals(qname))
1512 return arg.getVal().object();
1518 catch (java.util.NoSuchElementException nsee)
1521 // Should throw some sort of an error.
1527 * Reset parameters that the user specified for the transformation.
1528 * Called during transformer.reset() after we have cleared the
1529 * variable stack. We need to make sure that user params are
1530 * reset so that the transformer object can be reused.
1532 private void resetUserParameters()
1538 if (null == m_userParams)
1541 int n = m_userParams.size();
1542 for (int i = n - 1; i >= 0; i--)
1544 Arg arg = (Arg) m_userParams.elementAt(i);
1545 QName name = arg.getQName();
1546 // The first string might be the namespace, or it might be
1547 // the local name, if the namespace is null.
1548 String s1 = name.getNamespace();
1549 String s2 = name.getLocalPart();
1551 setParameter(s2, s1, arg.getVal().object());
1556 catch (java.util.NoSuchElementException nsee)
1558 // Should throw some sort of an error.
1564 * Set a bag of parameters for the transformation. Note that
1565 * these will not be additive, they will replace the existing
1566 * set of parameters.
1568 * NEEDSDOC @param params
1570 public void setParameters(Properties params)
1575 Enumeration names = params.propertyNames();
1577 while (names.hasMoreElements())
1579 String name = params.getProperty((String) names.nextElement());
1580 StringTokenizer tokenizer = new StringTokenizer(name, "{}", false);
1585 // The first string might be the namespace, or it might be
1586 // the local name, if the namespace is null.
1587 String s1 = tokenizer.nextToken();
1588 String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null;
1591 setParameter(s1, null, params.getProperty(name));
1593 setParameter(s2, s1, params.getProperty(name));
1595 catch (java.util.NoSuchElementException nsee)
1598 // Should throw some sort of an error.
1604 * Reset the parameters to a null list.
1606 public void clearParameters()
1609 synchronized (m_reentryGuard)
1611 VariableStack varstack = new VariableStack();
1613 m_xcontext.setVarStack(varstack);
1615 m_userParams = null;
1621 * Internal -- push the global variables from the Stylesheet onto
1622 * the context's runtime variable stack.
1623 * <p>If we encounter a variable
1624 * that is already defined in the variable stack, we ignore it. This
1625 * is because the second variable definition will be at a lower import
1626 * precedence. Presumably, global"variables at the same import precedence
1627 * with the same name will have been caught during the recompose process.
1628 * <p>However, if we encounter a parameter that is already defined in the
1629 * variable stack, we need to see if this is a parameter whose value was
1630 * supplied by a setParameter call. If so, we need to "receive" the one
1631 * already in the stack, ignoring this one. If it is just an earlier
1632 * xsl:param or xsl:variable definition, we ignore it using the same
1633 * reasoning as explained above for the variable.
1635 * @param contextNode The root of the source tree, can't be null.
1637 * @throws TransformerException
1639 protected void pushGlobalVars(int contextNode) throws TransformerException
1642 XPathContext xctxt = m_xcontext;
1643 VariableStack vs = xctxt.getVarStack();
1644 StylesheetRoot sr = getStylesheet();
1645 Vector vars = sr.getVariablesAndParamsComposed();
1647 int i = vars.size();
1652 ElemVariable v = (ElemVariable) vars.elementAt(i);
1654 // XObject xobj = v.getValue(this, contextNode);
1655 XObject xobj = new XUnresolvedVariable(v, contextNode, this,
1656 vs.getStackFrame(), 0, true);
1658 if(null == vs.elementAt(i))
1659 vs.setGlobalVariable(i, xobj);
1665 * Set an object that will be used to resolve URIs used in
1667 * @param resolver An object that implements the URIResolver interface,
1670 public void setURIResolver(URIResolver resolver)
1673 synchronized (m_reentryGuard)
1675 m_xcontext.getSourceTreeManager().setURIResolver(resolver);
1680 * Get an object that will be used to resolve URIs used in
1683 * @return An object that implements the URIResolver interface,
1686 public URIResolver getURIResolver()
1688 return m_xcontext.getSourceTreeManager().getURIResolver();
1691 // ======== End Transformer Implementation ========
1694 * Set the content event handler.
1696 * NEEDSDOC @param handler
1697 * @throws java.lang.NullPointerException If the handler
1699 * @see org.xml.sax.XMLReader#setContentHandler
1701 public void setContentHandler(ContentHandler handler)
1704 if (handler == null)
1706 throw new NullPointerException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_CONTENT_HANDLER, null)); //"Null content handler");
1710 m_outputContentHandler = handler;
1712 if (null == m_serializationHandler)
1714 ToXMLSAXHandler h = new ToXMLSAXHandler();
1715 h.setContentHandler(handler);
1716 h.setTransformer(this);
1718 m_serializationHandler = h;
1721 m_serializationHandler.setContentHandler(handler);
1726 * Get the content event handler.
1728 * @return The current content handler, or null if none was set.
1729 * @see org.xml.sax.XMLReader#getContentHandler
1731 public ContentHandler getContentHandler()
1733 return m_outputContentHandler;
1737 * Given a stylesheet element, create a result tree fragment from it's
1738 * contents. The fragment will be built within the shared RTF DTM system
1739 * used as a variable stack.
1740 * @param templateParent The template element that holds the fragment.
1741 * @return the NodeHandle for the root node of the resulting RTF.
1743 * @throws TransformerException
1744 * @xsl.usage advanced
1746 public int transformToRTF(ElemTemplateElement templateParent)
1747 throws TransformerException
1749 // Retrieve a DTM to contain the RTF. At this writing, this may be a
1750 // multi-document DTM (SAX2RTFDTM).
1751 DTM dtmFrag = m_xcontext.getRTFDTM();
1752 return transformToRTF(templateParent,dtmFrag);
1756 * Given a stylesheet element, create a result tree fragment from it's
1757 * contents. The fragment will also use the shared DTM system, but will
1758 * obtain its space from the global variable pool rather than the dynamic
1759 * variable stack. This allows late binding of XUnresolvedVariables without
1760 * the risk that their content will be discarded when the variable stack
1763 * @param templateParent The template element that holds the fragment.
1764 * @return the NodeHandle for the root node of the resulting RTF.
1766 * @throws TransformerException
1767 * @xsl.usage advanced
1769 public int transformToGlobalRTF(ElemTemplateElement templateParent)
1770 throws TransformerException
1772 // Retrieve a DTM to contain the RTF. At this writing, this may be a
1773 // multi-document DTM (SAX2RTFDTM).
1774 DTM dtmFrag = m_xcontext.getGlobalRTFDTM();
1775 return transformToRTF(templateParent,dtmFrag);
1779 * Given a stylesheet element, create a result tree fragment from it's
1781 * @param templateParent The template element that holds the fragment.
1782 * @param dtmFrag The DTM to write the RTF into
1783 * @return the NodeHandle for the root node of the resulting RTF.
1785 * @throws TransformerException
1786 * @xsl.usage advanced
1788 private int transformToRTF(ElemTemplateElement templateParent,DTM dtmFrag)
1789 throws TransformerException
1792 XPathContext xctxt = m_xcontext;
1794 ContentHandler rtfHandler = dtmFrag.getContentHandler();
1796 // Obtain the ResultTreeFrag's root node.
1797 // NOTE: In SAX2RTFDTM, this value isn't available until after
1798 // the startDocument has been issued, so assignment has been moved
1799 // down a bit in the code.
1800 int resultFragment; // not yet reliably = dtmFrag.getDocument();
1802 // Save the current result tree handler.
1803 SerializationHandler savedRTreeHandler = this.m_serializationHandler;
1806 // And make a new handler for the RTF.
1807 ToSAXHandler h = new ToXMLSAXHandler();
1808 h.setContentHandler(rtfHandler);
1809 h.setTransformer(this);
1811 // Replace the old handler (which was already saved)
1812 m_serializationHandler = h;
1814 // use local variable for the current handler
1815 SerializationHandler rth = m_serializationHandler;
1819 rth.startDocument();
1821 // startDocument is "bottlenecked" in RTH. We need it acted upon immediately,
1822 // to set the DTM's state as in-progress, so that if the xsl:variable's body causes
1823 // further RTF activity we can keep that from bashing this DTM.
1829 // Do the transformation of the child elements.
1830 executeChildTemplates(templateParent, true);
1832 // Make sure everything is flushed!
1835 // Get the document ID. May not exist until the RTH has not only
1836 // received, but flushed, the startDocument, and may be invalid
1837 // again after the document has been closed (still debating that)
1838 // ... so waiting until just before the end seems simplest/safest.
1839 resultFragment = dtmFrag.getDocument();
1846 catch (org.xml.sax.SAXException se)
1848 throw new TransformerException(se);
1853 // Restore the previous result tree handler.
1854 this.m_serializationHandler = savedRTreeHandler;
1857 return resultFragment;
1861 * Take the contents of a template element, process it, and
1862 * convert it to a string.
1864 * @param elem The parent element whose children will be output
1867 * @return The stringized result of executing the elements children.
1869 * @throws TransformerException
1870 * @xsl.usage advanced
1872 public String transformToString(ElemTemplateElement elem)
1873 throws TransformerException
1875 ElemTemplateElement firstChild = elem.getFirstChildElem();
1876 if(null == firstChild)
1878 if(elem.hasTextLitOnly() && m_optimizer)
1880 return ((ElemTextLiteral)firstChild).getNodeValue();
1883 // Save the current result tree handler.
1884 SerializationHandler savedRTreeHandler = this.m_serializationHandler;
1886 // Create a Serializer object that will handle the SAX events
1887 // and build the ResultTreeFrag nodes.
1888 StringWriter sw = (StringWriter) m_stringWriterObjectPool.getInstance();
1890 m_serializationHandler =
1891 (ToTextStream) m_textResultHandlerObjectPool.getInstance();
1893 if (null == m_serializationHandler)
1895 // if we didn't get one from the pool, go make a new one
1898 Serializer serializer = org.apache.xml.serializer.SerializerFactory.getSerializer(
1899 m_textformat.getProperties());
1900 m_serializationHandler = (SerializationHandler) serializer;
1903 m_serializationHandler.setTransformer(this);
1904 m_serializationHandler.setWriter(sw);
1911 /* Don't call startDocument, the SerializationHandler will
1912 * generate its own internal startDocument call anyways
1914 // this.m_serializationHandler.startDocument();
1916 // Do the transformation of the child elements.
1917 executeChildTemplates(elem, true);
1918 this.m_serializationHandler.endDocument();
1920 result = sw.toString();
1922 catch (org.xml.sax.SAXException se)
1924 throw new TransformerException(se);
1928 sw.getBuffer().setLength(0);
1934 catch (Exception ioe){}
1936 m_stringWriterObjectPool.freeInstance(sw);
1937 m_serializationHandler.reset();
1938 m_textResultHandlerObjectPool.freeInstance(m_serializationHandler);
1940 // Restore the previous result tree handler.
1941 m_serializationHandler = savedRTreeHandler;
1948 * Given an element and mode, find the corresponding
1949 * template and process the contents.
1951 * @param xslInstruction The calling element.
1952 * @param template The template to use if xsl:for-each, current template for apply-imports, or null.
1953 * @param child The source context node.
1954 * @throws TransformerException
1955 * @return true if applied a template, false if not.
1956 * @xsl.usage advanced
1958 public boolean applyTemplateToNode(ElemTemplateElement xslInstruction, // xsl:apply-templates or xsl:for-each
1959 ElemTemplate template, int child)
1960 throws TransformerException
1963 DTM dtm = m_xcontext.getDTM(child);
1964 short nodeType = dtm.getNodeType(child);
1965 boolean isDefaultTextRule = false;
1966 boolean isApplyImports = false;
1968 isApplyImports = ((xslInstruction == null)
1970 : xslInstruction.getXSLToken()
1971 == Constants.ELEMNAME_APPLY_IMPORTS);
1973 if (null == template || isApplyImports)
1975 int maxImportLevel, endImportLevel=0;
1980 template.getStylesheetComposed().getImportCountComposed() - 1;
1982 template.getStylesheetComposed().getEndImportCountComposed();
1986 maxImportLevel = -1;
1989 // If we're trying an xsl:apply-imports at the top level (ie there are no
1990 // imported stylesheets), we need to indicate that there is no matching template.
1991 // The above logic will calculate a maxImportLevel of -1 which indicates
1992 // that we should find any template. This is because a value of -1 for
1993 // maxImportLevel has a special meaning. But we don't want that.
1994 // We want to match -no- templates. See bugzilla bug 1170.
1995 if (isApplyImports && (maxImportLevel == -1))
2002 // Find the XSL template that is the best match for the
2004 XPathContext xctxt = m_xcontext;
2008 xctxt.pushNamespaceContext(xslInstruction);
2010 QName mode = this.getMode();
2013 template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode,
2014 maxImportLevel, endImportLevel, m_quietConflictWarnings, dtm);
2016 template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode,
2017 m_quietConflictWarnings, dtm);
2022 xctxt.popNamespaceContext();
2026 // If that didn't locate a node, fall back to a default template rule.
2027 // See http://www.w3.org/TR/xslt#built-in-rule.
2028 if (null == template)
2032 case DTM.DOCUMENT_FRAGMENT_NODE :
2033 case DTM.ELEMENT_NODE :
2034 template = m_stylesheetRoot.getDefaultRule();
2036 case DTM.CDATA_SECTION_NODE :
2037 case DTM.TEXT_NODE :
2038 case DTM.ATTRIBUTE_NODE :
2039 template = m_stylesheetRoot.getDefaultTextRule();
2040 isDefaultTextRule = true;
2042 case DTM.DOCUMENT_NODE :
2043 template = m_stylesheetRoot.getDefaultRootRule();
2047 // No default rules for processing instructions and the like.
2053 // If we are processing the default text rule, then just clone
2054 // the value directly to the result tree.
2057 pushElemTemplateElement(template);
2058 m_xcontext.pushCurrentNode(child);
2059 pushPairCurrentMatched(template, child);
2061 // Fix copy copy29 test.
2062 if (!isApplyImports) {
2063 DTMIterator cnl = new org.apache.xpath.NodeSetDTM(child, m_xcontext.getDTMManager());
2064 m_xcontext.pushContextNodeList(cnl);
2067 if (isDefaultTextRule)
2071 case DTM.CDATA_SECTION_NODE :
2072 case DTM.TEXT_NODE :
2073 ClonerToResultTree.cloneToResultTree(child, nodeType,
2074 dtm, getResultTreeHandler(), false);
2076 case DTM.ATTRIBUTE_NODE :
2077 dtm.dispatchCharactersEvents(child, getResultTreeHandler(), false);
2084 // And execute the child templates.
2085 // 9/11/00: If template has been compiled, hand off to it
2086 // since much (most? all?) of the processing has been inlined.
2087 // (It would be nice if there was a single entry point that
2088 // worked for both... but the interpretive system works by
2089 // having the Tranformer execute the children, while the
2090 // compiled obviously has to run its own code. It's
2091 // also unclear that "execute" is really the right name for
2092 // that entry point.)
2093 m_xcontext.setSAXLocator(template);
2094 // m_xcontext.getVarStack().link();
2095 m_xcontext.getVarStack().link(template.m_frameSize);
2096 executeChildTemplates(template, true);
2099 catch (org.xml.sax.SAXException se)
2101 throw new TransformerException(se);
2105 if (!isDefaultTextRule)
2106 m_xcontext.getVarStack().unlink();
2107 m_xcontext.popCurrentNode();
2108 if (!isApplyImports) {
2109 m_xcontext.popContextNodeList();
2111 popCurrentMatched();
2113 popElemTemplateElement();
2121 * Execute each of the children of a template element. This method
2122 * is only for extension use.
2124 * @param elem The ElemTemplateElement that contains the children
2125 * that should execute.
2126 * NEEDSDOC @param context
2127 * @param mode The current mode.
2128 * @param handler The ContentHandler to where the result events
2131 * @throws TransformerException
2132 * @xsl.usage advanced
2134 public void executeChildTemplates(
2135 ElemTemplateElement elem, org.w3c.dom.Node context, QName mode, ContentHandler handler)
2136 throws TransformerException
2139 XPathContext xctxt = m_xcontext;
2145 xctxt.pushCurrentNode(xctxt.getDTMHandleFromNode(context));
2146 executeChildTemplates(elem, handler);
2150 xctxt.popCurrentNode();
2152 // I'm not sure where or why this was here. It is clearly in
2153 // error though, without a corresponding pushMode().
2160 * Execute each of the children of a template element.
2162 * @param elem The ElemTemplateElement that contains the children
2163 * that should execute.
2164 * @param shouldAddAttrs true if xsl:attributes should be executed.
2166 * @throws TransformerException
2167 * @xsl.usage advanced
2169 public void executeChildTemplates(
2170 ElemTemplateElement elem, boolean shouldAddAttrs)
2171 throws TransformerException
2174 // Does this element have any children?
2175 ElemTemplateElement t = elem.getFirstChildElem();
2180 if(elem.hasTextLitOnly() && m_optimizer)
2182 char[] chars = ((ElemTextLiteral)t).getChars();
2185 // Have to push stuff on for tooling...
2186 this.pushElemTemplateElement(t);
2187 m_serializationHandler.characters(chars, 0, chars.length);
2189 catch(SAXException se)
2191 throw new TransformerException(se);
2195 this.popElemTemplateElement();
2200 // // Check for infinite loops if we have to.
2201 // boolean check = (m_stackGuard.m_recursionLimit > -1);
2204 // getStackGuard().push(elem, xctxt.getCurrentNode());
2206 XPathContext xctxt = m_xcontext;
2207 xctxt.pushSAXLocatorNull();
2208 int currentTemplateElementsTop = m_currentTemplateElements.size();
2209 m_currentTemplateElements.push(null);
2213 // Loop through the children of the template, calling execute on
2215 for (; t != null; t = t.getNextSiblingElem())
2218 && t.getXSLToken() == Constants.ELEMNAME_ATTRIBUTE)
2221 xctxt.setSAXLocator(t);
2222 m_currentTemplateElements.setElementAt(t,currentTemplateElementsTop);
2226 catch(RuntimeException re)
2228 TransformerException te = new TransformerException(re);
2234 m_currentTemplateElements.pop();
2235 xctxt.popSAXLocator();
2238 // Check for infinite loops if we have to
2240 // getStackGuard().pop();
2243 * Execute each of the children of a template element.
2245 * @param elem The ElemTemplateElement that contains the children
2246 * that should execute.
2247 * @param handler The ContentHandler to where the result events
2250 * @throws TransformerException
2251 * @xsl.usage advanced
2253 public void executeChildTemplates(
2254 ElemTemplateElement elem, ContentHandler handler)
2255 throws TransformerException
2258 SerializationHandler xoh = this.getSerializationHandler();
2260 // These may well not be the same! In this case when calling
2261 // the Redirect extension, it has already set the ContentHandler
2262 // in the Transformer.
2263 SerializationHandler savedHandler = xoh;
2269 // %REVIEW% Make sure current node is being pushed.
2270 LexicalHandler lex = null;
2271 if (handler instanceof LexicalHandler) {
2272 lex = (LexicalHandler) handler;
2274 m_serializationHandler = new ToXMLSAXHandler(handler, lex, savedHandler.getEncoding());
2275 m_serializationHandler.setTransformer(this);
2276 executeChildTemplates(elem, true);
2278 catch (TransformerException e)
2282 catch (SAXException se) {
2283 throw new TransformerException(se);
2287 m_serializationHandler = savedHandler;
2292 * Get the keys for the xsl:sort elements.
2293 * Note: Should this go into ElemForEach?
2295 * @param foreach Valid ElemForEach element, not null.
2296 * @param sourceNodeContext The current node context in the source tree,
2297 * needed to evaluate the Attribute Value Templates.
2299 * @return A Vector of NodeSortKeys, or null.
2301 * @throws TransformerException
2302 * @xsl.usage advanced
2304 public Vector processSortKeys(ElemForEach foreach, int sourceNodeContext)
2305 throws TransformerException
2309 XPathContext xctxt = m_xcontext;
2310 int nElems = foreach.getSortElemCount();
2313 keys = new Vector();
2315 // March backwards, collecting the sort keys.
2316 for (int i = 0; i < nElems; i++)
2318 ElemSort sort = foreach.getSortElem(i);
2321 (null != sort.getLang())
2322 ? sort.getLang().evaluate(xctxt, sourceNodeContext, foreach) : null;
2323 String dataTypeString = sort.getDataType().evaluate(xctxt,
2324 sourceNodeContext, foreach);
2326 if (dataTypeString.indexOf(":") >= 0)
2328 "TODO: Need to write the hooks for QNAME sort data type");
2329 else if (!(dataTypeString.equalsIgnoreCase(Constants.ATTRVAL_DATATYPE_TEXT))
2330 &&!(dataTypeString.equalsIgnoreCase(
2331 Constants.ATTRVAL_DATATYPE_NUMBER)))
2332 foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2333 new Object[]{ Constants.ATTRNAME_DATATYPE,
2336 boolean treatAsNumbers =
2337 ((null != dataTypeString) && dataTypeString.equals(
2338 Constants.ATTRVAL_DATATYPE_NUMBER)) ? true : false;
2339 String orderString = sort.getOrder().evaluate(xctxt, sourceNodeContext,
2342 if (!(orderString.equalsIgnoreCase(Constants.ATTRVAL_ORDER_ASCENDING))
2343 &&!(orderString.equalsIgnoreCase(
2344 Constants.ATTRVAL_ORDER_DESCENDING)))
2345 foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2346 new Object[]{ Constants.ATTRNAME_ORDER,
2349 boolean descending =
2350 ((null != orderString) && orderString.equals(
2351 Constants.ATTRVAL_ORDER_DESCENDING)) ? true : false;
2352 AVT caseOrder = sort.getCaseOrder();
2353 boolean caseOrderUpper;
2355 if (null != caseOrder)
2357 String caseOrderString = caseOrder.evaluate(xctxt, sourceNodeContext,
2360 if (!(caseOrderString.equalsIgnoreCase(Constants.ATTRVAL_CASEORDER_UPPER))
2361 &&!(caseOrderString.equalsIgnoreCase(
2362 Constants.ATTRVAL_CASEORDER_LOWER)))
2363 foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE,
2364 new Object[]{ Constants.ATTRNAME_CASEORDER,
2368 ((null != caseOrderString) && caseOrderString.equals(
2369 Constants.ATTRVAL_CASEORDER_UPPER)) ? true : false;
2373 caseOrderUpper = false;
2376 keys.addElement(new NodeSortKey(this, sort.getSelect(), treatAsNumbers,
2377 descending, langString, caseOrderUpper,
2384 //==========================================================
2385 // SECTION: TransformState implementation
2386 //==========================================================
2389 * Get the count of how many elements are
2391 * @return The number of active elements on
2392 * the currentTemplateElements stack.
2394 public int getCurrentTemplateElementsCount()
2396 return m_currentTemplateElements.size();
2401 * Get the count of how many elements are
2403 * @return The number of active elements on
2404 * the currentTemplateElements stack.
2406 public ObjectStack getCurrentTemplateElements()
2408 return m_currentTemplateElements;
2412 * Push the current template element.
2414 * @param elem The current ElemTemplateElement (may be null, and then
2415 * set via setCurrentElement).
2417 public void pushElemTemplateElement(ElemTemplateElement elem)
2419 m_currentTemplateElements.push(elem);
2423 * Pop the current template element.
2425 public void popElemTemplateElement()
2427 m_currentTemplateElements.pop();
2431 * Set the top of the current template elements
2434 * @param e The current ElemTemplateElement about to
2437 public void setCurrentElement(ElemTemplateElement e)
2439 m_currentTemplateElements.setTop(e);
2443 * Retrieves the current ElemTemplateElement that is
2446 * @return The current ElemTemplateElement that is executing,
2447 * should not normally be null.
2449 public ElemTemplateElement getCurrentElement()
2451 return (m_currentTemplateElements.size() > 0) ?
2452 (ElemTemplateElement) m_currentTemplateElements.peek() : null;
2456 * This method retrieves the current context node
2457 * in the source tree.
2459 * @return The current context node (should never be null?).
2461 public int getCurrentNode()
2463 return m_xcontext.getCurrentNode();
2467 * This method retrieves the xsl:template
2468 * that is in effect, which may be a matched template
2469 * or a named template.
2471 * <p>Please note that the ElemTemplate returned may
2472 * be a default template, and thus may not have a template
2473 * defined in the stylesheet.</p>
2475 * @return The current xsl:template, should not be null.
2477 public ElemTemplate getCurrentTemplate()
2480 ElemTemplateElement elem = getCurrentElement();
2482 while ((null != elem)
2483 && (elem.getXSLToken() != Constants.ELEMNAME_TEMPLATE))
2485 elem = elem.getParentElem();
2488 return (ElemTemplate) elem;
2492 * Push both the current xsl:template or xsl:for-each onto the
2493 * stack, along with the child node that was matched.
2494 * (Note: should this only be used for xsl:templates?? -sb)
2496 * @param template xsl:template or xsl:for-each.
2497 * @param child The child that was matched.
2499 public void pushPairCurrentMatched(ElemTemplateElement template, int child)
2501 m_currentMatchTemplates.push(template);
2502 m_currentMatchedNodes.push(child);
2506 * Pop the elements that were pushed via pushPairCurrentMatched.
2508 public void popCurrentMatched()
2510 m_currentMatchTemplates.pop();
2511 m_currentMatchedNodes.pop();
2515 * This method retrieves the xsl:template
2516 * that was matched. Note that this may not be
2517 * the same thing as the current template (which
2518 * may be from getCurrentElement()), since a named
2519 * template may be in effect.
2521 * @return The pushed template that was pushed via pushPairCurrentMatched.
2523 public ElemTemplate getMatchedTemplate()
2525 return (ElemTemplate) m_currentMatchTemplates.peek();
2529 * Retrieves the node in the source tree that matched
2530 * the template obtained via getMatchedTemplate().
2532 * @return The matched node that corresponds to the
2533 * match attribute of the current xsl:template.
2535 public int getMatchedNode()
2537 return m_currentMatchedNodes.peepTail();
2541 * Get the current context node list.
2543 * @return A reset clone of the context node list.
2545 public DTMIterator getContextNodeList()
2550 DTMIterator cnl = m_xcontext.getContextNodeList();
2552 return (cnl == null) ? null : (DTMIterator) cnl.cloneWithReset();
2554 catch (CloneNotSupportedException cnse)
2557 // should never happen.
2563 * Get the TrAX Transformer object in effect.
2565 * @return This object.
2567 public Transformer getTransformer()
2572 //==========================================================
2573 // SECTION: Accessor Functions
2574 //==========================================================
2577 * Set the stylesheet for this processor. If this is set, then the
2578 * process calls that take only the input .xml will use
2579 * this instead of looking for a stylesheet PI. Also,
2580 * setting the stylesheet is needed if you are going
2581 * to use the processor as a SAX ContentHandler.
2583 * @param stylesheetRoot A non-null StylesheetRoot object,
2584 * or null if you wish to clear the stylesheet reference.
2586 public void setStylesheet(StylesheetRoot stylesheetRoot)
2588 m_stylesheetRoot = stylesheetRoot;
2592 * Get the current stylesheet for this processor.
2594 * @return The stylesheet that is associated with this
2597 public final StylesheetRoot getStylesheet()
2599 return m_stylesheetRoot;
2603 * Get quietConflictWarnings property. If the quietConflictWarnings
2604 * property is set to true, warnings about pattern conflicts won't be
2605 * printed to the diagnostics stream.
2607 * @return True if this transformer should not report
2608 * template match conflicts.
2610 public boolean getQuietConflictWarnings()
2612 return m_quietConflictWarnings;
2616 * Set the execution context for XPath.
2618 * @param xcontext A non-null reference to the XPathContext
2619 * associated with this transformer.
2620 * @xsl.usage internal
2622 public void setXPathContext(XPathContext xcontext)
2624 m_xcontext = xcontext;
2628 * Get the XPath context associated with this transformer.
2630 * @return The XPathContext reference, never null.
2632 public final XPathContext getXPathContext()
2638 * Get the SerializationHandler object.
2640 * @return The current SerializationHandler, which may not
2641 * be the main result tree manager.
2643 public SerializationHandler getResultTreeHandler()
2645 return m_serializationHandler;
2649 * Get the SerializationHandler object.
2651 * @return The current SerializationHandler, which may not
2652 * be the main result tree manager.
2654 public SerializationHandler getSerializationHandler()
2656 return m_serializationHandler;
2660 * Get the KeyManager object.
2662 * @return A reference to the KeyManager object, which should
2665 public KeyManager getKeyManager()
2667 return m_keyManager;
2671 * Check to see if this is a recursive attribute definition.
2673 * @param attrSet A non-null ElemAttributeSet reference.
2675 * @return true if the attribute set is recursive.
2677 public boolean isRecursiveAttrSet(ElemAttributeSet attrSet)
2680 if (null == m_attrSetStack)
2682 m_attrSetStack = new Stack();
2685 if (!m_attrSetStack.empty())
2687 int loc = m_attrSetStack.search(attrSet);
2699 * Push an executing attribute set, so we can check for
2700 * recursive attribute definitions.
2702 * @param attrSet A non-null ElemAttributeSet reference.
2704 public void pushElemAttributeSet(ElemAttributeSet attrSet)
2706 m_attrSetStack.push(attrSet);
2710 * Pop the current executing attribute set.
2712 public void popElemAttributeSet()
2714 m_attrSetStack.pop();
2718 * Get the table of counters, for optimized xsl:number support.
2720 * @return The CountersTable, never null.
2722 public CountersTable getCountersTable()
2725 if (null == m_countersTable)
2726 m_countersTable = new CountersTable();
2728 return m_countersTable;
2732 * Tell if the current template rule is null, i.e. if we are
2733 * directly within an apply-templates. Used for xsl:apply-imports.
2735 * @return True if the current template rule is null.
2737 public boolean currentTemplateRuleIsNull()
2739 return ((!m_currentTemplateRuleIsNull.isEmpty())
2740 && (m_currentTemplateRuleIsNull.peek() == true));
2744 * Push true if the current template rule is null, false
2747 * @param b True if the we are executing an xsl:for-each
2748 * (or xsl:call-template?).
2750 public void pushCurrentTemplateRuleIsNull(boolean b)
2752 m_currentTemplateRuleIsNull.push(b);
2756 * Push true if the current template rule is null, false
2759 public void popCurrentTemplateRuleIsNull()
2761 m_currentTemplateRuleIsNull.pop();
2765 * Push a funcion result for the currently active EXSLT
2766 * <code>func:function</code>.
2768 * @param val the result of executing an EXSLT
2769 * <code>func:result</code> instruction for the current
2770 * <code>func:function</code>.
2772 public void pushCurrentFuncResult(Object val) {
2773 m_currentFuncResult.push(val);
2777 * Pops the result of the currently active EXSLT <code>func:function</code>.
2779 * @return the value of the <code>func:function</code>
2781 public Object popCurrentFuncResult() {
2782 return m_currentFuncResult.pop();
2786 * Determines whether an EXSLT <code>func:result</code> instruction has been
2787 * executed for the currently active EXSLT <code>func:function</code>.
2789 * @return <code>true</code> if and only if a <code>func:result</code>
2790 * instruction has been executed
2792 public boolean currentFuncResultSeen() {
2793 return !m_currentFuncResult.empty()
2794 && m_currentFuncResult.peek() != null;
2798 * Return the message manager.
2800 * @return The message manager, never null.
2802 public MsgMgr getMsgMgr()
2805 if (null == m_msgMgr)
2806 m_msgMgr = new MsgMgr(this);
2812 * Set the error event listener.
2814 * @param listener The new error listener.
2815 * @throws IllegalArgumentException if
2817 public void setErrorListener(ErrorListener listener)
2818 throws IllegalArgumentException
2821 synchronized (m_reentryGuard)
2823 if (listener == null)
2824 throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler");
2826 m_errorHandler = listener;
2831 * Get the current error event handler.
2833 * @return The current error handler, which should never be null.
2835 public ErrorListener getErrorListener()
2837 return m_errorHandler;
2841 * Look up the value of a feature.
2843 * <p>The feature name is any fully-qualified URI. It is
2844 * possible for an TransformerFactory to recognize a feature name but
2845 * to be unable to return its value; this is especially true
2846 * in the case of an adapter for a SAX1 Parser, which has
2847 * no way of knowing whether the underlying parser is
2848 * validating, for example.</p>
2850 * <h3>Open issues:</h3>
2852 * <dt><h4>Should getFeature be changed to hasFeature?</h4></dt>
2853 * <dd>Keith Visco writes: Should getFeature be changed to hasFeature?
2854 * It returns a boolean which indicated whether the "state"
2855 * of feature is "true or false". I assume this means whether
2856 * or not a feature is supported? I know SAX is using "getFeature",
2857 * but to me "hasFeature" is cleaner.</dd>
2860 * @param name The feature name, which is a fully-qualified
2862 * @return The current state of the feature (true or false).
2863 * @throws org.xml.sax.SAXNotRecognizedException When the
2864 * TransformerFactory does not recognize the feature name.
2865 * @throws org.xml.sax.SAXNotSupportedException When the
2866 * TransformerFactory recognizes the feature name but
2867 * cannot determine its value at this time.
2869 * @throws SAXNotRecognizedException
2870 * @throws SAXNotSupportedException
2872 public boolean getFeature(String name)
2873 throws SAXNotRecognizedException, SAXNotSupportedException
2876 if ("http://xml.org/trax/features/sax/input".equals(name))
2878 else if ("http://xml.org/trax/features/dom/input".equals(name))
2881 throw new SAXNotRecognizedException(name);
2887 * NEEDSDOC Method getMode
2890 * NEEDSDOC (getMode) @return
2892 public QName getMode()
2894 return m_modes.isEmpty() ? null : (QName) m_modes.peek();
2900 * NEEDSDOC Method pushMode
2903 * NEEDSDOC @param mode
2905 public void pushMode(QName mode)
2913 * NEEDSDOC Method popMode
2916 public void popMode()
2922 * Called by SourceTreeHandler to start the transformation
2923 * in a separate thread
2925 * NEEDSDOC @param priority
2927 public void runTransformThread(int priority)
2930 // used in SourceTreeHandler
2931 Thread t = ThreadControllerWrapper.runThread(this, priority);
2932 this.setTransformThread(t);
2936 * Called by this.transform() if isParserEventsOnMain()==false.
2937 * Similar with runTransformThread(), but no priority is set
2938 * and setTransformThread is not set.
2940 public void runTransformThread()
2942 ThreadControllerWrapper.runThread(this, -1);
2946 * Called by CoRoutineSAXParser. Launches the CoroutineSAXParser
2947 * in a thread, and prepares it to invoke the parser from that thread
2951 public static void runTransformThread(Runnable runnable)
2953 ThreadControllerWrapper.runThread(runnable, -1);
2957 * Used by SourceTreeHandler to wait until the transform
2960 * @throws SAXException
2962 public void waitTransformThread() throws SAXException
2965 // This is called to make sure the task is done.
2966 // It is possible that the thread has been reused -
2967 // but for a different transformation. ( what if we
2968 // recycle the transformer ? Not a problem since this is
2970 Thread transformThread = this.getTransformThread();
2972 if (null != transformThread)
2976 ThreadControllerWrapper.waitThread(transformThread, this);
2978 if (!this.hasTransformThreadErrorCatcher())
2980 Exception e = this.getExceptionThrown();
2984 e.printStackTrace();
2985 throw new org.xml.sax.SAXException(e);
2989 this.setTransformThread(null);
2991 catch (InterruptedException ie){}
2996 * Get the exception thrown by the secondary thread (normally
2997 * the transform thread).
2999 * @return The thrown exception, or null if no exception was
3002 public Exception getExceptionThrown()
3004 return m_exceptionThrown;
3008 * Set the exception thrown by the secondary thread (normally
3009 * the transform thread).
3011 * @param e The thrown exception, or null if no exception was
3014 public void setExceptionThrown(Exception e)
3016 m_exceptionThrown = e;
3020 * This is just a way to set the document for run().
3022 * @param doc A non-null reference to the root of the
3023 * tree to be transformed.
3025 public void setSourceTreeDocForThread(int doc)
3031 * From a secondary thread, post the exception, so that
3032 * it can be picked up from the main thread.
3034 * @param e The exception that was thrown.
3036 void postExceptionFromThread(Exception e)
3039 // Commented out in response to problem reported by Nicola Brown <Nicola.Brown@jacobsrimell.com>
3040 // if(m_reportInPostExceptionFromThread)
3042 // // Consider re-throwing the exception if this flag is set.
3043 // e.printStackTrace();
3045 // %REVIEW Need DTM equivelent?
3046 // if (m_inputContentHandler instanceof SourceTreeHandler)
3048 // SourceTreeHandler sth = (SourceTreeHandler) m_inputContentHandler;
3050 // sth.setExceptionThrown(e);
3052 // ContentHandler ch = getContentHandler();
3054 // if(ch instanceof SourceTreeHandler)
3056 // SourceTreeHandler sth = (SourceTreeHandler) ch;
3057 // ((TransformerImpl)(sth.getTransformer())).postExceptionFromThread(e);
3059 // m_isTransformDone = true; // android-removed
3060 m_exceptionThrown = e;
3061 ; // should have already been reported via the error handler?
3066 // See message from me on 3/27/2001 to Patrick Moore.
3067 // String msg = e.getMessage();
3068 // System.out.println(e.getMessage());
3069 // Is this really needed? -sb
3075 // // m_throwNewError = false;
3076 // e.printStackTrace();
3078 // throw new org.apache.xml.utils.WrappedRuntimeException(e);
3083 * Run the transform thread.
3088 m_hasBeenReset = false;
3093 // int n = ((SourceTreeHandler)getInputContentHandler()).getDTMRoot();
3094 // transformNode(n);
3097 // m_isTransformDone = false; // android-removed
3099 // Should no longer be needed...
3100 // if(m_inputContentHandler instanceof TransformerHandlerImpl)
3102 // TransformerHandlerImpl thi = (TransformerHandlerImpl)m_inputContentHandler;
3103 // thi.waitForInitialEvents();
3106 transformNode(m_doc);
3111 // e.printStackTrace();
3113 // Strange that the other catch won't catch this...
3114 if (null != m_transformThread)
3115 postExceptionFromThread(e); // Assume we're on the main thread
3117 throw new RuntimeException(e.getMessage());
3121 // m_isTransformDone = true; // android-removed
3123 if (m_inputContentHandler instanceof TransformerHandlerImpl)
3125 ((TransformerHandlerImpl) m_inputContentHandler).clearCoRoutine();
3128 // synchronized (this)
3137 // e.printStackTrace();
3138 if (null != m_transformThread)
3139 postExceptionFromThread(e);
3141 throw new RuntimeException(e.getMessage()); // Assume we're on the main thread.
3145 // Fragment re-execution interfaces for a tool.
3148 * Test whether whitespace-only text nodes are visible in the logical
3149 * view of <code>DTM</code>. Normally, this function
3150 * will be called by the implementation of <code>DTM</code>;
3151 * it is not normally called directly from
3154 * @param elementHandle int Handle of the element.
3155 * @return one of NOTSTRIP, STRIP, or INHERIT.
3157 public short getShouldStripSpace(int elementHandle, DTM dtm)
3162 org.apache.xalan.templates.WhiteSpaceInfo info =
3163 m_stylesheetRoot.getWhiteSpaceInfo(m_xcontext, elementHandle, dtm);
3167 return DTMWSFilter.INHERIT;
3172 // System.out.println("getShouldStripSpace: "+info.getShouldStripSpace());
3173 return info.getShouldStripSpace()
3174 ? DTMWSFilter.STRIP : DTMWSFilter.NOTSTRIP;
3177 catch (TransformerException se)
3179 return DTMWSFilter.INHERIT;
3183 * Initializer method.
3185 * @param transformer non-null transformer instance
3186 * @param realHandler Content Handler instance
3188 public void init(ToXMLSAXHandler h,Transformer transformer, ContentHandler realHandler)
3190 h.setTransformer(transformer);
3191 h.setContentHandler(realHandler);
3194 public void setSerializationHandler(SerializationHandler xoh)
3196 m_serializationHandler = xoh;
3202 * Fire off characters, cdate events.
3203 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, char[], int, int)
3205 public void fireGenerateEvent(
3213 * Fire off startElement, endElement events.
3214 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String, Attributes)
3216 public void fireGenerateEvent(
3223 * Fire off processingInstruction events.
3225 public void fireGenerateEvent(int eventType, String name, String data) {
3229 * Fire off comment and entity ref events.
3230 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String)
3232 public void fireGenerateEvent(int eventType, String data) {
3236 * Fire off startDocument, endDocument events.
3237 * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int)
3239 public void fireGenerateEvent(int eventType) {
3243 * @see org.apache.xml.serializer.SerializerTrace#hasTraceListeners()
3245 public boolean hasTraceListeners() {
3250 * @return Incremental flag
3252 public boolean getIncremental() {
3253 return m_incremental;
3257 * @return Optimization flag
3259 public boolean getOptimize() {
3264 * @return Source location flag
3266 public boolean getSource_location() {
3267 return m_source_location;
3270 } // end TransformerImpl class