| /* |
| * 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) |
| 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 |
| |