/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: TransformerImpl.java 475979 2006-11-16 23:32:48Z minchau $ */ package org.apache.xalan.transformer; import java.io.IOException; import java.io.StringWriter; import java.util.Enumeration; import java.util.Properties; import java.util.Stack; import java.util.StringTokenizer; import java.util.Vector; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.ErrorListener; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.SourceLocator; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.apache.xalan.extensions.ExtensionsTable; import org.apache.xalan.res.XSLMessages; import org.apache.xalan.res.XSLTErrorResources; import org.apache.xml.serializer.Method; import org.apache.xml.serializer.Serializer; import org.apache.xml.serializer.SerializerFactory; import org.apache.xalan.templates.AVT; import org.apache.xalan.templates.Constants; import org.apache.xalan.templates.ElemAttributeSet; import org.apache.xalan.templates.ElemForEach; import org.apache.xalan.templates.ElemSort; import org.apache.xalan.templates.ElemTemplate; import org.apache.xalan.templates.ElemTemplateElement; import org.apache.xalan.templates.ElemTextLiteral; import org.apache.xalan.templates.ElemVariable; import org.apache.xalan.templates.OutputProperties; import org.apache.xalan.templates.Stylesheet; import org.apache.xalan.templates.StylesheetComposed; import org.apache.xalan.templates.StylesheetRoot; import org.apache.xalan.templates.XUnresolvedVariable; import org.apache.xml.dtm.DTM; import org.apache.xml.dtm.DTMIterator; import org.apache.xml.dtm.DTMManager; import org.apache.xml.dtm.DTMWSFilter; import org.apache.xml.serializer.ToSAXHandler; import org.apache.xml.serializer.ToTextStream; import org.apache.xml.serializer.ToXMLSAXHandler; import org.apache.xml.serializer.SerializationHandler; import org.apache.xml.utils.BoolStack; import org.apache.xml.utils.DOMBuilder; import org.apache.xml.utils.NodeVector; import org.apache.xml.utils.ObjectPool; import org.apache.xml.utils.ObjectStack; import org.apache.xml.utils.QName; import org.apache.xml.utils.SAXSourceLocator; import org.apache.xml.utils.ThreadControllerWrapper; import org.apache.xpath.Arg; import org.apache.xpath.ExtensionsProvider; import org.apache.xpath.VariableStack; import org.apache.xpath.XPathContext; import org.apache.xpath.functions.FuncExtFunction; import org.apache.xpath.objects.XObject; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.ext.LexicalHandler; /** * This class implements the * {@link javax.xml.transform.Transformer} interface, and is the core * representation of the transformation execution.</p> * @xsl.usage advanced */ public class TransformerImpl extends Transformer implements Runnable, DTMWSFilter, ExtensionsProvider, org.apache.xml.serializer.SerializerTrace { // Synch object to gaurd against setting values from the TrAX interface // or reentry while the transform is going on. /** NEEDSDOC Field m_reentryGuard */ private Boolean m_reentryGuard = new Boolean(true); /** * This is null unless we own the stream. */ private java.io.FileOutputStream m_outputStream = null; /** The thread that the transformer is running on. */ private Thread m_transformThread; /** The base URL of the source tree. */ private String m_urlOfSource = null; /** The Result object at the start of the transform, if any. */ private Result m_outputTarget = null; /** * The output format object set by the user. May be null. */ private OutputProperties m_outputFormat; /** * The content handler for the source input tree. */ ContentHandler m_inputContentHandler; /** * The content handler for the result tree. */ private ContentHandler m_outputContentHandler = null; // /* // * Use member variable to store param variables as they're // * being created, use member variable so we don't // * have to create a new vector every time. // */ // private Vector m_newVars = new Vector(); /** * A pool of ResultTreeHandlers, for serialization of a subtree to text. * Please note that each of these also holds onto a Text Serializer. */ private ObjectPool m_textResultHandlerObjectPool = new ObjectPool(ToTextStream.class); /** * Related to m_textResultHandlerObjectPool, this is a pool of * StringWriters, which are passed to the Text Serializers. * (I'm not sure if this is really needed any more. -sb) */ private ObjectPool m_stringWriterObjectPool = new ObjectPool(StringWriter.class); /** * A static text format object, which can be used over and * over to create the text serializers. */ private OutputProperties m_textformat = new OutputProperties(Method.TEXT); // Commenteded out in response to problem reported by // Nicola Brown <Nicola.Brown@jacobsrimell.com> // /** // * Flag to let us know if an exception should be reported inside the // * postExceptionFromThread method. This is needed if the transform is // * being generated from SAX events, and thus there is no central place // * to report the exception from. (An exception is usually picked up in // * the main thread from the transform thread in {@link #transform(Source source)} // * from {@link #getExceptionThrown()}. ) // */ // private boolean m_reportInPostExceptionFromThread = false; /** * A node vector used as a stack to track the current * ElemTemplateElement. Needed for the * org.apache.xalan.transformer.TransformState interface, * so a tool can discover the calling template. Note the use of an array * for this limits the recursion depth to 4K. */ ObjectStack m_currentTemplateElements = new ObjectStack(XPathContext.RECURSIONLIMIT); /** The top of the currentTemplateElements stack. */ //int m_currentTemplateElementsTop = 0; /** * A node vector used as a stack to track the current * ElemTemplate that was matched. * Needed for the * org.apache.xalan.transformer.TransformState interface, * so a tool can discover the matched template */ Stack m_currentMatchTemplates = new Stack(); /** * A node vector used as a stack to track the current * node that was matched. * Needed for the * org.apache.xalan.transformer.TransformState interface, * so a tool can discover the matched * node. */ NodeVector m_currentMatchedNodes = new NodeVector(); /** * The root of a linked set of stylesheets. */ private StylesheetRoot m_stylesheetRoot = null; /** * If this is set to true, do not warn about pattern * match conflicts. */ private boolean m_quietConflictWarnings = true; /** * The liason to the XML parser, so the XSL processor * can handle included files, and the like, and do the * initial parse of the XSL document. */ private XPathContext m_xcontext; /** * Output handler to bottleneck SAX events. */ private SerializationHandler m_serializationHandler; /** The key manager, which manages xsl:keys. */ private KeyManager m_keyManager = new KeyManager(); /** * Stack for the purposes of flagging infinite recursion with * attribute sets. */ Stack m_attrSetStack = null; /** * The table of counters for xsl:number support. */ CountersTable m_countersTable = null; /** * Is > 0 when we're processing a for-each. */ BoolStack m_currentTemplateRuleIsNull = new BoolStack(); /** * Keeps track of the result delivered by any EXSLT <code>func:result</code> * instruction that has been executed for the currently active EXSLT * <code>func:function</code> */ ObjectStack m_currentFuncResult = new ObjectStack(); /** * The message manager, which manages error messages, warning * messages, and other types of message events. */ private MsgMgr m_msgMgr; /** * The flag for the setting of the optimize feature; * This flag should have the same value as the FEATURE_OPTIMIZE feature * which is set by the TransformerFactory.setAttribut() method before a * Transformer is created */ private boolean m_optimizer = true; /** * The flag for the setting of the incremental feature; * This flag should have the same value as the FEATURE_INCREMENTAL feature * which is set by the TransformerFactory.setAttribut() method before a * Transformer is created */ private boolean m_incremental = false; /** * The flag for the setting of the source_location feature; * This flag should have the same value as the FEATURE_SOURCE_LOCATION feature * which is set by the TransformerFactory.setAttribut() method before a * Transformer is created */ private boolean m_source_location = false; /** * The SAX error handler, where errors and warnings are sent. */ private ErrorListener m_errorHandler = new org.apache.xml.utils.DefaultErrorHandler(false); /** * If the transform thread throws an exception, the exception needs to * be stashed away so that the main thread can pass it on to the * client. */ private Exception m_exceptionThrown = null; /** * This is needed for support of setSourceTreeDocForThread(Node doc), * which must be called in order for the transform thread's run * method to obtain the root of the source tree to be transformed. */ private int m_doc; /** Flag to to tell if the tranformer needs to be reset. */ private boolean m_hasBeenReset = false; /** NEEDSDOC Field m_shouldReset */ private boolean m_shouldReset = true; /** * A stack of current template modes. */ private Stack m_modes = new Stack(); //========================================================== // SECTION: Constructor //========================================================== /** * Construct a TransformerImpl. * * @param stylesheet The root of the stylesheet tree. */ public TransformerImpl(StylesheetRoot stylesheet) // throws javax.xml.transform.TransformerException { m_optimizer = stylesheet.getOptimizer(); m_incremental = stylesheet.getIncremental(); m_source_location = stylesheet.getSource_location(); setStylesheet(stylesheet); XPathContext xPath = new XPathContext(this); xPath.setIncremental(m_incremental); xPath.getDTMManager().setIncremental(m_incremental); xPath.setSource_location(m_source_location); xPath.getDTMManager().setSource_location(m_source_location); if (stylesheet.isSecureProcessing()) xPath.setSecureProcessing(true); setXPathContext(xPath); getXPathContext().setNamespaceContext(stylesheet); } // ================ ExtensionsTable =================== /** * The table of ExtensionHandlers. */ private ExtensionsTable m_extensionsTable = null; /** * Get the extensions table object. * * @return The extensions table. */ public ExtensionsTable getExtensionsTable() { return m_extensionsTable; } /** * If the stylesheet contains extensions, set the extensions table object. * * * @param sroot The stylesheet. * @throws javax.xml.transform.TransformerException */ void setExtensionsTable(StylesheetRoot sroot) throws javax.xml.transform.TransformerException { try { if (sroot.getExtensions() != null) //only load extensions if secureProcessing is disabled if(!sroot.isSecureProcessing()) m_extensionsTable = new ExtensionsTable(sroot); } catch (javax.xml.transform.TransformerException te) {te.printStackTrace();} } //== Implementation of the XPath ExtensionsProvider interface. public boolean functionAvailable(String ns, String funcName) throws javax.xml.transform.TransformerException { return getExtensionsTable().functionAvailable(ns, funcName); } public boolean elementAvailable(String ns, String elemName) throws javax.xml.transform.TransformerException { return getExtensionsTable().elementAvailable(ns, elemName); } public Object extFunction(String ns, String funcName, Vector argVec, Object methodKey) throws javax.xml.transform.TransformerException {//System.out.println("TransImpl.extFunction() " + ns + " " + funcName +" " + getExtensionsTable()); return getExtensionsTable().extFunction(ns, funcName, argVec, methodKey, getXPathContext().getExpressionContext()); } public Object extFunction(FuncExtFunction extFunction, Vector argVec) throws javax.xml.transform.TransformerException { return getExtensionsTable().extFunction(extFunction, argVec, getXPathContext().getExpressionContext()); } //========================= /** * Reset the state. This needs to be called after a process() call * is invoked, if the processor is to be used again. */ public void reset() { if (!m_hasBeenReset && m_shouldReset) { m_hasBeenReset = true; if (this.m_outputStream != null) { try { m_outputStream.close(); } catch (java.io.IOException ioe){} } m_outputStream = null; // I need to look more carefully at which of these really // needs to be reset. m_countersTable = null; m_xcontext.reset(); m_xcontext.getVarStack().reset(); resetUserParameters(); m_currentTemplateElements.removeAllElements(); m_currentMatchTemplates.removeAllElements(); m_currentMatchedNodes.removeAllElements(); m_serializationHandler = null; m_outputTarget = null; m_keyManager = new KeyManager(); m_attrSetStack = null; m_countersTable = null; m_currentTemplateRuleIsNull = new BoolStack(); // m_xmlSource = null; // android-removed m_doc = DTM.NULL; // m_isTransformDone = false; // android-removed m_transformThread = null; // m_inputContentHandler = null; // For now, reset the document cache each time. m_xcontext.getSourceTreeManager().reset(); } // m_reportInPostExceptionFromThread = false; } // ========= Transformer Interface Implementation ========== /** * Get the thread that the transform process is on. * * @return The thread that the transform process is on, or null. * @xsl.usage internal */ public Thread getTransformThread() { return m_transformThread; } /** * Get the thread that the transform process is on. * * @param t The transform thread, may be null. * @xsl.usage internal */ public void setTransformThread(Thread t) { m_transformThread = t; } /** NEEDSDOC Field m_hasTransformThreadErrorCatcher */ private boolean m_hasTransformThreadErrorCatcher = false; /** * Return true if the transform was initiated from the transform method, * otherwise it was probably done from a pure parse events. * * NEEDSDOC ($objectName$) @return */ public boolean hasTransformThreadErrorCatcher() { return m_hasTransformThreadErrorCatcher; } /** * Process the source tree to SAX parse events. * @param source The input for the source tree. * * @throws TransformerException */ public void transform(Source source) throws TransformerException { transform(source, true); } /** * Process the source tree to SAX parse events. * @param source The input for the source tree. * @param shouldRelease Flag indicating whether to release DTMManager. * * @throws TransformerException */ public void transform(Source source, boolean shouldRelease) throws TransformerException { try { // Patch for bugzilla #13863. If we don't reset the namespaceContext // then we will get a NullPointerException if transformer is reused // (for stylesheets that use xsl:key). Not sure if this should go // here or in reset(). -is if(getXPathContext().getNamespaceContext() == null){ getXPathContext().setNamespaceContext(getStylesheet()); } String base = source.getSystemId(); // If no systemID of the source, use the base of the stylesheet. if(null == base) { base = m_stylesheetRoot.getBaseIdentifier(); } // As a last resort, use the current user dir. if(null == base) { String currentDir = ""; try { currentDir = System.getProperty("user.dir"); } catch (SecurityException se) {}// user.dir not accessible from applet if (currentDir.startsWith(java.io.File.separator)) base = "file://" + currentDir; else base = "file:///" + currentDir; base = base + java.io.File.separatorChar + source.getClass().getName(); } setBaseURLOfSource(base); DTMManager mgr = m_xcontext.getDTMManager(); /* * According to JAXP1.2, new SAXSource()/StreamSource() * should create an empty input tree, with a default root node. * new DOMSource()creates an empty document using DocumentBuilder. * newDocument(); Use DocumentBuilder.newDocument() for all 3 situations, * since there is no clear spec. how to create an empty tree when * both SAXSource() and StreamSource() are used. */ if ((source instanceof StreamSource && source.getSystemId()==null && ((StreamSource)source).getInputStream()==null && ((StreamSource)source).getReader()==null)|| (source instanceof SAXSource && ((SAXSource)source).getInputSource()==null && ((SAXSource)source).getXMLReader()==null )|| (source instanceof DOMSource && ((DOMSource)source).getNode()==null)){ try { DocumentBuilderFactory builderF = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = builderF.newDocumentBuilder(); String systemID = source.getSystemId(); source = new DOMSource(builder.newDocument()); // Copy system ID from original, empty Source to new Source if (systemID != null) { source.setSystemId(systemID); } } catch (ParserConfigurationException e) { fatalError(e); } } DTM dtm = mgr.getDTM(source, false, this, true, true); dtm.setDocumentBaseURI(base); boolean hardDelete = true; // %REVIEW% I have to think about this. -sb try { // NOTE: This will work because this is _NOT_ a shared DTM, and thus has // only a single Document node. If it could ever be an RTF or other // shared DTM, look at dtm.getDocumentRoot(nodeHandle). this.transformNode(dtm.getDocument()); } finally { if (shouldRelease) mgr.release(dtm, hardDelete); } // Kick off the parse. When the ContentHandler gets // the startDocument event, it will call transformNode( node ). // reader.parse( xmlSource ); // This has to be done to catch exceptions thrown from // the transform thread spawned by the STree handler. Exception e = getExceptionThrown(); if (null != e) { if (e instanceof javax.xml.transform.TransformerException) { throw (javax.xml.transform.TransformerException) e; } else if (e instanceof org.apache.xml.utils.WrappedRuntimeException) { fatalError( ((org.apache.xml.utils.WrappedRuntimeException) e).getException()); } else { throw new javax.xml.transform.TransformerException(e); } } else if (null != m_serializationHandler) { m_serializationHandler.endDocument(); } } catch (org.apache.xml.utils.WrappedRuntimeException wre) { Throwable throwable = wre.getException(); while (throwable instanceof org.apache.xml.utils.WrappedRuntimeException) { throwable = ((org.apache.xml.utils.WrappedRuntimeException) throwable).getException(); } fatalError(throwable); } // Patch attributed to David Eisenberg <david@catcode.com> catch (org.xml.sax.SAXParseException spe) { fatalError(spe); } catch (org.xml.sax.SAXException se) { m_errorHandler.fatalError(new TransformerException(se)); } finally { m_hasTransformThreadErrorCatcher = false; // This looks to be redundent to the one done in TransformNode. reset(); } } private void fatalError(Throwable throwable) throws TransformerException { if (throwable instanceof org.xml.sax.SAXParseException) m_errorHandler.fatalError(new TransformerException(throwable.getMessage(),new SAXSourceLocator((org.xml.sax.SAXParseException)throwable))); else m_errorHandler.fatalError(new TransformerException(throwable)); } /** * Get the base URL of the source. * * * NEEDSDOC @param base * @return The base URL of the source tree, or null. */ public void setBaseURLOfSource(String base) { m_urlOfSource = base; } /** * Get an output property that is in effect for the * transformation. The property specified may be a property * that was set with setOutputProperty, or it may be a * property specified in the stylesheet. * * NEEDSDOC @param qnameString * * @return The string value of the output property, or null * if no property was found. * * @throws IllegalArgumentException If the property is not supported. * * @see javax.xml.transform.OutputKeys */ public String getOutputProperty(String qnameString) throws IllegalArgumentException { String value = null; OutputProperties props = getOutputFormat(); value = props.getProperty(qnameString); if (null == value) { if (!OutputProperties.isLegalPropertyKey(qnameString)) throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: " //+ qnameString); } return value; } /** * Get the value of a property, without using the default properties. This * can be used to test if a property has been explicitly set by the stylesheet * or user. * * NEEDSDOC @param qnameString * * @return The value of the property, or null if not found. * * @throws IllegalArgumentException If the property is not supported, * and is not namespaced. */ public String getOutputPropertyNoDefault(String qnameString) throws IllegalArgumentException { String value = null; OutputProperties props = getOutputFormat(); value = (String) props.getProperties().get(qnameString); if (null == value) { if (!OutputProperties.isLegalPropertyKey(qnameString)) throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: " // + qnameString); } return value; } /** * This method is used to set or override the value * of the effective xsl:output attribute values * specified in the stylesheet. * <p> * The recognized standard output properties are: * <ul> * <li>cdata-section-elements * <li>doctype-system * <li>doctype-public * <li>indent * <li>media-type * <li>method * <li>omit-xml-declaration * <li>standalone * <li>version * </ul> * <p> * For example: * <pre> * tran.setOutputProperty("standalone", "yes"); * </pre> * <p> * In the case of the cdata-section-elements property, * the value should be a whitespace separated list of * element names. The element name is the local name * of the element, if it is in no namespace, or, the URI * in braces followed immediately by the local name * if the element is in that namespace. For example: * <pre> * tran.setOutputProperty( * "cdata-section-elements", * "elem1 {http://example.uri}elem2 elem3"); * </pre> * <p> * The recognized Xalan extension elements are: * <ul> * <li>content-handler * <li>entities * <li>indent-amount * <li>line-separator * <li>omit-meta-tag * <li>use-url-escaping * </ul> * <p> * These must be in the extension namespace of * "http://xml.apache.org/xalan". This is accomplished * by putting the namespace URI in braces before the * property name, for example: * <pre> * tran.setOutputProperty( * "{http://xml.apache.org/xalan}line-separator" , * "\n"); * </pre> * * @param name The property name. * @param value The requested value for the property. * @throws IllegalArgumentException if the property name is not legal. */ public void setOutputProperty(String name, String value) throws IllegalArgumentException { synchronized (m_reentryGuard) { // Get the output format that was set by the user, otherwise get the // output format from the stylesheet. if (null == m_outputFormat) { m_outputFormat = (OutputProperties) getStylesheet().getOutputComposed().clone(); } if (!OutputProperties.isLegalPropertyKey(name)) throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{name})); //"output property not recognized: " //+ name); m_outputFormat.setProperty(name, value); } } /** * Set the output properties for the transformation. These * properties will override properties set in the templates * with xsl:output. * * <p>If argument to this function is null, any properties * previously set will be removed.</p> * * @param oformat A set of output properties that will be * used to override any of the same properties in effect * for the transformation. * * @see javax.xml.transform.OutputKeys * @see java.util.Properties * * @throws IllegalArgumentException if any of the argument keys are not * recognized and are not namespace qualified. */ public void setOutputProperties(Properties oformat) throws IllegalArgumentException { synchronized (m_reentryGuard) { if (null != oformat) { // See if an *explicit* method was set. String method = (String) oformat.get(OutputKeys.METHOD); if (null != method) m_outputFormat = new OutputProperties(method); else if(m_outputFormat==null) m_outputFormat = new OutputProperties(); m_outputFormat.copyFrom(oformat); // copyFrom does not set properties that have been already set, so // this must be called after, which is a bit in the reverse from // what one might think. m_outputFormat.copyFrom(m_stylesheetRoot.getOutputProperties()); } else { // if oformat is null JAXP says that any props previously set are removed // and we are to revert back to those in the templates object (i.e. Stylesheet). m_outputFormat = null; } } } /** * Get a copy of the output properties for the transformation. These * properties will override properties set in the templates * with xsl:output. * * <p>Note that mutation of the Properties object returned will not * effect the properties that the transformation contains.</p> * * @return A copy of the set of output properties in effect * for the next transformation. * * NEEDSDOC ($objectName$) @return */ public Properties getOutputProperties() { return (Properties) getOutputFormat().getProperties().clone(); } /** * Create a result ContentHandler from a Result object, based * on the current OutputProperties. * * @param outputTarget Where the transform result should go, * should not be null. * * @return A valid ContentHandler that will create the * result tree when it is fed SAX events. * * @throws TransformerException */ public SerializationHandler createSerializationHandler(Result outputTarget) throws TransformerException { SerializationHandler xoh = createSerializationHandler(outputTarget, getOutputFormat()); return xoh; } /** * Create a ContentHandler from a Result object and an OutputProperties. * * @param outputTarget Where the transform result should go, * should not be null. * @param format The OutputProperties object that will contain * instructions on how to serialize the output. * * @return A valid ContentHandler that will create the * result tree when it is fed SAX events. * * @throws TransformerException */ public SerializationHandler createSerializationHandler( Result outputTarget, OutputProperties format) throws TransformerException { SerializationHandler xoh; // If the Result object contains a Node, then create // a ContentHandler that will add nodes to the input node. org.w3c.dom.Node outputNode = null; if (outputTarget instanceof DOMResult) { outputNode = ((DOMResult) outputTarget).getNode(); org.w3c.dom.Node nextSibling = ((DOMResult)outputTarget).getNextSibling(); org.w3c.dom.Document doc; short type; if (null != outputNode) { type = outputNode.getNodeType(); doc = (org.w3c.dom.Node.DOCUMENT_NODE == type) ? (org.w3c.dom.Document) outputNode : outputNode.getOwnerDocument(); } else { boolean isSecureProcessing = m_stylesheetRoot.isSecureProcessing(); doc = org.apache.xml.utils.DOMHelper.createDocument(isSecureProcessing); outputNode = doc; type = outputNode.getNodeType(); ((DOMResult) outputTarget).setNode(outputNode); } DOMBuilder handler = (org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE == type) ? new DOMBuilder(doc, (org.w3c.dom.DocumentFragment) outputNode) : new DOMBuilder(doc, outputNode); if (nextSibling != null) handler.setNextSibling(nextSibling); String encoding = format.getProperty(OutputKeys.ENCODING); xoh = new ToXMLSAXHandler(handler, (LexicalHandler)handler, encoding); } else if (outputTarget instanceof SAXResult) { ContentHandler handler = ((SAXResult) outputTarget).getHandler(); if (null == handler) throw new IllegalArgumentException( "handler can not be null for a SAXResult"); LexicalHandler lexHandler; if (handler instanceof LexicalHandler) lexHandler = (LexicalHandler) handler; else lexHandler = null; String encoding = format.getProperty(OutputKeys.ENCODING); String method = format.getProperty(OutputKeys.METHOD); ToXMLSAXHandler toXMLSAXHandler = new ToXMLSAXHandler(handler, lexHandler, encoding); toXMLSAXHandler.setShouldOutputNSAttr(false); xoh = toXMLSAXHandler; String publicID = format.getProperty(OutputKeys.DOCTYPE_PUBLIC); String systemID = format.getProperty(OutputKeys.DOCTYPE_SYSTEM); if (systemID != null) xoh.setDoctypeSystem(systemID); if (publicID != null) xoh.setDoctypePublic(publicID); if (handler instanceof TransformerClient) { XalanTransformState state = new XalanTransformState(); ((TransformerClient)handler).setTransformState(state); ((ToSAXHandler)xoh).setTransformState(state); } } // Otherwise, create a ContentHandler that will serialize the // result tree to either a stream or a writer. else if (outputTarget instanceof StreamResult) { StreamResult sresult = (StreamResult) outputTarget; try { SerializationHandler serializer = (SerializationHandler) SerializerFactory.getSerializer(format.getProperties()); if (null != sresult.getWriter()) serializer.setWriter(sresult.getWriter()); else if (null != sresult.getOutputStream()) serializer.setOutputStream(sresult.getOutputStream()); else if (null != sresult.getSystemId()) { String fileURL = sresult.getSystemId(); if (fileURL.startsWith("file:///")) { if (fileURL.substring(8).indexOf(":") >0) fileURL = fileURL.substring(8); else fileURL = fileURL.substring(7); } else if (fileURL.startsWith("file:/")) { if (fileURL.substring(6).indexOf(":") >0) fileURL = fileURL.substring(6); else fileURL = fileURL.substring(5); } m_outputStream = new java.io.FileOutputStream(fileURL); serializer.setOutputStream(m_outputStream); xoh = serializer; } else throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_OUTPUT_SPECIFIED, null)); //"No output specified!"); // handler = serializer.asContentHandler(); // this.setSerializer(serializer); xoh = serializer; } // catch (UnsupportedEncodingException uee) // { // throw new TransformerException(uee); // } catch (IOException ioe) { throw new TransformerException(ioe); } } else { 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 " //+ outputTarget.getClass().getName() //+ "!"); } // before we forget, lets make the created handler hold a reference // to the current TransformImpl object xoh.setTransformer(this); SourceLocator srcLocator = getStylesheet(); xoh.setSourceLocator(srcLocator); return xoh; } /** * Process the source tree to the output result. * @param xmlSource The input for the source tree. * @param outputTarget The output source target. * * @throws TransformerException */ public void transform(Source xmlSource, Result outputTarget) throws TransformerException { transform(xmlSource, outputTarget, true); } /** * Process the source tree to the output result. * @param xmlSource The input for the source tree. * @param outputTarget The output source target. * @param shouldRelease Flag indicating whether to release DTMManager. * * @throws TransformerException */ public void transform(Source xmlSource, Result outputTarget, boolean shouldRelease) throws TransformerException { synchronized (m_reentryGuard) { SerializationHandler xoh = createSerializationHandler(outputTarget); this.setSerializationHandler(xoh); m_outputTarget = outputTarget; transform(xmlSource, shouldRelease); } } /** * Process the source node to the output result, if the * processor supports the "http://xml.org/trax/features/dom/input" * feature. * %REVIEW% Do we need a Node version of this? * @param node The input source node, which can be any valid DTM node. * @param outputTarget The output source target. * * @throws TransformerException */ public void transformNode(int node, Result outputTarget) throws TransformerException { SerializationHandler xoh = createSerializationHandler(outputTarget); this.setSerializationHandler(xoh); m_outputTarget = outputTarget; transformNode(node); } /** * Process the source node to the output result, if the * processor supports the "http://xml.org/trax/features/dom/input" * feature. * %REVIEW% Do we need a Node version of this? * @param node The input source node, which can be any valid DTM node. * * @throws TransformerException */ public void transformNode(int node) throws TransformerException { //dml setExtensionsTable(getStylesheet()); // Make sure we're not writing to the same output content handler. synchronized (m_serializationHandler) { m_hasBeenReset = false; XPathContext xctxt = getXPathContext(); DTM dtm = xctxt.getDTM(node); try { pushGlobalVars(node); // ========== // Give the top-level templates a chance to pass information into // the context (this is mainly for setting up tables for extensions). StylesheetRoot stylesheet = this.getStylesheet(); int n = stylesheet.getGlobalImportCount(); for (int i = 0; i < n; i++) { StylesheetComposed imported = stylesheet.getGlobalImport(i); int includedCount = imported.getIncludeCountComposed(); for (int j = -1; j < includedCount; j++) { Stylesheet included = imported.getIncludeComposed(j); included.runtimeInit(this); for (ElemTemplateElement child = included.getFirstChildElem(); child != null; child = child.getNextSiblingElem()) { child.runtimeInit(this); } } } // =========== // System.out.println("Calling applyTemplateToNode - "+Thread.currentThread().getName()); DTMIterator dtmIter = new org.apache.xpath.axes.SelfIteratorNoPredicate(); dtmIter.setRoot(node, xctxt); xctxt.pushContextNodeList(dtmIter); try { this.applyTemplateToNode(null, null, node); } finally { xctxt.popContextNodeList(); } // m_stylesheetRoot.getStartRule().execute(this); // System.out.println("Done with applyTemplateToNode - "+Thread.currentThread().getName()); if (null != m_serializationHandler) { m_serializationHandler.endDocument(); } } catch (Exception se) { // System.out.println(Thread.currentThread().getName()+" threw an exception! " // +se.getMessage()); // If an exception was thrown, we need to make sure that any waiting // handlers can terminate, which I guess is best done by sending // an endDocument. // SAXSourceLocator while(se instanceof org.apache.xml.utils.WrappedRuntimeException) { Exception e = ((org.apache.xml.utils.WrappedRuntimeException)se).getException(); if(null != e) se = e; } if (null != m_serializationHandler) { try { if(se instanceof org.xml.sax.SAXParseException) m_serializationHandler.fatalError((org.xml.sax.SAXParseException)se); else if(se instanceof TransformerException) { TransformerException te = ((TransformerException)se); SAXSourceLocator sl = new SAXSourceLocator( te.getLocator() ); m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(te.getMessage(), sl, te)); } else { m_serializationHandler.fatalError(new org.xml.sax.SAXParseException(se.getMessage(), new SAXSourceLocator(), se)); } } catch (Exception e){} } if(se instanceof TransformerException) { m_errorHandler.fatalError((TransformerException)se); } else if(se instanceof org.xml.sax.SAXParseException) { m_errorHandler.fatalError(new TransformerException(se.getMessage(), new SAXSourceLocator((org.xml.sax.SAXParseException)se), se)); } else { m_errorHandler.fatalError(new TransformerException(se)); } } finally { this.reset(); } } } /** * Get a SAX2 ContentHandler for the input. * * @return A valid ContentHandler, which should never be null, as * long as getFeature("http://xml.org/trax/features/sax/input") * returns true. */ public ContentHandler getInputContentHandler() { return getInputContentHandler(false); } /** * Get a SAX2 ContentHandler for the input. * * @param doDocFrag true if a DocumentFragment should be created as * the root, rather than a Document. * * @return A valid ContentHandler, which should never be null, as * long as getFeature("http://xml.org/trax/features/sax/input") * returns true. */ public ContentHandler getInputContentHandler(boolean doDocFrag) { if (null == m_inputContentHandler) { // if(null == m_urlOfSource && null != m_stylesheetRoot) // m_urlOfSource = m_stylesheetRoot.getBaseIdentifier(); m_inputContentHandler = new TransformerHandlerImpl(this, doDocFrag, m_urlOfSource); } return m_inputContentHandler; } /** * Set the output properties for the transformation. These * properties will override properties set in the templates * with xsl:output. * * @param oformat A valid OutputProperties object (which will * not be mutated), or null. */ public void setOutputFormat(OutputProperties oformat) { m_outputFormat = oformat; } /** * Get the output properties used for the transformation. * * @return the output format that was set by the user, * otherwise the output format from the stylesheet. */ public OutputProperties getOutputFormat() { // Get the output format that was set by the user, otherwise get the // output format from the stylesheet. OutputProperties format = (null == m_outputFormat) ? getStylesheet().getOutputComposed() : m_outputFormat; return format; } /** * Set a parameter for the templates. * * @param name The name of the parameter. * @param namespace The namespace of the parameter. * @param value The value object. This can be any valid Java object * -- it's up to the processor to provide the proper * coersion to the object, or simply pass it on for use * in extensions. */ public void setParameter(String name, String namespace, Object value) { VariableStack varstack = getXPathContext().getVarStack(); QName qname = new QName(namespace, name); XObject xobject = XObject.create(value, getXPathContext()); StylesheetRoot sroot = m_stylesheetRoot; Vector vars = sroot.getVariablesAndParamsComposed(); int i = vars.size(); while (--i >= 0) { ElemVariable variable = (ElemVariable)vars.elementAt(i); if(variable.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE && variable.getName().equals(qname)) { varstack.setGlobalVariable(i, xobject); } } } /** NEEDSDOC Field m_userParams */ Vector m_userParams; /** * Set a parameter for the transformation. * * @param name The name of the parameter, * which may have a namespace URI. * @param value The value object. This can be any valid Java object * -- it's up to the processor to provide the proper * coersion to the object, or simply pass it on for use * in extensions. */ public void setParameter(String name, Object value) { if (value == null) { throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_INVALID_SET_PARAM_VALUE, new Object[]{name})); } StringTokenizer tokenizer = new StringTokenizer(name, "{}", false); try { // The first string might be the namespace, or it might be // the local name, if the namespace is null. String s1 = tokenizer.nextToken(); String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null; if (null == m_userParams) m_userParams = new Vector(); if (null == s2) { replaceOrPushUserParam(new QName(s1), XObject.create(value, getXPathContext())); setParameter(s1, null, value); } else { replaceOrPushUserParam(new QName(s1, s2), XObject.create(value, getXPathContext())); setParameter(s2, s1, value); } } catch (java.util.NoSuchElementException nsee) { // Should throw some sort of an error. } } /** * NEEDSDOC Method replaceOrPushUserParam * * * NEEDSDOC @param qname * NEEDSDOC @param xval */ private void replaceOrPushUserParam(QName qname, XObject xval) { int n = m_userParams.size(); for (int i = n - 1; i >= 0; i--) { Arg arg = (Arg) m_userParams.elementAt(i); if (arg.getQName().equals(qname)) { m_userParams.setElementAt(new Arg(qname, xval, true), i); return; } } m_userParams.addElement(new Arg(qname, xval, true)); } /** * Get a parameter that was explicitly set with setParameter * or setParameters. * * * NEEDSDOC @param name * @return A parameter that has been set with setParameter * or setParameters, * *not* all the xsl:params on the stylesheet (which require * a transformation Source to be evaluated). */ public Object getParameter(String name) { try { // VariableStack varstack = getXPathContext().getVarStack(); // The first string might be the namespace, or it might be // the local name, if the namespace is null. QName qname = QName.getQNameFromString(name); if (null == m_userParams) return null; int n = m_userParams.size(); for (int i = n - 1; i >= 0; i--) { Arg arg = (Arg) m_userParams.elementAt(i); if (arg.getQName().equals(qname)) { return arg.getVal().object(); } } return null; } catch (java.util.NoSuchElementException nsee) { // Should throw some sort of an error. return null; } } /** * Reset parameters that the user specified for the transformation. * Called during transformer.reset() after we have cleared the * variable stack. We need to make sure that user params are * reset so that the transformer object can be reused. */ private void resetUserParameters() { try { if (null == m_userParams) return; int n = m_userParams.size(); for (int i = n - 1; i >= 0; i--) { Arg arg = (Arg) m_userParams.elementAt(i); QName name = arg.getQName(); // The first string might be the namespace, or it might be // the local name, if the namespace is null. String s1 = name.getNamespace(); String s2 = name.getLocalPart(); setParameter(s2, s1, arg.getVal().object()); } } catch (java.util.NoSuchElementException nsee) { // Should throw some sort of an error. } } /** * Set a bag of parameters for the transformation. Note that * these will not be additive, they will replace the existing * set of parameters. * * NEEDSDOC @param params */ public void setParameters(Properties params) { clearParameters(); Enumeration names = params.propertyNames(); while (names.hasMoreElements()) { String name = params.getProperty((String) names.nextElement()); StringTokenizer tokenizer = new StringTokenizer(name, "{}", false); try { // The first string might be the namespace, or it might be // the local name, if the namespace is null. String s1 = tokenizer.nextToken(); String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken() : null; if (null == s2) setParameter(s1, null, params.getProperty(name)); else setParameter(s2, s1, params.getProperty(name)); } catch (java.util.NoSuchElementException nsee) { // Should throw some sort of an error. } } } /** * Reset the parameters to a null list. */ public void clearParameters() { synchronized (m_reentryGuard) { VariableStack varstack = new VariableStack(); m_xcontext.setVarStack(varstack); m_userParams = null; } } /** * Internal -- push the global variables from the Stylesheet onto * the context's runtime variable stack. * <p>If we encounter a variable * that is already defined in the variable stack, we ignore it. This * is because the second variable definition will be at a lower import * precedence. Presumably, global"variables at the same import precedence * with the same name will have been caught during the recompose process. * <p>However, if we encounter a parameter that is already defined in the * variable stack, we need to see if this is a parameter whose value was * supplied by a setParameter call. If so, we need to "receive" the one * already in the stack, ignoring this one. If it is just an earlier * xsl:param or xsl:variable definition, we ignore it using the same * reasoning as explained above for the variable. * * @param contextNode The root of the source tree, can't be null. * * @throws TransformerException */ protected void pushGlobalVars(int contextNode) throws TransformerException { XPathContext xctxt = m_xcontext; VariableStack vs = xctxt.getVarStack(); StylesheetRoot sr = getStylesheet(); Vector vars = sr.getVariablesAndParamsComposed(); int i = vars.size(); vs.link(i); while (--i >= 0) { ElemVariable v = (ElemVariable) vars.elementAt(i); // XObject xobj = v.getValue(this, contextNode); XObject xobj = new XUnresolvedVariable(v, contextNode, this, vs.getStackFrame(), 0, true); if(null == vs.elementAt(i)) vs.setGlobalVariable(i, xobj); } } /** * Set an object that will be used to resolve URIs used in * document(), etc. * @param resolver An object that implements the URIResolver interface, * or null. */ public void setURIResolver(URIResolver resolver) { synchronized (m_reentryGuard) { m_xcontext.getSourceTreeManager().setURIResolver(resolver); } } /** * Get an object that will be used to resolve URIs used in * document(), etc. * * @return An object that implements the URIResolver interface, * or null. */ public URIResolver getURIResolver() { return m_xcontext.getSourceTreeManager().getURIResolver(); } // ======== End Transformer Implementation ======== /** * Set the content event handler. * * NEEDSDOC @param handler * @throws java.lang.NullPointerException If the handler * is null. * @see org.xml.sax.XMLReader#setContentHandler */ public void setContentHandler(ContentHandler handler) { if (handler == null) { throw new NullPointerException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_CONTENT_HANDLER, null)); //"Null content handler"); } else { m_outputContentHandler = handler; if (null == m_serializationHandler) { ToXMLSAXHandler h = new ToXMLSAXHandler(); h.setContentHandler(handler); h.setTransformer(this); m_serializationHandler = h; } else m_serializationHandler.setContentHandler(handler); } } /** * Get the content event handler. * * @return The current content handler, or null if none was set. * @see org.xml.sax.XMLReader#getContentHandler */ public ContentHandler getContentHandler() { return m_outputContentHandler; } /** * Given a stylesheet element, create a result tree fragment from it's * contents. The fragment will be built within the shared RTF DTM system * used as a variable stack. * @param templateParent The template element that holds the fragment. * @return the NodeHandle for the root node of the resulting RTF. * * @throws TransformerException * @xsl.usage advanced */ public int transformToRTF(ElemTemplateElement templateParent) throws TransformerException { // Retrieve a DTM to contain the RTF. At this writing, this may be a // multi-document DTM (SAX2RTFDTM). DTM dtmFrag = m_xcontext.getRTFDTM(); return transformToRTF(templateParent,dtmFrag); } /** * Given a stylesheet element, create a result tree fragment from it's * contents. The fragment will also use the shared DTM system, but will * obtain its space from the global variable pool rather than the dynamic * variable stack. This allows late binding of XUnresolvedVariables without * the risk that their content will be discarded when the variable stack * is popped. * * @param templateParent The template element that holds the fragment. * @return the NodeHandle for the root node of the resulting RTF. * * @throws TransformerException * @xsl.usage advanced */ public int transformToGlobalRTF(ElemTemplateElement templateParent) throws TransformerException { // Retrieve a DTM to contain the RTF. At this writing, this may be a // multi-document DTM (SAX2RTFDTM). DTM dtmFrag = m_xcontext.getGlobalRTFDTM(); return transformToRTF(templateParent,dtmFrag); } /** * Given a stylesheet element, create a result tree fragment from it's * contents. * @param templateParent The template element that holds the fragment. * @param dtmFrag The DTM to write the RTF into * @return the NodeHandle for the root node of the resulting RTF. * * @throws TransformerException * @xsl.usage advanced */ private int transformToRTF(ElemTemplateElement templateParent,DTM dtmFrag) throws TransformerException { XPathContext xctxt = m_xcontext; ContentHandler rtfHandler = dtmFrag.getContentHandler(); // Obtain the ResultTreeFrag's root node. // NOTE: In SAX2RTFDTM, this value isn't available until after // the startDocument has been issued, so assignment has been moved // down a bit in the code. int resultFragment; // not yet reliably = dtmFrag.getDocument(); // Save the current result tree handler. SerializationHandler savedRTreeHandler = this.m_serializationHandler; // And make a new handler for the RTF. ToSAXHandler h = new ToXMLSAXHandler(); h.setContentHandler(rtfHandler); h.setTransformer(this); // Replace the old handler (which was already saved) m_serializationHandler = h; // use local variable for the current handler SerializationHandler rth = m_serializationHandler; try { rth.startDocument(); // startDocument is "bottlenecked" in RTH. We need it acted upon immediately, // to set the DTM's state as in-progress, so that if the xsl:variable's body causes // further RTF activity we can keep that from bashing this DTM. rth.flushPending(); try { // Do the transformation of the child elements. executeChildTemplates(templateParent, true); // Make sure everything is flushed! rth.flushPending(); // Get the document ID. May not exist until the RTH has not only // received, but flushed, the startDocument, and may be invalid // again after the document has been closed (still debating that) // ... so waiting until just before the end seems simplest/safest. resultFragment = dtmFrag.getDocument(); } finally { rth.endDocument(); } } catch (org.xml.sax.SAXException se) { throw new TransformerException(se); } finally { // Restore the previous result tree handler. this.m_serializationHandler = savedRTreeHandler; } return resultFragment; } /** * Take the contents of a template element, process it, and * convert it to a string. * * @param elem The parent element whose children will be output * as a string. * * @return The stringized result of executing the elements children. * * @throws TransformerException * @xsl.usage advanced */ public String transformToString(ElemTemplateElement elem) throws TransformerException { ElemTemplateElement firstChild = elem.getFirstChildElem(); if(null == firstChild) return ""; if(elem.hasTextLitOnly() && m_optimizer) { return ((ElemTextLiteral)firstChild).getNodeValue(); } // Save the current result tree handler. SerializationHandler savedRTreeHandler = this.m_serializationHandler; // Create a Serializer object that will handle the SAX events // and build the ResultTreeFrag nodes. StringWriter sw = (StringWriter) m_stringWriterObjectPool.getInstance(); m_serializationHandler = (ToTextStream) m_textResultHandlerObjectPool.getInstance(); if (null == m_serializationHandler) { // if we didn't get one from the pool, go make a new one Serializer serializer = org.apache.xml.serializer.SerializerFactory.getSerializer( m_textformat.getProperties()); m_serializationHandler = (SerializationHandler) serializer; } m_serializationHandler.setTransformer(this); m_serializationHandler.setWriter(sw); String result; try { /* Don't call startDocument, the SerializationHandler will * generate its own internal startDocument call anyways */ // this.m_serializationHandler.startDocument(); // Do the transformation of the child elements. executeChildTemplates(elem, true); this.m_serializationHandler.endDocument(); result = sw.toString(); } catch (org.xml.sax.SAXException se) { throw new TransformerException(se); } finally { sw.getBuffer().setLength(0); try { sw.close(); } catch (Exception ioe){} m_stringWriterObjectPool.freeInstance(sw); m_serializationHandler.reset(); m_textResultHandlerObjectPool.freeInstance(m_serializationHandler); // Restore the previous result tree handler. m_serializationHandler = savedRTreeHandler; } return result; } /** * Given an element and mode, find the corresponding * template and process the contents. * * @param xslInstruction The calling element. * @param template The template to use if xsl:for-each, current template for apply-imports, or null. * @param child The source context node. * @throws TransformerException * @return true if applied a template, false if not. * @xsl.usage advanced */ public boolean applyTemplateToNode(ElemTemplateElement xslInstruction, // xsl:apply-templates or xsl:for-each ElemTemplate template, int child) throws TransformerException { DTM dtm = m_xcontext.getDTM(child); short nodeType = dtm.getNodeType(child); boolean isDefaultTextRule = false; boolean isApplyImports = false; isApplyImports = ((xslInstruction == null) ? false : xslInstruction.getXSLToken() == Constants.ELEMNAME_APPLY_IMPORTS); if (null == template || isApplyImports) { int maxImportLevel, endImportLevel=0; if (isApplyImports) { maxImportLevel = template.getStylesheetComposed().getImportCountComposed() - 1; endImportLevel = template.getStylesheetComposed().getEndImportCountComposed(); } else { maxImportLevel = -1; } // If we're trying an xsl:apply-imports at the top level (ie there are no // imported stylesheets), we need to indicate that there is no matching template. // The above logic will calculate a maxImportLevel of -1 which indicates // that we should find any template. This is because a value of -1 for // maxImportLevel has a special meaning. But we don't want that. // We want to match -no- templates. See bugzilla bug 1170. if (isApplyImports && (maxImportLevel == -1)) { template = null; } else { // Find the XSL template that is the best match for the // element. XPathContext xctxt = m_xcontext; try { xctxt.pushNamespaceContext(xslInstruction); QName mode = this.getMode(); if (isApplyImports) template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode, maxImportLevel, endImportLevel, m_quietConflictWarnings, dtm); else template = m_stylesheetRoot.getTemplateComposed(xctxt, child, mode, m_quietConflictWarnings, dtm); } finally { xctxt.popNamespaceContext(); } } // If that didn't locate a node, fall back to a default template rule. // See http://www.w3.org/TR/xslt#built-in-rule. if (null == template) { switch (nodeType) { case DTM.DOCUMENT_FRAGMENT_NODE : case DTM.ELEMENT_NODE : template = m_stylesheetRoot.getDefaultRule(); break; case DTM.CDATA_SECTION_NODE : case DTM.TEXT_NODE : case DTM.ATTRIBUTE_NODE : template = m_stylesheetRoot.getDefaultTextRule(); isDefaultTextRule = true; break; case DTM.DOCUMENT_NODE : template = m_stylesheetRoot.getDefaultRootRule(); break; default : // No default rules for processing instructions and the like. return false; } } } // If we are processing the default text rule, then just clone // the value directly to the result tree. try { pushElemTemplateElement(template); m_xcontext.pushCurrentNode(child); pushPairCurrentMatched(template, child); // Fix copy copy29 test. if (!isApplyImports) { DTMIterator cnl = new org.apache.xpath.NodeSetDTM(child, m_xcontext.getDTMManager()); m_xcontext.pushContextNodeList(cnl); } if (isDefaultTextRule) { switch (nodeType) { case DTM.CDATA_SECTION_NODE : case DTM.TEXT_NODE : ClonerToResultTree.cloneToResultTree(child, nodeType, dtm, getResultTreeHandler(), false); break; case DTM.ATTRIBUTE_NODE : dtm.dispatchCharactersEvents(child, getResultTreeHandler(), false); break; } } else { // And execute the child templates. // 9/11/00: If template has been compiled, hand off to it // since much (most? all?) of the processing has been inlined. // (It would be nice if there was a single entry point that // worked for both... but the interpretive system works by // having the Tranformer execute the children, while the // compiled obviously has to run its own code. It's // also unclear that "execute" is really the right name for // that entry point.) m_xcontext.setSAXLocator(template); // m_xcontext.getVarStack().link(); m_xcontext.getVarStack().link(template.m_frameSize); executeChildTemplates(template, true); } } catch (org.xml.sax.SAXException se) { throw new TransformerException(se); } finally { if (!isDefaultTextRule) m_xcontext.getVarStack().unlink(); m_xcontext.popCurrentNode(); if (!isApplyImports) { m_xcontext.popContextNodeList(); } popCurrentMatched(); popElemTemplateElement(); } return true; } /** * Execute each of the children of a template element. This method * is only for extension use. * * @param elem The ElemTemplateElement that contains the children * that should execute. * NEEDSDOC @param context * @param mode The current mode. * @param handler The ContentHandler to where the result events * should be fed. * * @throws TransformerException * @xsl.usage advanced */ public void executeChildTemplates( ElemTemplateElement elem, org.w3c.dom.Node context, QName mode, ContentHandler handler) throws TransformerException { XPathContext xctxt = m_xcontext; try { if(null != mode) pushMode(mode); xctxt.pushCurrentNode(xctxt.getDTMHandleFromNode(context)); executeChildTemplates(elem, handler); } finally { xctxt.popCurrentNode(); // I'm not sure where or why this was here. It is clearly in // error though, without a corresponding pushMode(). if (null != mode) popMode(); } } /** * Execute each of the children of a template element. * * @param elem The ElemTemplateElement that contains the children * that should execute. * @param shouldAddAttrs true if xsl:attributes should be executed. * * @throws TransformerException * @xsl.usage advanced */ public void executeChildTemplates( ElemTemplateElement elem, boolean shouldAddAttrs) throws TransformerException { // Does this element have any children? ElemTemplateElement t = elem.getFirstChildElem(); if (null == t) return; if(elem.hasTextLitOnly() && m_optimizer) { char[] chars = ((ElemTextLiteral)t).getChars(); try { // Have to push stuff on for tooling... this.pushElemTemplateElement(t); m_serializationHandler.characters(chars, 0, chars.length); } catch(SAXException se) { throw new TransformerException(se); } finally { this.popElemTemplateElement(); } return; } // // Check for infinite loops if we have to. // boolean check = (m_stackGuard.m_recursionLimit > -1); // // if (check) // getStackGuard().push(elem, xctxt.getCurrentNode()); XPathContext xctxt = m_xcontext; xctxt.pushSAXLocatorNull(); int currentTemplateElementsTop = m_currentTemplateElements.size(); m_currentTemplateElements.push(null); try { // Loop through the children of the template, calling execute on // each of them. for (; t != null; t = t.getNextSiblingElem()) { if (!shouldAddAttrs && t.getXSLToken() == Constants.ELEMNAME_ATTRIBUTE) continue; xctxt.setSAXLocator(t); m_currentTemplateElements.setElementAt(t,currentTemplateElementsTop); t.execute(this); } } catch(RuntimeException re) { TransformerException te = new TransformerException(re); te.setLocator(t); throw te; } finally { m_currentTemplateElements.pop(); xctxt.popSAXLocator(); } // Check for infinite loops if we have to // if (check) // getStackGuard().pop(); } /** * Execute each of the children of a template element. * * @param elem The ElemTemplateElement that contains the children * that should execute. * @param handler The ContentHandler to where the result events * should be fed. * * @throws TransformerException * @xsl.usage advanced */ public void executeChildTemplates( ElemTemplateElement elem, ContentHandler handler) throws TransformerException { SerializationHandler xoh = this.getSerializationHandler(); // These may well not be the same! In this case when calling // the Redirect extension, it has already set the ContentHandler // in the Transformer. SerializationHandler savedHandler = xoh; try { xoh.flushPending(); // %REVIEW% Make sure current node is being pushed. LexicalHandler lex = null; if (handler instanceof LexicalHandler) { lex = (LexicalHandler) handler; } m_serializationHandler = new ToXMLSAXHandler(handler, lex, savedHandler.getEncoding()); m_serializationHandler.setTransformer(this); executeChildTemplates(elem, true); } catch (TransformerException e) { throw e; } catch (SAXException se) { throw new TransformerException(se); } finally { m_serializationHandler = savedHandler; } } /** * Get the keys for the xsl:sort elements. * Note: Should this go into ElemForEach? * * @param foreach Valid ElemForEach element, not null. * @param sourceNodeContext The current node context in the source tree, * needed to evaluate the Attribute Value Templates. * * @return A Vector of NodeSortKeys, or null. * * @throws TransformerException * @xsl.usage advanced */ public Vector processSortKeys(ElemForEach foreach, int sourceNodeContext) throws TransformerException { Vector keys = null; XPathContext xctxt = m_xcontext; int nElems = foreach.getSortElemCount(); if (nElems > 0) keys = new Vector(); // March backwards, collecting the sort keys. for (int i = 0; i < nElems; i++) { ElemSort sort = foreach.getSortElem(i); String langString = (null != sort.getLang()) ? sort.getLang().evaluate(xctxt, sourceNodeContext, foreach) : null; String dataTypeString = sort.getDataType().evaluate(xctxt, sourceNodeContext, foreach); if (dataTypeString.indexOf(":") >= 0) System.out.println( "TODO: Need to write the hooks for QNAME sort data type"); else if (!(dataTypeString.equalsIgnoreCase(Constants.ATTRVAL_DATATYPE_TEXT)) &&!(dataTypeString.equalsIgnoreCase( Constants.ATTRVAL_DATATYPE_NUMBER))) foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE, new Object[]{ Constants.ATTRNAME_DATATYPE, dataTypeString }); boolean treatAsNumbers = ((null != dataTypeString) && dataTypeString.equals( Constants.ATTRVAL_DATATYPE_NUMBER)) ? true : false; String orderString = sort.getOrder().evaluate(xctxt, sourceNodeContext, foreach); if (!(orderString.equalsIgnoreCase(Constants.ATTRVAL_ORDER_ASCENDING)) &&!(orderString.equalsIgnoreCase( Constants.ATTRVAL_ORDER_DESCENDING))) foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE, new Object[]{ Constants.ATTRNAME_ORDER, orderString }); boolean descending = ((null != orderString) && orderString.equals( Constants.ATTRVAL_ORDER_DESCENDING)) ? true : false; AVT caseOrder = sort.getCaseOrder(); boolean caseOrderUpper; if (null != caseOrder) { String caseOrderString = caseOrder.evaluate(xctxt, sourceNodeContext, foreach); if (!(caseOrderString.equalsIgnoreCase(Constants.ATTRVAL_CASEORDER_UPPER)) &&!(caseOrderString.equalsIgnoreCase( Constants.ATTRVAL_CASEORDER_LOWER))) foreach.error(XSLTErrorResources.ER_ILLEGAL_ATTRIBUTE_VALUE, new Object[]{ Constants.ATTRNAME_CASEORDER, caseOrderString }); caseOrderUpper = ((null != caseOrderString) && caseOrderString.equals( Constants.ATTRVAL_CASEORDER_UPPER)) ? true : false; } else { caseOrderUpper = false; } keys.addElement(new NodeSortKey(this, sort.getSelect(), treatAsNumbers, descending, langString, caseOrderUpper, foreach)); } return keys; } //========================================================== // SECTION: TransformState implementation //========================================================== /** * Get the count of how many elements are * active. * @return The number of active elements on * the currentTemplateElements stack. */ public int getCurrentTemplateElementsCount() { return m_currentTemplateElements.size(); } /** * Get the count of how many elements are * active. * @return The number of active elements on * the currentTemplateElements stack. */ public ObjectStack getCurrentTemplateElements() { return m_currentTemplateElements; } /** * Push the current template element. * * @param elem The current ElemTemplateElement (may be null, and then * set via setCurrentElement). */ public void pushElemTemplateElement(ElemTemplateElement elem) { m_currentTemplateElements.push(elem); } /** * Pop the current template element. */ public void popElemTemplateElement() { m_currentTemplateElements.pop(); } /** * Set the top of the current template elements * stack. * * @param e The current ElemTemplateElement about to * be executed. */ public void setCurrentElement(ElemTemplateElement e) { m_currentTemplateElements.setTop(e); } /** * Retrieves the current ElemTemplateElement that is * being executed. * * @return The current ElemTemplateElement that is executing, * should not normally be null. */ public ElemTemplateElement getCurrentElement() { return (m_currentTemplateElements.size() > 0) ? (ElemTemplateElement) m_currentTemplateElements.peek() : null; } /** * This method retrieves the current context node * in the source tree. * * @return The current context node (should never be null?). */ public int getCurrentNode() { return m_xcontext.getCurrentNode(); } /** * This method retrieves the xsl:template * that is in effect, which may be a matched template * or a named template. * * <p>Please note that the ElemTemplate returned may * be a default template, and thus may not have a template * defined in the stylesheet.</p> * * @return The current xsl:template, should not be null. */ public ElemTemplate getCurrentTemplate() { ElemTemplateElement elem = getCurrentElement(); while ((null != elem) && (elem.getXSLToken() != Constants.ELEMNAME_TEMPLATE)) { elem = elem.getParentElem(); } return (ElemTemplate) elem; } /** * Push both the current xsl:template or xsl:for-each onto the * stack, along with the child node that was matched. * (Note: should this only be used for xsl:templates?? -sb) * * @param template xsl:template or xsl:for-each. * @param child The child that was matched. */ public void pushPairCurrentMatched(ElemTemplateElement template, int child) { m_currentMatchTemplates.push(template); m_currentMatchedNodes.push(child); } /** * Pop the elements that were pushed via pushPairCurrentMatched. */ public void popCurrentMatched() { m_currentMatchTemplates.pop(); m_currentMatchedNodes.pop(); } /** * This method retrieves the xsl:template * that was matched. Note that this may not be * the same thing as the current template (which * may be from getCurrentElement()), since a named * template may be in effect. * * @return The pushed template that was pushed via pushPairCurrentMatched. */ public ElemTemplate getMatchedTemplate() { return (ElemTemplate) m_currentMatchTemplates.peek(); } /** * Retrieves the node in the source tree that matched * the template obtained via getMatchedTemplate(). * * @return The matched node that corresponds to the * match attribute of the current xsl:template. */ public int getMatchedNode() { return m_currentMatchedNodes.peepTail(); } /** * Get the current context node list. * * @return A reset clone of the context node list. */ public DTMIterator getContextNodeList() { try { DTMIterator cnl = m_xcontext.getContextNodeList(); return (cnl == null) ? null : (DTMIterator) cnl.cloneWithReset(); } catch (CloneNotSupportedException cnse) { // should never happen. return null; } } /** * Get the TrAX Transformer object in effect. * * @return This object. */ public Transformer getTransformer() { return this; } //========================================================== // SECTION: Accessor Functions //========================================================== /** * Set the stylesheet for this processor. If this is set, then the * process calls that take only the input .xml will use * this instead of looking for a stylesheet PI. Also, * setting the stylesheet is needed if you are going * to use the processor as a SAX ContentHandler. * * @param stylesheetRoot A non-null StylesheetRoot object, * or null if you wish to clear the stylesheet reference. */ public void setStylesheet(StylesheetRoot stylesheetRoot) { m_stylesheetRoot = stylesheetRoot; } /** * Get the current stylesheet for this processor. * * @return The stylesheet that is associated with this * transformer. */ public final StylesheetRoot getStylesheet() { return m_stylesheetRoot; } /** * Get quietConflictWarnings property. If the quietConflictWarnings * property is set to true, warnings about pattern conflicts won't be * printed to the diagnostics stream. * * @return True if this transformer should not report * template match conflicts. */ public boolean getQuietConflictWarnings() { return m_quietConflictWarnings; } /** * Set the execution context for XPath. * * @param xcontext A non-null reference to the XPathContext * associated with this transformer. * @xsl.usage internal */ public void setXPathContext(XPathContext xcontext) { m_xcontext = xcontext; } /** * Get the XPath context associated with this transformer. * * @return The XPathContext reference, never null. */ public final XPathContext getXPathContext() { return m_xcontext; } /** * Get the SerializationHandler object. * * @return The current SerializationHandler, which may not * be the main result tree manager. */ public SerializationHandler getResultTreeHandler() { return m_serializationHandler; } /** * Get the SerializationHandler object. * * @return The current SerializationHandler, which may not * be the main result tree manager. */ public SerializationHandler getSerializationHandler() { return m_serializationHandler; } /** * Get the KeyManager object. * * @return A reference to the KeyManager object, which should * never be null. */ public KeyManager getKeyManager() { return m_keyManager; } /** * Check to see if this is a recursive attribute definition. * * @param attrSet A non-null ElemAttributeSet reference. * * @return true if the attribute set is recursive. */ public boolean isRecursiveAttrSet(ElemAttributeSet attrSet) { if (null == m_attrSetStack) { m_attrSetStack = new Stack(); } if (!m_attrSetStack.empty()) { int loc = m_attrSetStack.search(attrSet); if (loc > -1) { return true; } } return false; } /** * Push an executing attribute set, so we can check for * recursive attribute definitions. * * @param attrSet A non-null ElemAttributeSet reference. */ public void pushElemAttributeSet(ElemAttributeSet attrSet) { m_attrSetStack.push(attrSet); } /** * Pop the current executing attribute set. */ public void popElemAttributeSet() { m_attrSetStack.pop(); } /** * Get the table of counters, for optimized xsl:number support. * * @return The CountersTable, never null. */ public CountersTable getCountersTable() { if (null == m_countersTable) m_countersTable = new CountersTable(); return m_countersTable; } /** * Tell if the current template rule is null, i.e. if we are * directly within an apply-templates. Used for xsl:apply-imports. * * @return True if the current template rule is null. */ public boolean currentTemplateRuleIsNull() { return ((!m_currentTemplateRuleIsNull.isEmpty()) && (m_currentTemplateRuleIsNull.peek() == true)); } /** * Push true if the current template rule is null, false * otherwise. * * @param b True if the we are executing an xsl:for-each * (or xsl:call-template?). */ public void pushCurrentTemplateRuleIsNull(boolean b) { m_currentTemplateRuleIsNull.push(b); } /** * Push true if the current template rule is null, false * otherwise. */ public void popCurrentTemplateRuleIsNull() { m_currentTemplateRuleIsNull.pop(); } /** * Push a funcion result for the currently active EXSLT * <code>func:function</code>. * * @param val the result of executing an EXSLT * <code>func:result</code> instruction for the current * <code>func:function</code>. */ public void pushCurrentFuncResult(Object val) { m_currentFuncResult.push(val); } /** * Pops the result of the currently active EXSLT <code>func:function</code>. * * @return the value of the <code>func:function</code> */ public Object popCurrentFuncResult() { return m_currentFuncResult.pop(); } /** * Determines whether an EXSLT <code>func:result</code> instruction has been * executed for the currently active EXSLT <code>func:function</code>. * * @return <code>true</code> if and only if a <code>func:result</code> * instruction has been executed */ public boolean currentFuncResultSeen() { return !m_currentFuncResult.empty() && m_currentFuncResult.peek() != null; } /** * Return the message manager. * * @return The message manager, never null. */ public MsgMgr getMsgMgr() { if (null == m_msgMgr) m_msgMgr = new MsgMgr(this); return m_msgMgr; } /** * Set the error event listener. * * @param listener The new error listener. * @throws IllegalArgumentException if */ public void setErrorListener(ErrorListener listener) throws IllegalArgumentException { synchronized (m_reentryGuard) { if (listener == null) throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_NULL_ERROR_HANDLER, null)); //"Null error handler"); m_errorHandler = listener; } } /** * Get the current error event handler. * * @return The current error handler, which should never be null. */ public ErrorListener getErrorListener() { return m_errorHandler; } /** * Look up the value of a feature. * * <p>The feature name is any fully-qualified URI. It is * possible for an TransformerFactory to recognize a feature name but * to be unable to return its value; this is especially true * in the case of an adapter for a SAX1 Parser, which has * no way of knowing whether the underlying parser is * validating, for example.</p> * * <h3>Open issues:</h3> * <dl> * <dt><h4>Should getFeature be changed to hasFeature?</h4></dt> * <dd>Keith Visco writes: Should getFeature be changed to hasFeature? * It returns a boolean which indicated whether the "state" * of feature is "true or false". I assume this means whether * or not a feature is supported? I know SAX is using "getFeature", * but to me "hasFeature" is cleaner.</dd> * </dl> * * @param name The feature name, which is a fully-qualified * URI. * @return The current state of the feature (true or false). * @throws org.xml.sax.SAXNotRecognizedException When the * TransformerFactory does not recognize the feature name. * @throws org.xml.sax.SAXNotSupportedException When the * TransformerFactory recognizes the feature name but * cannot determine its value at this time. * * @throws SAXNotRecognizedException * @throws SAXNotSupportedException */ public boolean getFeature(String name) throws SAXNotRecognizedException, SAXNotSupportedException { if ("http://xml.org/trax/features/sax/input".equals(name)) return true; else if ("http://xml.org/trax/features/dom/input".equals(name)) return true; throw new SAXNotRecognizedException(name); } // %TODO% Doc /** * NEEDSDOC Method getMode * * * NEEDSDOC (getMode) @return */ public QName getMode() { return m_modes.isEmpty() ? null : (QName) m_modes.peek(); } // %TODO% Doc /** * NEEDSDOC Method pushMode * * * NEEDSDOC @param mode */ public void pushMode(QName mode) { m_modes.push(mode); } // %TODO% Doc /** * NEEDSDOC Method popMode * */ public void popMode() { m_modes.pop(); } /** * Called by SourceTreeHandler to start the transformation * in a separate thread * * NEEDSDOC @param priority */ public void runTransformThread(int priority) { // used in SourceTreeHandler Thread t = ThreadControllerWrapper.runThread(this, priority); this.setTransformThread(t); } /** * Called by this.transform() if isParserEventsOnMain()==false. * Similar with runTransformThread(), but no priority is set * and setTransformThread is not set. */ public void runTransformThread() { ThreadControllerWrapper.runThread(this, -1); } /** * Called by CoRoutineSAXParser. Launches the CoroutineSAXParser * in a thread, and prepares it to invoke the parser from that thread * upon request. * */ public static void runTransformThread(Runnable runnable) { ThreadControllerWrapper.runThread(runnable, -1); } /** * Used by SourceTreeHandler to wait until the transform * completes * * @throws SAXException */ public void waitTransformThread() throws SAXException { // This is called to make sure the task is done. // It is possible that the thread has been reused - // but for a different transformation. ( what if we // recycle the transformer ? Not a problem since this is // still in use. ) Thread transformThread = this.getTransformThread(); if (null != transformThread) { try { ThreadControllerWrapper.waitThread(transformThread, this); if (!this.hasTransformThreadErrorCatcher()) { Exception e = this.getExceptionThrown(); if (null != e) { e.printStackTrace(); throw new org.xml.sax.SAXException(e); } } this.setTransformThread(null); } catch (InterruptedException ie){} } } /** * Get the exception thrown by the secondary thread (normally * the transform thread). * * @return The thrown exception, or null if no exception was * thrown. */ public Exception getExceptionThrown() { return m_exceptionThrown; } /** * Set the exception thrown by the secondary thread (normally * the transform thread). * * @param e The thrown exception, or null if no exception was * thrown. */ public void setExceptionThrown(Exception e) { m_exceptionThrown = e; } /** * This is just a way to set the document for run(). * * @param doc A non-null reference to the root of the * tree to be transformed. */ public void setSourceTreeDocForThread(int doc) { m_doc = doc; } /** * From a secondary thread, post the exception, so that * it can be picked up from the main thread. * * @param e The exception that was thrown. */ void postExceptionFromThread(Exception e) { // Commented out in response to problem reported by Nicola Brown <Nicola.Brown@jacobsrimell.com> // if(m_reportInPostExceptionFromThread) // { // // Consider re-throwing the exception if this flag is set. // e.printStackTrace(); // } // %REVIEW Need DTM equivelent? // if (m_inputContentHandler instanceof SourceTreeHandler) // { // SourceTreeHandler sth = (SourceTreeHandler) m_inputContentHandler; // // sth.setExceptionThrown(e); // } // ContentHandler ch = getContentHandler(); // if(ch instanceof SourceTreeHandler) // { // SourceTreeHandler sth = (SourceTreeHandler) ch; // ((TransformerImpl)(sth.getTransformer())).postExceptionFromThread(e); // } // m_isTransformDone = true; // android-removed m_exceptionThrown = e; ; // should have already been reported via the error handler? synchronized (this) { // See message from me on 3/27/2001 to Patrick Moore. // String msg = e.getMessage(); // System.out.println(e.getMessage()); // Is this really needed? -sb notifyAll(); // if (null == msg) // { // // // m_throwNewError = false; // e.printStackTrace(); // } // throw new org.apache.xml.utils.WrappedRuntimeException(e); } } /** * Run the transform thread. */ public void run() { m_hasBeenReset = false; try { // int n = ((SourceTreeHandler)getInputContentHandler()).getDTMRoot(); // transformNode(n); try { // m_isTransformDone = false; // android-removed // Should no longer be needed... // if(m_inputContentHandler instanceof TransformerHandlerImpl) // { // TransformerHandlerImpl thi = (TransformerHandlerImpl)m_inputContentHandler; // thi.waitForInitialEvents(); // } transformNode(m_doc); } catch (Exception e) { // e.printStackTrace(); // Strange that the other catch won't catch this... if (null != m_transformThread) postExceptionFromThread(e); // Assume we're on the main thread else throw new RuntimeException(e.getMessage()); } finally { // m_isTransformDone = true; // android-removed if (m_inputContentHandler instanceof TransformerHandlerImpl) { ((TransformerHandlerImpl) m_inputContentHandler).clearCoRoutine(); } // synchronized (this) // { // notifyAll(); // } } } catch (Exception e) { // e.printStackTrace(); if (null != m_transformThread) postExceptionFromThread(e); else throw new RuntimeException(e.getMessage()); // Assume we're on the main thread. } } // Fragment re-execution interfaces for a tool. /** * Test whether whitespace-only text nodes are visible in the logical * view of <code>DTM</code>. Normally, this function * will be called by the implementation of <code>DTM</code>; * it is not normally called directly from * user code. * * @param elementHandle int Handle of the element. * @return one of NOTSTRIP, STRIP, or INHERIT. */ public short getShouldStripSpace(int elementHandle, DTM dtm) { try { org.apache.xalan.templates.WhiteSpaceInfo info = m_stylesheetRoot.getWhiteSpaceInfo(m_xcontext, elementHandle, dtm); if (null == info) { return DTMWSFilter.INHERIT; } else { // System.out.println("getShouldStripSpace: "+info.getShouldStripSpace()); return info.getShouldStripSpace() ? DTMWSFilter.STRIP : DTMWSFilter.NOTSTRIP; } } catch (TransformerException se) { return DTMWSFilter.INHERIT; } } /** * Initializer method. * * @param transformer non-null transformer instance * @param realHandler Content Handler instance */ public void init(ToXMLSAXHandler h,Transformer transformer, ContentHandler realHandler) { h.setTransformer(transformer); h.setContentHandler(realHandler); } public void setSerializationHandler(SerializationHandler xoh) { m_serializationHandler = xoh; } /** * Fire off characters, cdate events. * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, char[], int, int) */ public void fireGenerateEvent( int eventType, char[] ch, int start, int length) { } /** * Fire off startElement, endElement events. * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String, Attributes) */ public void fireGenerateEvent( int eventType, String name, Attributes atts) { } /** * Fire off processingInstruction events. */ public void fireGenerateEvent(int eventType, String name, String data) { } /** * Fire off comment and entity ref events. * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int, String) */ public void fireGenerateEvent(int eventType, String data) { } /** * Fire off startDocument, endDocument events. * @see org.apache.xml.serializer.SerializerTrace#fireGenerateEvent(int) */ public void fireGenerateEvent(int eventType) { } /** * @see org.apache.xml.serializer.SerializerTrace#hasTraceListeners() */ public boolean hasTraceListeners() { return false; } /** * @return Incremental flag */ public boolean getIncremental() { return m_incremental; } /** * @return Optimization flag */ public boolean getOptimize() { return m_optimizer; } /** * @return Source location flag */ public boolean getSource_location() { return m_source_location; } } // end TransformerImpl class