| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, Lotus |
| * Development Corporation., http://www.lotus.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.xalan.transformer; |
| |
| // Java imports |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.StringWriter; |
| import java.io.UnsupportedEncodingException; |
| import java.util.Enumeration; |
| import java.util.NoSuchElementException; |
| import java.util.Properties; |
| import java.util.Stack; |
| import java.util.StringTokenizer; |
| import java.util.Vector; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.transform.ErrorListener; |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.Source; |
| 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.sax.SAXResult; |
| import javax.xml.transform.stream.StreamResult; |
| import org.apache.xalan.processor.TransformerFactoryImpl; |
| import org.apache.xalan.res.XSLMessages; |
| import org.apache.xalan.res.XSLTErrorResources; |
| import org.apache.xalan.serialize.Method; |
| import org.apache.xalan.serialize.Serializer; |
| import org.apache.xalan.serialize.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.WhiteSpaceInfo; |
| import org.apache.xalan.templates.XUnresolvedVariable; |
| import org.apache.xalan.trace.TraceManager; |
| 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.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.QName; |
| import org.apache.xml.utils.SAXSourceLocator; |
| import org.apache.xml.utils.WrappedRuntimeException; |
| import org.apache.xpath.Arg; |
| import org.apache.xpath.VariableStack; |
| import org.apache.xpath.XPathContext; |
| import org.apache.xpath.objects.XObject; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.DocumentFragment; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.Text; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXNotRecognizedException; |
| import org.xml.sax.SAXNotSupportedException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.ext.DeclHandler; |
| import org.xml.sax.ext.LexicalHandler; |
| |
| //dml |
| import org.apache.xpath.ExtensionsProvider; |
| import org.apache.xalan.extensions.ExtensionsTable; |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * This class implements the |
| * {@link javax.xml.transform.Transformer} interface, and is the core |
| * representation of the transformation execution.</p> |
| */ |
| public class TransformerImpl extends Transformer |
| implements Runnable, DTMWSFilter, ExtensionsProvider |
| { |
| |
| // 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; |
| |
| /** |
| * True if the parser events should be on the main thread, |
| * false if not. Experemental. Can not be set right now. |
| */ |
| private boolean m_parserEventsOnMain = true; |
| |
| /** 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 output serializer */ |
| private Serializer m_serializer; |
| |
| /** |
| * 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(); |
| |
| /** The JAXP Document Builder, mainly to create Result Tree Fragments. */ |
| DocumentBuilder m_docBuilder = null; |
| |
| /** |
| * 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("org.apache.xalan.transformer.ResultTreeHandler"); |
| |
| /** |
| * 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("java.io.StringWriter"); |
| |
| /** |
| * 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. |
| */ |
| ElemTemplateElement[] m_currentTemplateElements |
| = new ElemTemplateElement[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; |
| |
| /** |
| * Object to guard agains infinite recursion when |
| * doing queries. |
| */ |
| private StackGuard m_stackGuard; |
| |
| /** |
| * Output handler to bottleneck SAX events. |
| */ |
| private ResultTreeHandler m_resultTreeHandler; |
| |
| /** 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. |
| * @see ElemNumber |
| */ |
| CountersTable m_countersTable = null; |
| |
| /** |
| * Is > 0 when we're processing a for-each. |
| */ |
| BoolStack m_currentTemplateRuleIsNull = new BoolStack(); |
| |
| /** |
| * The message manager, which manages error messages, warning |
| * messages, and other types of message events. |
| */ |
| private MsgMgr m_msgMgr; |
| |
| /** |
| * This is a compile-time flag to turn off calling |
| * of trace listeners. Set this to false for optimization purposes. |
| */ |
| public static boolean S_DEBUG = false; |
| |
| /** |
| * The SAX error handler, where errors and warnings are sent. |
| */ |
| private ErrorListener m_errorHandler = |
| new org.apache.xml.utils.DefaultErrorHandler(); |
| |
| /** |
| * The trace manager. |
| */ |
| private TraceManager m_traceManager = new TraceManager(this); |
| |
| /** |
| * 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; |
| |
| /** |
| * The InputSource for the source tree, which is needed if the |
| * parse thread is not the main thread, in order for the parse |
| * thread's run method to get to the input source. |
| * (Delete this if reversing threads is outlawed. -sb) |
| */ |
| private Source m_xmlSource; |
| |
| /** |
| * 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; |
| |
| /** |
| * If the the transform is on the secondary thread, we |
| * need to know when it is done, so we can return. |
| */ |
| private boolean m_isTransformDone = false; |
| |
| /** 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; |
| |
| /** |
| * NEEDSDOC Method setShouldReset |
| * |
| * |
| * NEEDSDOC @param shouldReset |
| */ |
| public void setShouldReset(boolean shouldReset) |
| { |
| m_shouldReset = shouldReset; |
| } |
| |
| /** |
| * 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 |
| { |
| setStylesheet(stylesheet); |
| setXPathContext(new XPathContext(this)); |
| getXPathContext().setNamespaceContext(stylesheet); |
| m_stackGuard = new StackGuard(this); |
| } |
| |
| // ================ 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()); |
| } |
| |
| //========================= |
| |
| /** |
| * 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(); |
| |
| |
| int n = m_currentTemplateElements.length; |
| for (int i = 0; i < n; i++) |
| { |
| m_currentTemplateElements[i] = null; |
| } |
| m_currentTemplateElementsTop = 0; |
| |
| m_currentMatchTemplates.removeAllElements(); |
| m_currentMatchedNodes.removeAllElements(); |
| |
| m_resultTreeHandler = null; |
| m_outputTarget = null; |
| m_keyManager = new KeyManager(); |
| m_attrSetStack = null; |
| m_countersTable = null; |
| m_currentTemplateRuleIsNull = new BoolStack(); |
| m_xmlSource = null; |
| m_doc = DTM.NULL; |
| m_isTransformDone = false; |
| m_transformThread = null; |
| |
| // m_inputContentHandler = null; |
| // For now, reset the document cache each time. |
| m_xcontext.getSourceTreeManager().reset(); |
| } |
| |
| // m_reportInPostExceptionFromThread = false; |
| } |
| |
| /** |
| * <code>getProperty</code> returns the current setting of the |
| * property described by the <code>property</code> argument. |
| * |
| * %REVIEW% Obsolete now that source_location is handled in the TransformerFactory? |
| * |
| * @param property a <code>String</code> value |
| * @return a <code>boolean</code> value |
| */ |
| public boolean getProperty(String property) |
| { |
| return false; |
| } |
| |
| /** |
| * Set a runtime property for this <code>TransformerImpl</code>. |
| * |
| * %REVIEW% Obsolete now that source_location is handled in the TransformerFactory? |
| * |
| * @param property a <code>String</code> value |
| * @param value an <code>Object</code> value |
| */ |
| public void setProperty(String property, Object value) |
| { |
| } |
| |
| // ========= Transformer Interface Implementation ========== |
| |
| /** |
| * <meta name="usage" content="experimental"/> |
| * Get true if the parser events should be on the main thread, |
| * false if not. Experimental. Can not be set right now. |
| * |
| * @return true if the parser events should be on the main thread, |
| * false if not. |
| */ |
| public boolean isParserEventsOnMain() |
| { |
| return m_parserEventsOnMain; |
| } |
| |
| /** |
| * <meta name="usage" content="internal"/> |
| * Get the thread that the transform process is on. |
| * |
| * @return The thread that the transform process is on, or null. |
| */ |
| public Thread getTransformThread() |
| { |
| return m_transformThread; |
| } |
| |
| /** |
| * <meta name="usage" content="internal"/> |
| * Get the thread that the transform process is on. |
| * |
| * @param t The transform thread, may be null. |
| */ |
| 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 |
| { |
| 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(); |
| 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) |
| { |
| fatalError(e); |
| } |
| else if (null != m_resultTreeHandler) |
| { |
| m_resultTreeHandler.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))); |
| if (throwable instanceof TransformerException) |
| m_errorHandler.fatalError((TransformerException)throwable); |
| else |
| m_errorHandler.fatalError(new TransformerException(throwable)); |
| |
| } |
| |
| /** |
| * Get the base URL of the source. |
| * |
| * @return The base URL of the source tree, or null. |
| */ |
| public String getBaseURLOfSource() |
| { |
| return m_urlOfSource; |
| } |
| |
| /** |
| * 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 the original output target. |
| * |
| * @return The Result object used to kick of the transform or null. |
| */ |
| public Result getOutputTarget() |
| { |
| return m_outputTarget; |
| } |
| |
| /** |
| * Set the original output target. This is useful when using a SAX transform and |
| * supplying a ContentHandler or when the URI of the output target should |
| * not be the same as the systemID of the original output target. |
| * |
| * |
| * NEEDSDOC @param outputTarget |
| */ |
| public void setOutputTarget(Result outputTarget) |
| { |
| m_outputTarget = outputTarget; |
| } |
| |
| /** |
| * 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. |
| * |
| * @param name A non-null String that specifies an output |
| * property name, which may be namespace qualified. |
| * |
| * 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 (!props.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. |
| * |
| * @param name The property name, which is a fully-qualified URI. |
| * |
| * 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 (!props.isLegalPropertyKey(qnameString)) |
| throw new IllegalArgumentException(XSLMessages.createMessage(XSLTErrorResources.ER_OUTPUT_PROPERTY_NOT_RECOGNIZED, new Object[]{qnameString})); //"output property not recognized: " |
| // + qnameString); |
| } |
| |
| return value; |
| } |
| |
| /** |
| * Set the value of a property. Recognized properties are: |
| * |
| * <p>"http://xml.apache.org/xslt/sourcebase" - the base URL for the |
| * source, which is needed when pure SAX ContentHandler transformation |
| * is to be done.</p> |
| * |
| * @param name The property name, which is a fully-qualified URI. |
| * @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 (!m_outputFormat.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. |
| */ |
| public void setOutputProperties(Properties oformat) |
| { |
| |
| 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(); |
| } |
| |
| if (null != oformat) |
| { |
| 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()); |
| } |
| } |
| |
| /** |
| * 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> |
| * |
| * @returns 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 ContentHandler createResultContentHandler(Result outputTarget) |
| throws TransformerException |
| { |
| return createResultContentHandler(outputTarget, getOutputFormat()); |
| } |
| |
| /** |
| * 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 ContentHandler createResultContentHandler( |
| Result outputTarget, OutputProperties format) |
| throws TransformerException |
| { |
| |
| ContentHandler handler = null; |
| |
| // 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.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 |
| { |
| doc = org.apache.xpath.DOMHelper.createDocument(); |
| outputNode = doc; |
| type = outputNode.getNodeType(); |
| |
| ((DOMResult) outputTarget).setNode(outputNode); |
| } |
| |
| handler = |
| (org.w3c.dom.Node.DOCUMENT_FRAGMENT_NODE == type) |
| ? new DOMBuilder(doc, (org.w3c.dom.DocumentFragment) outputNode) |
| : new DOMBuilder(doc, outputNode); |
| } |
| else if (outputTarget instanceof SAXResult) |
| { |
| handler = ((SAXResult) outputTarget).getHandler(); |
| |
| if (null == handler) |
| throw new IllegalArgumentException( |
| "handler can not be null for a SAXResult"); |
| } |
| |
| // 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; |
| String method = format.getProperty(OutputKeys.METHOD); |
| |
| try |
| { |
| Serializer serializer = |
| 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); |
| } |
| |
| m_outputStream = new java.io.FileOutputStream(fileURL); |
| |
| serializer.setOutputStream(m_outputStream); |
| } |
| else |
| throw new TransformerException(XSLMessages.createMessage(XSLTErrorResources.ER_NO_OUTPUT_SPECIFIED, null)); //"No output specified!"); |
| |
| handler = serializer.asContentHandler(); |
| |
| this.setSerializer(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() |
| //+ "!"); |
| } |
| |
| return handler; |
| } |
| |
| /** |
| * 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) |
| { |
| ContentHandler handler = createResultContentHandler(outputTarget); |
| |
| m_outputTarget = outputTarget; |
| |
| this.setContentHandler(handler); |
| 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 |
| { |
| |
| |
| ContentHandler handler = createResultContentHandler(outputTarget); |
| |
| m_outputTarget = outputTarget; |
| |
| this.setContentHandler(handler); |
| 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. |
| * @param outputTarget The output source target. |
| * |
| * @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_outputContentHandler) |
| { |
| 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_resultTreeHandler) |
| { |
| m_resultTreeHandler.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_resultTreeHandler) |
| { |
| try |
| { |
| if(se instanceof org.xml.sax.SAXParseException) |
| m_resultTreeHandler.fatalError((org.xml.sax.SAXParseException)se); |
| else if(se instanceof TransformerException) |
| { |
| TransformerException te = ((TransformerException)se); |
| SAXSourceLocator sl = new SAXSourceLocator( te.getLocator() ); |
| m_resultTreeHandler.fatalError(new org.xml.sax.SAXParseException(te.getMessage(), sl, te)); |
| } |
| else |
| { |
| m_resultTreeHandler.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; |
| } |
| |
| /** |
| * Get a SAX2 DeclHandler for the input. |
| * @return A valid DeclHandler, which should never be null, as |
| * long as getFeature("http://xml.org/trax/features/sax/input") |
| * returns true. |
| */ |
| public DeclHandler getInputDeclHandler() |
| { |
| |
| if (m_inputContentHandler instanceof DeclHandler) |
| return (DeclHandler) m_inputContentHandler; |
| else |
| return null; |
| } |
| |
| /** |
| * Get a SAX2 LexicalHandler for the input. |
| * @return A valid LexicalHandler, which should never be null, as |
| * long as getFeature("http://xml.org/trax/features/sax/input") |
| * returns true. |
| */ |
| public LexicalHandler getInputLexicalHandler() |
| { |
| |
| if (m_inputContentHandler instanceof LexicalHandler) |
| return (LexicalHandler) m_inputContentHandler; |
| else |
| return null; |
| } |
| |
| /** |
| * 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; |
| } |
| |
| private org.apache.xml.utils.StringVector fileOutVector = null; |
| |
| /** |
| * XSLT 2.0 -- cannot output to same file more than once during a transformation. |
| * @param fileName Absolute file pathname. |
| * @returns true if this fileName has already been used. |
| */ |
| public boolean OutputFileAlreadyUsed(String fileName) |
| { |
| if (null == fileOutVector) |
| fileOutVector = new org.apache.xml.utils.StringVector(); |
| |
| if (fileOutVector.contains(fileName)) |
| { |
| // System.out.println("OutputFileAlreadyUsed " + fileName); |
| return true; |
| } |
| else |
| { |
| fileOutVector.addElement(fileName); |
| return false; |
| } |
| } |
| |
| /** |
| * <meta name="usage" content="internal"/> |
| * Get the current serializer in use, which may well not |
| * be the main serializer (for instance, this may well be |
| * a text serializer for string creation from templates). |
| * |
| * @return The current serializer, or null if there is none. |
| */ |
| public Serializer getSerializer() |
| { |
| return m_serializer; |
| } |
| |
| /** |
| * <meta name="usage" content="internal"/> |
| * Set the current serializer. |
| * |
| * @param s The current serializer, or null. |
| */ |
| public void setSerializer(Serializer s) |
| { |
| m_serializer = s; |
| } |
| |
| /** |
| * 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) |
| { |
| |
| 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. |
| * |
| * @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. |
| * |
| * 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. |
| * |
| * @param resolver The new content 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_resultTreeHandler) |
| m_resultTreeHandler = new ResultTreeHandler(this, handler); |
| else |
| m_resultTreeHandler.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; |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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 |
| */ |
| 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); |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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 |
| */ |
| 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); |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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 |
| */ |
| 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. |
| ResultTreeHandler savedRTreeHandler = this.m_resultTreeHandler; |
| |
| // And make a new handler for the RTF. |
| m_resultTreeHandler = new ResultTreeHandler(this, rtfHandler); |
| |
| ResultTreeHandler rth = m_resultTreeHandler; |
| |
| 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_resultTreeHandler = savedRTreeHandler; |
| } |
| |
| return resultFragment; |
| } |
| |
| /** |
| * <meta name="usage" content="internal"/> |
| * Get the StringWriter pool, so that StringWriter |
| * objects may be reused. |
| * |
| * @return The string writer pool, not null. |
| */ |
| public ObjectPool getStringWriterPool() |
| { |
| return m_stringWriterObjectPool; |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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. |
| * @param transformer The XSLT transformer instance. |
| * @param sourceNode The current source node context. |
| * @param mode The current xslt mode. |
| * |
| * @return The stringized result of executing the elements children. |
| * |
| * @throws TransformerException |
| */ |
| public String transformToString(ElemTemplateElement elem) |
| throws TransformerException |
| { |
| ElemTemplateElement firstChild = elem.getFirstChildElem(); |
| if(null == firstChild) |
| return ""; |
| if(elem.hasTextLitOnly() && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize) |
| { |
| return ((ElemTextLiteral)firstChild).getNodeValue(); |
| } |
| |
| // Save the current result tree handler. |
| ResultTreeHandler savedRTreeHandler = this.m_resultTreeHandler; |
| |
| // Create a Serializer object that will handle the SAX events |
| // and build the ResultTreeFrag nodes. |
| StringWriter sw = (StringWriter) m_stringWriterObjectPool.getInstance(); |
| |
| m_resultTreeHandler = |
| (ResultTreeHandler) m_textResultHandlerObjectPool.getInstance(); |
| |
| Serializer serializer = m_resultTreeHandler.getSerializer(); |
| |
| try |
| { |
| if (null == serializer) |
| { |
| serializer = |
| SerializerFactory.getSerializer(m_textformat.getProperties()); |
| |
| m_resultTreeHandler.setSerializer(serializer); |
| serializer.setWriter(sw); |
| |
| ContentHandler shandler = serializer.asContentHandler(); |
| |
| m_resultTreeHandler.init(this, shandler); |
| } |
| else |
| { |
| |
| // Leave Commented. -sb |
| // serializer.setWriter(sw); |
| // serializer.setOutputFormat(m_textformat); |
| // ContentHandler shandler = serializer.asContentHandler(); |
| // m_resultTreeHandler.setContentHandler(shandler); |
| } |
| } |
| catch (IOException ioe) |
| { |
| throw new TransformerException(ioe); |
| } |
| |
| String result; |
| |
| try |
| { |
| this.m_resultTreeHandler.startDocument(); |
| |
| // Do the transformation of the child elements. |
| executeChildTemplates(elem, true); |
| this.m_resultTreeHandler.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_textResultHandlerObjectPool.freeInstance(m_resultTreeHandler); |
| m_resultTreeHandler.reset(); |
| |
| // Restore the previous result tree handler. |
| m_resultTreeHandler = savedRTreeHandler; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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, or null. |
| * @param child The source context node. |
| * @param mode The current mode, may be null. |
| * @throws TransformerException |
| * @return true if applied a template, false if not. |
| */ |
| 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; |
| |
| if (null == template) |
| { |
| int maxImportLevel, endImportLevel=0; |
| boolean isApplyImports = ((xslInstruction == null) |
| ? false |
| : xslInstruction.getXSLToken() |
| == Constants.ELEMNAME_APPLY_IMPORTS); |
| |
| if (isApplyImports) |
| { |
| maxImportLevel = |
| xslInstruction.getStylesheetComposed().getImportCountComposed() - 1; |
| endImportLevel = |
| xslInstruction.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. |
| 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 |
| { |
| |
| // Fire a trace event for the template. |
| |
| if (TransformerImpl.S_DEBUG) |
| getTraceManager().fireTraceEvent(template); |
| // 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); |
| |
| if (TransformerImpl.S_DEBUG) |
| getTraceManager().fireTraceEndEvent(template); |
| } |
| } |
| catch (org.xml.sax.SAXException se) |
| { |
| throw new TransformerException(se); |
| } |
| finally |
| { |
| m_xcontext.getVarStack().unlink(); |
| m_xcontext.popCurrentNode(); |
| m_xcontext.popContextNodeList(); |
| popCurrentMatched(); |
| popElemTemplateElement(); |
| } |
| |
| return true; |
| } |
| |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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. |
| * @param sourceNode The current context node. |
| * NEEDSDOC @param context |
| * @param mode The current mode. |
| * @param handler The ContentHandler to where the result events |
| * should be fed. |
| * |
| * @throws TransformerException |
| */ |
| 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(); |
| } |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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 |
| */ |
| public void executeChildTemplates( |
| ElemTemplateElement elem, ContentHandler handler) |
| throws TransformerException |
| { |
| |
| ResultTreeHandler rth = this.getResultTreeHandler(); |
| |
| // These may well not be the same! In this case when calling |
| // the Redirect extension, it has already set the ContentHandler |
| // in the Transformer. |
| ContentHandler savedRTHHandler = rth.getContentHandler(); |
| ContentHandler savedHandler = this.getContentHandler(); |
| |
| try |
| { |
| getResultTreeHandler().flushPending(); |
| this.setContentHandler(handler); |
| |
| // %REVIEW% Make sure current node is being pushed. |
| executeChildTemplates(elem, true); |
| } |
| catch (org.xml.sax.SAXException se) |
| { |
| throw new TransformerException(se); |
| } |
| finally |
| { |
| this.setContentHandler(savedHandler); |
| |
| // This fixes a bug where the ResultTreeHandler's ContentHandler |
| // was being reset to the wrong ContentHandler. |
| rth.setContentHandler(savedRTHHandler); |
| } |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * Execute each of the children of a template element. |
| * |
| * @param transformer The XSLT transformer instance. |
| * |
| * @param elem The ElemTemplateElement that contains the children |
| * that should execute. |
| * @param sourceNode The current context node. |
| * @param mode The current mode. |
| * @param shouldAddAttrs true if xsl:attributes should be executed. |
| * |
| * @throws TransformerException |
| */ |
| 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() && org.apache.xalan.processor.TransformerFactoryImpl.m_optimize) |
| { |
| char[] chars = ((ElemTextLiteral)t).getChars(); |
| try |
| { |
| // Have to push stuff on for tooling... |
| this.pushElemTemplateElement(t); |
| m_resultTreeHandler.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_currentTemplateElementsTop; |
| m_currentTemplateElementsTop++; |
| |
| 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[currentTemplateElementsTop] = t; |
| t.execute(this); |
| } |
| } |
| catch(RuntimeException re) |
| { |
| TransformerException te = new TransformerException(re); |
| te.setLocator(t); |
| throw te; |
| } |
| finally |
| { |
| m_currentTemplateElementsTop--; |
| xctxt.popSAXLocator(); |
| } |
| |
| // Check for infinite loops if we have to |
| // if (check) |
| // getStackGuard().pop(); |
| } |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * 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 |
| */ |
| 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); |
| |
| if (TransformerImpl.S_DEBUG) |
| getTraceManager().fireTraceEvent(sort); |
| |
| 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 SortKey(this, sort.getSelect(), treatAsNumbers, |
| descending, langString, caseOrderUpper, |
| foreach)); |
| if (TransformerImpl.S_DEBUG) |
| getTraceManager().fireTraceEndEvent(sort); |
| } |
| |
| return keys; |
| } |
| |
| //========================================================== |
| // SECTION: TransformState implementation |
| //========================================================== |
| |
| /** |
| * Get the stack of ElemTemplateElements. |
| * |
| * @return A copy of stack that contains the xsl element instructions, |
| * the earliest called in index zero, and the latest called in index size()-1. |
| */ |
| public Vector getElementCallstack() |
| { |
| Vector elems = new Vector(); |
| int nStackSize = m_currentTemplateElementsTop; |
| for(int i = 0; i < nStackSize; i++) |
| { |
| ElemTemplateElement elem = m_currentTemplateElements[i]; |
| if(null != elem) |
| { |
| elems.addElement(elem); |
| } |
| } |
| return elems; |
| } |
| |
| /** |
| * Get the count of how many elements are |
| * active. |
| * @return The number of active elements on |
| * the currentTemplateElements stack. |
| */ |
| public int getCurrentTemplateElementsCount() |
| { |
| return m_currentTemplateElementsTop; |
| } |
| |
| |
| /** |
| * Get the count of how many elements are |
| * active. |
| * @return The number of active elements on |
| * the currentTemplateElements stack. |
| */ |
| public ElemTemplateElement[] 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[m_currentTemplateElementsTop++] = elem; |
| } |
| |
| /** |
| * Pop the current template element. |
| */ |
| public void popElemTemplateElement() |
| { |
| m_currentTemplateElementsTop--; |
| } |
| |
| /** |
| * 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[m_currentTemplateElementsTop-1] = 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_currentTemplateElementsTop > 0) ? |
| m_currentTemplateElements[m_currentTemplateElementsTop-1] : 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(); |
| } |
| |
| /** |
| * Get the call stack of xsl:template elements. |
| * |
| * @return A copy of stack that contains the xsl:template |
| * (ElemTemplate) instructions, the earliest called in index |
| * zero, and the latest called in index size()-1. |
| */ |
| public Vector getTemplateCallstack() |
| { |
| Vector elems = new Vector(); |
| int nStackSize = m_currentTemplateElementsTop; |
| for(int i = 0; i < nStackSize; i++) |
| { |
| ElemTemplateElement elem = m_currentTemplateElements[i]; |
| if(null != elem && (elem.getXSLToken() != Constants.ELEMNAME_TEMPLATE)) |
| { |
| elems.addElement(elem); |
| } |
| } |
| return elems; |
| } |
| |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * If the quietConflictWarnings property is set to |
| * true, warnings about pattern conflicts won't be |
| * printed to the diagnostics stream. |
| * False by default. |
| * (Currently setting this property will have no effect.) |
| * |
| * @param b true if conflict warnings should be suppressed. |
| */ |
| public void setQuietConflictWarnings(boolean b) |
| { |
| m_quietConflictWarnings = b; |
| } |
| |
| /** |
| * <meta name="usage" content="internal"/> |
| * Set the execution context for XPath. |
| * |
| * @param xcontext A non-null reference to the XPathContext |
| * associated with this transformer. |
| */ |
| 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; |
| } |
| |
| /** |
| * <meta name="usage" content="internal"/> |
| * Get the object used to guard the stack from |
| * recursion. |
| * |
| * @return The StackGuard object, which should never be null. |
| */ |
| public StackGuard getStackGuard() |
| { |
| return m_stackGuard; |
| } |
| |
| /** |
| * Get the recursion limit. |
| * Used for infinite loop check. If the value is -1, do not |
| * check for infinite loops. Anyone who wants to enable that |
| * check should change the value of this variable to be the |
| * level of recursion that they want to check. Be careful setting |
| * this variable, if the number is too low, it may report an |
| * infinite loop situation, when there is none. |
| * Post version 1.0.0, we'll make this a runtime feature. |
| * |
| * @return The limit on recursion, or -1 if no check is to be made. |
| */ |
| public int getRecursionLimit() |
| { |
| return m_stackGuard.getRecursionLimit(); |
| } |
| |
| /** |
| * Set the recursion limit. |
| * Used for infinite loop check. If the value is -1, do not |
| * check for infinite loops. Anyone who wants to enable that |
| * check should change the value of this variable to be the |
| * level of recursion that they want to check. Be careful setting |
| * this variable, if the number is too low, it may report an |
| * infinite loop situation, when there is none. |
| * Post version 1.0.0, we'll make this a runtime feature. |
| * |
| * @param limit A number that represents the limit of recursion, |
| * or -1 if no checking is to be done. |
| */ |
| public void setRecursionLimit(int limit) |
| { |
| m_stackGuard.setRecursionLimit(limit); |
| } |
| |
| /** |
| * Get the ResultTreeHandler object. |
| * |
| * @return The current ResultTreeHandler, which may not |
| * be the main result tree manager. |
| */ |
| public ResultTreeHandler getResultTreeHandler() |
| { |
| return m_resultTreeHandler; |
| } |
| |
| /** |
| * 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(); |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * Get an instance of the trace manager for this transformation. |
| * This object can be used to set trace listeners on various |
| * events during the transformation. |
| * |
| * @return A reference to the TraceManager, never null. |
| */ |
| public TraceManager getTraceManager() |
| { |
| return m_traceManager; |
| } |
| |
| /** |
| * 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(); |
| } |
| |
| //////////////////////// |
| // Implement Runnable // |
| //////////////////////// |
| |
| /** |
| * Base thread controler for xalan. Must be overriden with |
| * a derived class to support thread pooling. |
| * |
| * All thread-related stuff is in this class. |
| * |
| * <p><em>WARNING!</em> This class will probably move since the DTM |
| * CoroutineSAXParser depends on it. This class should move |
| * to the CoroutineSAXParser. You can use it, but be aware |
| * that your code will have to change when the move occurs.</p> |
| */ |
| public static class ThreadControler |
| { |
| |
| /** |
| * Will get a thread from the pool, execute the task |
| * and return the thread to the pool. |
| * |
| * The return value is used only to wait for completion |
| * |
| * |
| * NEEDSDOC @param task |
| * @param priority if >0 the task will run with the given priority |
| * ( doesn't seem to be used in xalan, since it's allways the default ) |
| * @returns The thread that is running the task, can be used |
| * to wait for completion |
| * |
| * NEEDSDOC ($objectName$) @return |
| */ |
| public Thread run(Runnable task, int priority) |
| { |
| |
| Thread t = new Thread(task); |
| |
| t.start(); |
| |
| // if( priority > 0 ) |
| // t.setPriority( priority ); |
| return t; |
| } |
| |
| /** |
| * Wait until the task is completed on the worker |
| * thread. |
| * |
| * NEEDSDOC @param worker |
| * NEEDSDOC @param task |
| * |
| * @throws InterruptedException |
| */ |
| public void waitThread(Thread worker, Runnable task) |
| throws InterruptedException |
| { |
| |
| // This should wait until the transformThread is considered not alive. |
| worker.join(); |
| } |
| } |
| |
| /** NEEDSDOC Field tpool */ |
| static ThreadControler tpool = new ThreadControler(); |
| |
| /** |
| * Change the ThreadControler that will be used to |
| * manage the transform threads. |
| * |
| * NEEDSDOC @param tp |
| */ |
| public static void setThreadControler(ThreadControler tp) |
| { |
| tpool = tp; |
| } |
| |
| /** |
| * Called by SourceTreeHandler to start the transformation |
| * in a separate thread |
| * |
| * NEEDSDOC @param priority |
| */ |
| public void runTransformThread(int priority) |
| { |
| |
| // used in SourceTreeHandler |
| Thread t = tpool.run(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() |
| { |
| tpool.run(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) |
| { |
| tpool.run(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 |
| { |
| tpool.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; |
| } |
| |
| /** |
| * Set the input source for the source tree, which is needed if the |
| * parse thread is not the main thread, in order for the parse |
| * thread's run method to get to the input source. |
| * |
| * @param source The input source for the source tree. |
| */ |
| public void setXMLSource(Source source) |
| { |
| m_xmlSource = source; |
| } |
| |
| /** |
| * Tell if the transform method is completed. |
| * |
| * @return True if transformNode has completed, or |
| * an exception was thrown. |
| */ |
| public boolean isTransformDone() |
| { |
| |
| synchronized (this) |
| { |
| return m_isTransformDone; |
| } |
| } |
| |
| /** |
| * Set if the transform method is completed. |
| * |
| * @param done True if transformNode has completed, or |
| * an exception was thrown. |
| */ |
| public void setIsTransformDone(boolean done) |
| { |
| |
| synchronized (this) |
| { |
| m_isTransformDone = done; |
| } |
| } |
| |
| /** |
| * 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; |
| 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; |
| |
| // 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; |
| |
| 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. |
| |
| /** |
| * This will get a snapshot of the current executing context |
| * |
| * |
| * @return TransformerSnapshot object, snapshot of executing context |
| */ |
| public TransformSnapshot getSnapshot() |
| { |
| return new TransformSnapshotImpl(this); |
| } |
| |
| /** |
| * This will execute the following XSLT instructions |
| * from the snapshot point, after the stylesheet execution |
| * context has been reset from the snapshot point. |
| * |
| * @param ts The snapshot of where to start execution |
| * |
| * @throws TransformerException |
| */ |
| public void executeFromSnapshot(TransformSnapshot ts) |
| throws TransformerException |
| { |
| |
| ElemTemplateElement template = getMatchedTemplate(); |
| int child = getMatchedNode(); |
| |
| pushElemTemplateElement(template); //needed?? |
| m_xcontext.pushCurrentNode(child); //needed?? |
| this.executeChildTemplates(template, true); // getResultTreeHandler()); |
| } |
| |
| /** |
| * This will reset the stylesheet execution context |
| * from the snapshot point. |
| * |
| * @param ts The snapshot of where to start execution |
| */ |
| public void resetToStylesheet(TransformSnapshot ts) |
| { |
| ((TransformSnapshotImpl) ts).apply(this); |
| } |
| |
| /** |
| * NEEDSDOC Method stopTransformation |
| * |
| */ |
| public void stopTransformation(){} |
| |
| /** |
| * 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; |
| } |
| } |
| } // end TransformerImpl class |
| |