aboutsummaryrefslogtreecommitdiff
path: root/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java')
-rw-r--r--src/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java1384
1 files changed, 1384 insertions, 0 deletions
diff --git a/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java b/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
new file mode 100644
index 0000000..6af03b7
--- /dev/null
+++ b/src/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java
@@ -0,0 +1,1384 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * $Id: TransformerImpl.java,v 1.10 2007/06/13 01:57:09 joehw Exp $
+ */
+
+package com.sun.org.apache.xalan.internal.xsltc.trax;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.UnknownServiceException;
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.lang.reflect.Constructor;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamReader;
+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.dom.DOMSource;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stax.StAXResult;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
+
+import com.sun.org.apache.xalan.internal.xsltc.DOM;
+import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
+import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
+import com.sun.org.apache.xalan.internal.xsltc.StripFilter;
+import com.sun.org.apache.xalan.internal.xsltc.Translet;
+import com.sun.org.apache.xalan.internal.xsltc.TransletException;
+import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;
+import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
+import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
+import com.sun.org.apache.xalan.internal.xsltc.dom.DOMWSFilter;
+import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl;
+import com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager;
+import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
+import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;
+import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
+
+import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
+import com.sun.org.apache.xml.internal.utils.XMLReaderManager;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.LexicalHandler;
+
+/**
+ * @author Morten Jorgensen
+ * @author G. Todd Miller
+ * @author Santiago Pericas-Geertsen
+ */
+public final class TransformerImpl extends Transformer
+ implements DOMCache, ErrorListener
+{
+ private final static String EMPTY_STRING = "";
+ private final static String NO_STRING = "no";
+ private final static String YES_STRING = "yes";
+ private final static String XML_STRING = "xml";
+
+ private final static String LEXICAL_HANDLER_PROPERTY =
+ "http://xml.org/sax/properties/lexical-handler";
+ private static final String NAMESPACE_FEATURE =
+ "http://xml.org/sax/features/namespaces";
+
+ /**
+ * Namespace prefixes feature for {@link XMLReader}.
+ */
+ private static final String NAMESPACE_PREFIXES_FEATURE =
+ "http://xml.org/sax/features/namespace-prefixes";
+
+ /**
+ * A reference to the translet or null if the identity transform.
+ */
+ private AbstractTranslet _translet = null;
+
+ /**
+ * The output method of this transformation.
+ */
+ private String _method = null;
+
+ /**
+ * The output encoding of this transformation.
+ */
+ private String _encoding = null;
+
+ /**
+ * The systemId set in input source.
+ */
+ private String _sourceSystemId = null;
+
+ /**
+ * An error listener for runtime errors.
+ */
+ private ErrorListener _errorListener = this;
+
+ /**
+ * A reference to a URI resolver for calls to document().
+ */
+ private URIResolver _uriResolver = null;
+
+ /**
+ * Output properties of this transformer instance.
+ */
+ private Properties _properties, _propertiesClone;
+
+ /**
+ * A reference to an output handler factory.
+ */
+ private TransletOutputHandlerFactory _tohFactory = null;
+
+ /**
+ * A reference to a internal DOM represenation of the input.
+ */
+ private DOM _dom = null;
+
+ /**
+ * Number of indent spaces to add when indentation is on.
+ */
+ private int _indentNumber;
+
+ /**
+ * A reference to the transformer factory that this templates
+ * object belongs to.
+ */
+ private TransformerFactoryImpl _tfactory = null;
+
+ /**
+ * A reference to the output stream, if we create one in our code.
+ */
+ private OutputStream _ostream = null;
+
+ /**
+ * A reference to the XSLTCDTMManager which is used to build the DOM/DTM
+ * for this transformer.
+ */
+ private XSLTCDTMManager _dtmManager = null;
+
+ /**
+ * A reference to an object that creates and caches XMLReader objects.
+ */
+ private XMLReaderManager _readerManager = XMLReaderManager.getInstance();
+
+ /**
+ * A flag indicating whether we use incremental building of the DTM.
+ */
+ //private boolean _isIncremental = false;
+
+ /**
+ * A flag indicating whether this transformer implements the identity
+ * transform.
+ */
+ private boolean _isIdentity = false;
+
+ /**
+ * State of the secure processing feature.
+ */
+ private boolean _isSecureProcessing = false;
+
+ /**
+ * A hashtable to store parameters for the identity transform. These
+ * are not needed during the transformation, but we must keep track of
+ * them to be fully complaint with the JAXP API.
+ */
+ private Hashtable _parameters = null;
+
+ /**
+ * This class wraps an ErrorListener into a MessageHandler in order to
+ * capture messages reported via xsl:message.
+ */
+ static class MessageHandler
+ extends com.sun.org.apache.xalan.internal.xsltc.runtime.MessageHandler
+ {
+ private ErrorListener _errorListener;
+
+ public MessageHandler(ErrorListener errorListener) {
+ _errorListener = errorListener;
+ }
+
+ public void displayMessage(String msg) {
+ if(_errorListener == null) {
+ System.err.println(msg);
+ }
+ else {
+ try {
+ _errorListener.warning(new TransformerException(msg));
+ }
+ catch (TransformerException e) {
+ // ignored
+ }
+ }
+ }
+ }
+
+ protected TransformerImpl(Properties outputProperties, int indentNumber,
+ TransformerFactoryImpl tfactory)
+ {
+ this(null, outputProperties, indentNumber, tfactory);
+ _isIdentity = true;
+ // _properties.put(OutputKeys.METHOD, "xml");
+ }
+
+ protected TransformerImpl(Translet translet, Properties outputProperties,
+ int indentNumber, TransformerFactoryImpl tfactory)
+ {
+ _translet = (AbstractTranslet) translet;
+ _properties = createOutputProperties(outputProperties);
+ _propertiesClone = (Properties) _properties.clone();
+ _indentNumber = indentNumber;
+ _tfactory = tfactory;
+ //_isIncremental = tfactory._incremental;
+ }
+
+ /**
+ * Return the state of the secure processing feature.
+ */
+ public boolean isSecureProcessing() {
+ return _isSecureProcessing;
+ }
+
+ /**
+ * Set the state of the secure processing feature.
+ */
+ public void setSecureProcessing(boolean flag) {
+ _isSecureProcessing = flag;
+ }
+
+ /**
+ * Returns the translet wrapped inside this Transformer or
+ * null if this is the identity transform.
+ */
+ protected AbstractTranslet getTranslet() {
+ return _translet;
+ }
+
+ public boolean isIdentity() {
+ return _isIdentity;
+ }
+
+ /**
+ * Implements JAXP's Transformer.transform()
+ *
+ * @param source Contains the input XML document
+ * @param result Will contain the output from the transformation
+ * @throws TransformerException
+ */
+ public void transform(Source source, Result result)
+ throws TransformerException
+ {
+ if (!_isIdentity) {
+ if (_translet == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_TRANSLET_ERR);
+ throw new TransformerException(err.toString());
+ }
+ // Pass output properties to the translet
+ transferOutputProperties(_translet);
+ }
+
+ final SerializationHandler toHandler = getOutputHandler(result);
+ if (toHandler == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR);
+ throw new TransformerException(err.toString());
+ }
+
+ if (_uriResolver != null && !_isIdentity) {
+ _translet.setDOMCache(this);
+ }
+
+ // Pass output properties to handler if identity
+ if (_isIdentity) {
+ transferOutputProperties(toHandler);
+ }
+
+ transform(source, toHandler, _encoding);
+ try{
+ if (result instanceof DOMResult) {
+ ((DOMResult)result).setNode(_tohFactory.getNode());
+ } else if (result instanceof StAXResult) {
+ if (((StAXResult) result).getXMLEventWriter() != null)
+ {
+ (_tohFactory.getXMLEventWriter()).flush();
+ }
+ else if (((StAXResult) result).getXMLStreamWriter() != null) {
+ (_tohFactory.getXMLStreamWriter()).flush();
+ //result = new StAXResult(_tohFactory.getXMLStreamWriter());
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("Result writing error");
+ }
+ }
+
+ /**
+ * Create an output handler for the transformation output based on
+ * the type and contents of the TrAX Result object passed to the
+ * transform() method.
+ */
+ public SerializationHandler getOutputHandler(Result result)
+ throws TransformerException
+ {
+ // Get output method using get() to ignore defaults
+ _method = (String) _properties.get(OutputKeys.METHOD);
+
+ // Get encoding using getProperty() to use defaults
+ _encoding = (String) _properties.getProperty(OutputKeys.ENCODING);
+
+ _tohFactory = TransletOutputHandlerFactory.newInstance();
+ _tohFactory.setEncoding(_encoding);
+ if (_method != null) {
+ _tohFactory.setOutputMethod(_method);
+ }
+
+ // Set indentation number in the factory
+ if (_indentNumber >= 0) {
+ _tohFactory.setIndentNumber(_indentNumber);
+ }
+
+ // Return the content handler for this Result object
+ try {
+ // Result object could be SAXResult, DOMResult, or StreamResult
+ if (result instanceof SAXResult) {
+ final SAXResult target = (SAXResult)result;
+ final ContentHandler handler = target.getHandler();
+
+ _tohFactory.setHandler(handler);
+
+ /**
+ * Fix for bug 24414
+ * If the lexicalHandler is set then we need to get that
+ * for obtaining the lexical information
+ */
+ LexicalHandler lexicalHandler = target.getLexicalHandler();
+
+ if (lexicalHandler != null ) {
+ _tohFactory.setLexicalHandler(lexicalHandler);
+ }
+
+ _tohFactory.setOutputType(TransletOutputHandlerFactory.SAX);
+ return _tohFactory.getSerializationHandler();
+ }
+ else if (result instanceof StAXResult) {
+ if (((StAXResult) result).getXMLEventWriter() != null)
+ _tohFactory.setXMLEventWriter(((StAXResult) result).getXMLEventWriter());
+ else if (((StAXResult) result).getXMLStreamWriter() != null)
+ _tohFactory.setXMLStreamWriter(((StAXResult) result).getXMLStreamWriter());
+ _tohFactory.setOutputType(TransletOutputHandlerFactory.STAX);
+ return _tohFactory.getSerializationHandler();
+ }
+ else if (result instanceof DOMResult) {
+ _tohFactory.setNode(((DOMResult) result).getNode());
+ _tohFactory.setNextSibling(((DOMResult) result).getNextSibling());
+ _tohFactory.setOutputType(TransletOutputHandlerFactory.DOM);
+ return _tohFactory.getSerializationHandler();
+ }
+ else if (result instanceof StreamResult) {
+ // Get StreamResult
+ final StreamResult target = (StreamResult) result;
+
+ // StreamResult may have been created with a java.io.File,
+ // java.io.Writer, java.io.OutputStream or just a String
+ // systemId.
+
+ _tohFactory.setOutputType(TransletOutputHandlerFactory.STREAM);
+
+ // try to get a Writer from Result object
+ final Writer writer = target.getWriter();
+ if (writer != null) {
+ _tohFactory.setWriter(writer);
+ return _tohFactory.getSerializationHandler();
+ }
+
+ // or try to get an OutputStream from Result object
+ final OutputStream ostream = target.getOutputStream();
+ if (ostream != null) {
+ _tohFactory.setOutputStream(ostream);
+ return _tohFactory.getSerializationHandler();
+ }
+
+ // or try to get just a systemId string from Result object
+ String systemId = result.getSystemId();
+ if (systemId == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_RESULT_ERR);
+ throw new TransformerException(err.toString());
+ }
+
+ // System Id may be in one of several forms, (1) a uri
+ // that starts with 'file:', (2) uri that starts with 'http:'
+ // or (3) just a filename on the local system.
+ URL url = null;
+ if (systemId.startsWith("file:")) {
+ // if StreamResult(File) or setSystemID(File) was used,
+ // the systemId will be URI encoded as a result of File.toURI(),
+ // it must be decoded for use by URL
+ try{
+ Class clazz = ObjectFactory.findProviderClass("java.net.URI", ObjectFactory.findClassLoader(), true);
+ Constructor construct = clazz.getConstructor(new Class[] {java.lang.String.class} );
+ URI uri = (URI) construct.newInstance(new Object[]{systemId}) ;
+ systemId = "file:";
+
+ String host = uri.getHost(); // decoded String
+ String path = uri.getPath(); //decoded String
+ if (path == null) {
+ path = "";
+ }
+
+ // if host (URI authority) then file:// + host + path
+ // else just path (may be absolute or relative)
+ if (host != null) {
+ systemId += "//" + host + path;
+ } else {
+ systemId += "//" + path;
+ }
+ }
+ catch(ClassNotFoundException e){
+ // running on J2SE 1.3 which doesn't have URI Class so OK to ignore
+ //ClassNotFoundException.
+ }
+ catch (Exception exception) {
+ // URI exception which means nothing can be done so OK to ignore
+ }
+
+ url = new URL(systemId);
+ _ostream = new FileOutputStream(url.getFile());
+ _tohFactory.setOutputStream(_ostream);
+ return _tohFactory.getSerializationHandler();
+ }
+ else if (systemId.startsWith("http:")) {
+ url = new URL(systemId);
+ final URLConnection connection = url.openConnection();
+ _tohFactory.setOutputStream(_ostream = connection.getOutputStream());
+ return _tohFactory.getSerializationHandler();
+ }
+ else {
+ // system id is just a filename
+ _tohFactory.setOutputStream(
+ _ostream = new FileOutputStream(new File(systemId)));
+ return _tohFactory.getSerializationHandler();
+ }
+ }
+ }
+ // If we cannot write to the location specified by the SystemId
+ catch (UnknownServiceException e) {
+ throw new TransformerException(e);
+ }
+ catch (ParserConfigurationException e) {
+ throw new TransformerException(e);
+ }
+ // If we cannot create the file specified by the SystemId
+ catch (IOException e) {
+ throw new TransformerException(e);
+ }
+ return null;
+ }
+
+ /**
+ * Set the internal DOM that will be used for the next transformation
+ */
+ protected void setDOM(DOM dom) {
+ _dom = dom;
+ }
+
+ /**
+ * Builds an internal DOM from a TrAX Source object
+ */
+ private DOM getDOM(Source source) throws TransformerException {
+ try {
+ DOM dom = null;
+
+ if (source != null) {
+ DTMWSFilter wsfilter;
+ if (_translet != null && _translet instanceof StripFilter) {
+ wsfilter = new DOMWSFilter(_translet);
+ } else {
+ wsfilter = null;
+ }
+
+ boolean hasIdCall = (_translet != null) ? _translet.hasIdCall()
+ : false;
+
+ if (_dtmManager == null) {
+ _dtmManager =
+ (XSLTCDTMManager)_tfactory.getDTMManagerClass()
+ .newInstance();
+ }
+ dom = (DOM)_dtmManager.getDTM(source, false, wsfilter, true,
+ false, false, 0, hasIdCall);
+ } else if (_dom != null) {
+ dom = _dom;
+ _dom = null; // use only once, so reset to 'null'
+ } else {
+ return null;
+ }
+
+ if (!_isIdentity) {
+ // Give the translet the opportunity to make a prepass of
+ // the document, in case it can extract useful information early
+ _translet.prepassDocument(dom);
+ }
+
+ return dom;
+
+ }
+ catch (Exception e) {
+ if (_errorListener != null) {
+ postErrorToListener(e.getMessage());
+ }
+ throw new TransformerException(e);
+ }
+ }
+
+ /**
+ * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl}
+ * object that create this <code>Transformer</code>.
+ */
+ protected TransformerFactoryImpl getTransformerFactory() {
+ return _tfactory;
+ }
+
+ /**
+ * Returns the {@link com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory}
+ * object that create the <code>TransletOutputHandler</code>.
+ */
+ protected TransletOutputHandlerFactory getTransletOutputHandlerFactory() {
+ return _tohFactory;
+ }
+
+ private void transformIdentity(Source source, SerializationHandler handler)
+ throws Exception
+ {
+ // Get systemId from source
+ if (source != null) {
+ _sourceSystemId = source.getSystemId();
+ }
+
+ if (source instanceof StreamSource) {
+ final StreamSource stream = (StreamSource) source;
+ final InputStream streamInput = stream.getInputStream();
+ final Reader streamReader = stream.getReader();
+ final XMLReader reader = _readerManager.getXMLReader();
+
+ try {
+ // Hook up reader and output handler
+ try {
+ reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
+ reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true);
+ } catch (SAXException e) {
+ // Falls through
+ }
+ reader.setContentHandler(handler);
+
+ // Create input source from source
+ InputSource input;
+ if (streamInput != null) {
+ input = new InputSource(streamInput);
+ input.setSystemId(_sourceSystemId);
+ }
+ else if (streamReader != null) {
+ input = new InputSource(streamReader);
+ input.setSystemId(_sourceSystemId);
+ }
+ else if (_sourceSystemId != null) {
+ input = new InputSource(_sourceSystemId);
+ }
+ else {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
+ throw new TransformerException(err.toString());
+ }
+
+ // Start pushing SAX events
+ reader.parse(input);
+ } finally {
+ _readerManager.releaseXMLReader(reader);
+ }
+ } else if (source instanceof SAXSource) {
+ final SAXSource sax = (SAXSource) source;
+ XMLReader reader = sax.getXMLReader();
+ final InputSource input = sax.getInputSource();
+ boolean userReader = true;
+
+ try {
+ // Create a reader if not set by user
+ if (reader == null) {
+ reader = _readerManager.getXMLReader();
+ userReader = false;
+ }
+
+ // Hook up reader and output handler
+ try {
+ reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
+ reader.setFeature(NAMESPACE_PREFIXES_FEATURE, true);
+ } catch (SAXException e) {
+ // Falls through
+ }
+ reader.setContentHandler(handler);
+
+ // Start pushing SAX events
+ reader.parse(input);
+ } finally {
+ if (!userReader) {
+ _readerManager.releaseXMLReader(reader);
+ }
+ }
+ } else if (source instanceof StAXSource) {
+ final StAXSource staxSource = (StAXSource)source;
+ StAXEvent2SAX staxevent2sax = null;
+ StAXStream2SAX staxStream2SAX = null;
+ if (staxSource.getXMLEventReader() != null) {
+ final XMLEventReader xmlEventReader = staxSource.getXMLEventReader();
+ staxevent2sax = new StAXEvent2SAX(xmlEventReader);
+ staxevent2sax.setContentHandler(handler);
+ staxevent2sax.parse();
+ handler.flushPending();
+ } else if (staxSource.getXMLStreamReader() != null) {
+ final XMLStreamReader xmlStreamReader = staxSource.getXMLStreamReader();
+ staxStream2SAX = new StAXStream2SAX(xmlStreamReader);
+ staxStream2SAX.setContentHandler(handler);
+ staxStream2SAX.parse();
+ handler.flushPending();
+ }
+ } else if (source instanceof DOMSource) {
+ final DOMSource domsrc = (DOMSource) source;
+ new DOM2TO(domsrc.getNode(), handler).parse();
+ } else if (source instanceof XSLTCSource) {
+ final DOM dom = ((XSLTCSource) source).getDOM(null, _translet);
+ ((SAXImpl)dom).copy(handler);
+ } else {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
+ throw new TransformerException(err.toString());
+ }
+ }
+
+ /**
+ * Internal transformation method - uses the internal APIs of XSLTC
+ */
+ private void transform(Source source, SerializationHandler handler,
+ String encoding) throws TransformerException
+ {
+ try {
+ /*
+ * According to JAXP1.2, new SAXSource()/StreamSource()
+ * should create an empty input tree, with a default root node.
+ * new DOMSource()creates an empty document using DocumentBuilder.
+ * newDocument(); Use DocumentBuilder.newDocument() for all 3
+ * situations, since there is no clear spec. how to create
+ * an empty tree when both SAXSource() and StreamSource() are used.
+ */
+ if ((source instanceof StreamSource && source.getSystemId()==null
+ && ((StreamSource)source).getInputStream()==null &&
+ ((StreamSource)source).getReader()==null)||
+ (source instanceof SAXSource &&
+ ((SAXSource)source).getInputSource()==null &&
+ ((SAXSource)source).getXMLReader()==null )||
+ (source instanceof DOMSource &&
+ ((DOMSource)source).getNode()==null)){
+ DocumentBuilderFactory builderF =
+ DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder =
+ builderF.newDocumentBuilder();
+ String systemID = source.getSystemId();
+ source = new DOMSource(builder.newDocument());
+
+ // Copy system ID from original, empty Source to new
+ if (systemID != null) {
+ source.setSystemId(systemID);
+ }
+ }
+ if (_isIdentity) {
+ transformIdentity(source, handler);
+ } else {
+ _translet.transform(getDOM(source), handler);
+ }
+ } catch (TransletException e) {
+ if (_errorListener != null) postErrorToListener(e.getMessage());
+ throw new TransformerException(e);
+ } catch (RuntimeException e) {
+ if (_errorListener != null) postErrorToListener(e.getMessage());
+ throw new TransformerException(e);
+ } catch (Exception e) {
+ if (_errorListener != null) postErrorToListener(e.getMessage());
+ throw new TransformerException(e);
+ } finally {
+ _dtmManager = null;
+ }
+
+ // If we create an output stream for the Result, we need to close it after the transformation.
+ if (_ostream != null) {
+ try {
+ _ostream.close();
+ }
+ catch (IOException e) {}
+ _ostream = null;
+ }
+ }
+
+ /**
+ * Implements JAXP's Transformer.getErrorListener()
+ * Get the error event handler in effect for the transformation.
+ *
+ * @return The error event handler currently in effect
+ */
+ public ErrorListener getErrorListener() {
+ return _errorListener;
+ }
+
+ /**
+ * Implements JAXP's Transformer.setErrorListener()
+ * Set the error event listener in effect for the transformation.
+ * Register a message handler in the translet in order to forward
+ * xsl:messages to error listener.
+ *
+ * @param listener The error event listener to use
+ * @throws IllegalArgumentException
+ */
+ public void setErrorListener(ErrorListener listener)
+ throws IllegalArgumentException {
+ if (listener == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.ERROR_LISTENER_NULL_ERR,
+ "Transformer");
+ throw new IllegalArgumentException(err.toString());
+ }
+ _errorListener = listener;
+
+ // Register a message handler to report xsl:messages
+ if (_translet != null)
+ _translet.setMessageHandler(new MessageHandler(_errorListener));
+ }
+
+ /**
+ * Inform TrAX error listener of an error
+ */
+ private void postErrorToListener(String message) {
+ try {
+ _errorListener.error(new TransformerException(message));
+ }
+ catch (TransformerException e) {
+ // ignored - transformation cannot be continued
+ }
+ }
+
+ /**
+ * Inform TrAX error listener of a warning
+ */
+ private void postWarningToListener(String message) {
+ try {
+ _errorListener.warning(new TransformerException(message));
+ }
+ catch (TransformerException e) {
+ // ignored - transformation cannot be continued
+ }
+ }
+
+ /**
+ * The translet stores all CDATA sections set in the <xsl:output> element
+ * in a Hashtable. This method will re-construct the whitespace separated
+ * list of elements given in the <xsl:output> element.
+ */
+ private String makeCDATAString(Hashtable cdata) {
+ // Return a 'null' string if no CDATA section elements were specified
+ if (cdata == null) return null;
+
+ StringBuffer result = new StringBuffer();
+
+ // Get an enumeration of all the elements in the hashtable
+ Enumeration elements = cdata.keys();
+ if (elements.hasMoreElements()) {
+ result.append((String)elements.nextElement());
+ while (elements.hasMoreElements()) {
+ String element = (String)elements.nextElement();
+ result.append(' ');
+ result.append(element);
+ }
+ }
+
+ return(result.toString());
+ }
+
+ /**
+ * Implements JAXP's Transformer.getOutputProperties().
+ * Returns a copy of the output properties for the transformation. This is
+ * a set of layered properties. The first layer contains properties set by
+ * calls to setOutputProperty() and setOutputProperties() on this class,
+ * and the output settings defined in the stylesheet's <xsl:output>
+ * element makes up the second level, while the default XSLT output
+ * settings are returned on the third level.
+ *
+ * @return Properties in effect for this Transformer
+ */
+ public Properties getOutputProperties() {
+ return (Properties) _properties.clone();
+ }
+
+ /**
+ * Implements JAXP's Transformer.getOutputProperty().
+ * 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 contains the name of the property
+ * @throws IllegalArgumentException if the property name is not known
+ */
+ public String getOutputProperty(String name)
+ throws IllegalArgumentException
+ {
+ if (!validOutputProperty(name)) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
+ throw new IllegalArgumentException(err.toString());
+ }
+ return _properties.getProperty(name);
+ }
+
+ /**
+ * Implements JAXP's Transformer.setOutputProperties().
+ * Set the output properties for the transformation. These properties
+ * will override properties set in the Templates with xsl:output.
+ * Unrecognised properties will be quitely ignored.
+ *
+ * @param properties The properties to use for the Transformer
+ * @throws IllegalArgumentException Never, errors are ignored
+ */
+ public void setOutputProperties(Properties properties)
+ throws IllegalArgumentException
+ {
+ if (properties != null) {
+ final Enumeration names = properties.propertyNames();
+
+ while (names.hasMoreElements()) {
+ final String name = (String) names.nextElement();
+
+ // Ignore lower layer properties
+ if (isDefaultProperty(name, properties)) continue;
+
+ if (validOutputProperty(name)) {
+ _properties.setProperty(name, properties.getProperty(name));
+ }
+ else {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
+ throw new IllegalArgumentException(err.toString());
+ }
+ }
+ }
+ else {
+ _properties = _propertiesClone;
+ }
+ }
+
+ /**
+ * Implements JAXP's Transformer.setOutputProperty().
+ * 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 The name of the property to set
+ * @param value The value to assign to the property
+ * @throws IllegalArgumentException Never, errors are ignored
+ */
+ public void setOutputProperty(String name, String value)
+ throws IllegalArgumentException
+ {
+ if (!validOutputProperty(name)) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
+ throw new IllegalArgumentException(err.toString());
+ }
+ _properties.setProperty(name, value);
+ }
+
+ /**
+ * Internal method to pass any properties to the translet prior to
+ * initiating the transformation
+ */
+ private void transferOutputProperties(AbstractTranslet translet)
+ {
+ // Return right now if no properties are set
+ if (_properties == null) return;
+
+ // Get a list of all the defined properties
+ Enumeration names = _properties.propertyNames();
+ while (names.hasMoreElements()) {
+ // Note the use of get() instead of getProperty()
+ String name = (String) names.nextElement();
+ String value = (String) _properties.get(name);
+
+ // Ignore default properties
+ if (value == null) continue;
+
+ // Pass property value to translet - override previous setting
+ if (name.equals(OutputKeys.ENCODING)) {
+ translet._encoding = value;
+ }
+ else if (name.equals(OutputKeys.METHOD)) {
+ translet._method = value;
+ }
+ else if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
+ translet._doctypePublic = value;
+ }
+ else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
+ translet._doctypeSystem = value;
+ }
+ else if (name.equals(OutputKeys.MEDIA_TYPE)) {
+ translet._mediaType = value;
+ }
+ else if (name.equals(OutputKeys.STANDALONE)) {
+ translet._standalone = value;
+ }
+ else if (name.equals(OutputKeys.VERSION)) {
+ translet._version = value;
+ }
+ else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
+ translet._omitHeader =
+ (value != null && value.toLowerCase().equals("yes"));
+ }
+ else if (name.equals(OutputKeys.INDENT)) {
+ translet._indent =
+ (value != null && value.toLowerCase().equals("yes"));
+ }
+ else if (name.equals(OutputPropertiesFactory.S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL +"indent-amount")) {
+ if (value != null) {
+ translet._indentamount = Integer.parseInt(value);
+ }
+ }
+ else if (name.equals(OutputPropertiesFactory.S_BUILTIN_EXTENSIONS_UNIVERSAL +"indent-amount")) {
+ if (value != null) {
+ translet._indentamount = Integer.parseInt(value);
+ }
+ }
+ else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
+ if (value != null) {
+ translet._cdata = null; // clear previous setting
+ StringTokenizer e = new StringTokenizer(value);
+ while (e.hasMoreTokens()) {
+ translet.addCdataElement(e.nextToken());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * This method is used to pass any properties to the output handler
+ * when running the identity transform.
+ */
+ public void transferOutputProperties(SerializationHandler handler)
+ {
+ // Return right now if no properties are set
+ if (_properties == null) return;
+
+ String doctypePublic = null;
+ String doctypeSystem = null;
+
+ // Get a list of all the defined properties
+ Enumeration names = _properties.propertyNames();
+ while (names.hasMoreElements()) {
+ // Note the use of get() instead of getProperty()
+ String name = (String) names.nextElement();
+ String value = (String) _properties.get(name);
+
+ // Ignore default properties
+ if (value == null) continue;
+
+ // Pass property value to translet - override previous setting
+ if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
+ doctypePublic = value;
+ }
+ else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
+ doctypeSystem = value;
+ }
+ else if (name.equals(OutputKeys.MEDIA_TYPE)) {
+ handler.setMediaType(value);
+ }
+ else if (name.equals(OutputKeys.STANDALONE)) {
+ handler.setStandalone(value);
+ }
+ else if (name.equals(OutputKeys.VERSION)) {
+ handler.setVersion(value);
+ }
+ else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
+ handler.setOmitXMLDeclaration(
+ value != null && value.toLowerCase().equals("yes"));
+ }
+ else if (name.equals(OutputKeys.INDENT)) {
+ handler.setIndent(
+ value != null && value.toLowerCase().equals("yes"));
+ }
+ else if (name.equals(OutputPropertiesFactory.S_BUILTIN_OLD_EXTENSIONS_UNIVERSAL +"indent-amount")) {
+ if (value != null) {
+ handler.setIndentAmount(Integer.parseInt(value));
+ }
+ }
+ else if (name.equals(OutputPropertiesFactory.S_BUILTIN_EXTENSIONS_UNIVERSAL +"indent-amount")) {
+ if (value != null) {
+ handler.setIndentAmount(Integer.parseInt(value));
+ }
+ }
+ else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
+ if (value != null) {
+ StringTokenizer e = new StringTokenizer(value);
+ Vector uriAndLocalNames = null;
+ while (e.hasMoreTokens()) {
+ final String token = e.nextToken();
+
+ // look for the last colon, as the String may be
+ // something like "http://abc.com:local"
+ int lastcolon = token.lastIndexOf(':');
+ String uri;
+ String localName;
+ if (lastcolon > 0) {
+ uri = token.substring(0, lastcolon);
+ localName = token.substring(lastcolon+1);
+ } else {
+ // no colon at all, lets hope this is the
+ // local name itself then
+ uri = null;
+ localName = token;
+ }
+
+ if (uriAndLocalNames == null) {
+ uriAndLocalNames = new Vector();
+ }
+ // add the uri/localName as a pair, in that order
+ uriAndLocalNames.addElement(uri);
+ uriAndLocalNames.addElement(localName);
+ }
+ handler.setCdataSectionElements(uriAndLocalNames);
+ }
+ }
+ }
+
+ // Call setDoctype() if needed
+ if (doctypePublic != null || doctypeSystem != null) {
+ handler.setDoctype(doctypeSystem, doctypePublic);
+ }
+ }
+
+ /**
+ * Internal method to create the initial set of properties. There
+ * are two layers of properties: the default layer and the base layer.
+ * The latter contains properties defined in the stylesheet or by
+ * the user using this API.
+ */
+ private Properties createOutputProperties(Properties outputProperties) {
+ final Properties defaults = new Properties();
+ setDefaults(defaults, "xml");
+
+ // Copy propeties set in stylesheet to base
+ final Properties base = new Properties(defaults);
+ if (outputProperties != null) {
+ final Enumeration names = outputProperties.propertyNames();
+ while (names.hasMoreElements()) {
+ final String name = (String) names.nextElement();
+ base.setProperty(name, outputProperties.getProperty(name));
+ }
+ }
+ else {
+ base.setProperty(OutputKeys.ENCODING, _translet._encoding);
+ if (_translet._method != null)
+ base.setProperty(OutputKeys.METHOD, _translet._method);
+ }
+
+ // Update defaults based on output method
+ final String method = base.getProperty(OutputKeys.METHOD);
+ if (method != null) {
+ if (method.equals("html")) {
+ setDefaults(defaults,"html");
+ }
+ else if (method.equals("text")) {
+ setDefaults(defaults,"text");
+ }
+ }
+
+ return base;
+ }
+
+ /**
+ * Internal method to get the default properties from the
+ * serializer factory and set them on the property object.
+ * @param props a java.util.Property object on which the properties are set.
+ * @param method The output method type, one of "xml", "text", "html" ...
+ */
+ private void setDefaults(Properties props, String method)
+ {
+ final Properties method_props =
+ OutputPropertiesFactory.getDefaultMethodProperties(method);
+ {
+ final Enumeration names = method_props.propertyNames();
+ while (names.hasMoreElements())
+ {
+ final String name = (String)names.nextElement();
+ props.setProperty(name, method_props.getProperty(name));
+ }
+ }
+ }
+ /**
+ * Verifies if a given output property name is a property defined in
+ * the JAXP 1.1 / TrAX spec
+ */
+ private boolean validOutputProperty(String name) {
+ return (name.equals(OutputKeys.ENCODING) ||
+ name.equals(OutputKeys.METHOD) ||
+ name.equals(OutputKeys.INDENT) ||
+ name.equals(OutputKeys.DOCTYPE_PUBLIC) ||
+ name.equals(OutputKeys.DOCTYPE_SYSTEM) ||
+ name.equals(OutputKeys.CDATA_SECTION_ELEMENTS) ||
+ name.equals(OutputKeys.MEDIA_TYPE) ||
+ name.equals(OutputKeys.OMIT_XML_DECLARATION) ||
+ name.equals(OutputKeys.STANDALONE) ||
+ name.equals(OutputKeys.VERSION) ||
+ name.charAt(0) == '{');
+ }
+
+ /**
+ * Checks if a given output property is default (2nd layer only)
+ */
+ private boolean isDefaultProperty(String name, Properties properties) {
+ return (properties.get(name) == null);
+ }
+
+ /**
+ * Implements JAXP's Transformer.setParameter()
+ * Add a parameter for the transformation. The parameter is simply passed
+ * on to the translet - no validation is performed - so any unused
+ * parameters are quitely ignored by the translet.
+ *
+ * @param name The name of the parameter
+ * @param value The value to assign to the parameter
+ */
+ public void setParameter(String name, Object value) {
+
+ if (value == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_SET_PARAM_VALUE, name);
+ throw new IllegalArgumentException(err.toString());
+ }
+
+ if (_isIdentity) {
+ if (_parameters == null) {
+ _parameters = new Hashtable();
+ }
+ _parameters.put(name, value);
+ }
+ else {
+ _translet.addParameter(name, value);
+ }
+ }
+
+ /**
+ * Implements JAXP's Transformer.clearParameters()
+ * Clear all parameters set with setParameter. Clears the translet's
+ * parameter stack.
+ */
+ public void clearParameters() {
+ if (_isIdentity && _parameters != null) {
+ _parameters.clear();
+ }
+ else {
+ _translet.clearParameters();
+ }
+ }
+
+ /**
+ * Implements JAXP's Transformer.getParameter()
+ * Returns the value of a given parameter. Note that the translet will not
+ * keep values for parameters that were not defined in the stylesheet.
+ *
+ * @param name The name of the parameter
+ * @return An object that contains the value assigned to the parameter
+ */
+ public final Object getParameter(String name) {
+ if (_isIdentity) {
+ return (_parameters != null) ? _parameters.get(name) : null;
+ }
+ else {
+ return _translet.getParameter(name);
+ }
+ }
+
+ /**
+ * Implements JAXP's Transformer.getURIResolver()
+ * Set the object currently used to resolve URIs used in document().
+ *
+ * @return The URLResolver object currently in use
+ */
+ public URIResolver getURIResolver() {
+ return _uriResolver;
+ }
+
+ /**
+ * Implements JAXP's Transformer.setURIResolver()
+ * Set an object that will be used to resolve URIs used in document().
+ *
+ * @param resolver The URIResolver to use in document()
+ */
+ public void setURIResolver(URIResolver resolver) {
+ _uriResolver = resolver;
+ }
+
+ /**
+ * This class should only be used as a DOMCache for the translet if the
+ * URIResolver has been set.
+ *
+ * The method implements XSLTC's DOMCache interface, which is used to
+ * plug in an external document loader into a translet. This method acts
+ * as an adapter between TrAX's URIResolver interface and XSLTC's
+ * DOMCache interface. This approach is simple, but removes the
+ * possibility of using external document caches with XSLTC.
+ *
+ * @param baseURI The base URI used by the document call.
+ * @param href The href argument passed to the document function.
+ * @param translet A reference to the translet requesting the document
+ */
+ public DOM retrieveDocument(String baseURI, String href, Translet translet) {
+ try {
+ // Argument to document function was: document('');
+ if (href.length() == 0) {
+ href = new String(baseURI);
+ }
+
+ /*
+ * Fix for bug 24188
+ * Incase the _uriResolver.resolve(href,base) is null
+ * try to still retrieve the document before returning null
+ * and throwing the FileNotFoundException in
+ * com.sun.org.apache.xalan.internal.xsltc.dom.LoadDocument
+ *
+ */
+ Source resolvedSource = _uriResolver.resolve(href, baseURI);
+ if (resolvedSource == null) {
+ StreamSource streamSource = new StreamSource(
+ SystemIDResolver.getAbsoluteURI(href, baseURI));
+ return getDOM(streamSource) ;
+ }
+
+ return getDOM(resolvedSource);
+ }
+ catch (TransformerException e) {
+ if (_errorListener != null)
+ postErrorToListener("File not found: " + e.getMessage());
+ return(null);
+ }
+ }
+
+ /**
+ * Receive notification of a recoverable error.
+ * The transformer must continue to provide normal parsing events after
+ * invoking this method. It should still be possible for the application
+ * to process the document through to the end.
+ *
+ * @param e The warning information encapsulated in a transformer
+ * exception.
+ * @throws TransformerException if the application chooses to discontinue
+ * the transformation (always does in our case).
+ */
+ public void error(TransformerException e)
+ throws TransformerException
+ {
+ Throwable wrapped = e.getException();
+ if (wrapped != null) {
+ System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG,
+ e.getMessageAndLocation(),
+ wrapped.getMessage()));
+ } else {
+ System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG,
+ e.getMessageAndLocation()));
+ }
+ throw e;
+ }
+
+ /**
+ * Receive notification of a non-recoverable error.
+ * The application must assume that the transformation cannot continue
+ * after the Transformer has invoked this method, and should continue
+ * (if at all) only to collect addition error messages. In fact,
+ * Transformers are free to stop reporting events once this method has
+ * been invoked.
+ *
+ * @param e The warning information encapsulated in a transformer
+ * exception.
+ * @throws TransformerException if the application chooses to discontinue
+ * the transformation (always does in our case).
+ */
+ public void fatalError(TransformerException e)
+ throws TransformerException
+ {
+ Throwable wrapped = e.getException();
+ if (wrapped != null) {
+ System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG,
+ e.getMessageAndLocation(),
+ wrapped.getMessage()));
+ } else {
+ System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG,
+ e.getMessageAndLocation()));
+ }
+ throw e;
+ }
+
+ /**
+ * Receive notification of a warning.
+ * Transformers can use this method to report conditions that are not
+ * errors or fatal errors. The default behaviour is to take no action.
+ * After invoking this method, the Transformer must continue with the
+ * transformation. It should still be possible for the application to
+ * process the document through to the end.
+ *
+ * @param e The warning information encapsulated in a transformer
+ * exception.
+ * @throws TransformerException if the application chooses to discontinue
+ * the transformation (never does in our case).
+ */
+ public void warning(TransformerException e)
+ throws TransformerException
+ {
+ Throwable wrapped = e.getException();
+ if (wrapped != null) {
+ System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG,
+ e.getMessageAndLocation(),
+ wrapped.getMessage()));
+ } else {
+ System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG,
+ e.getMessageAndLocation()));
+ }
+ }
+
+ /**
+ * This method resets the Transformer to its original configuration
+ * Transformer code is reset to the same state it was when it was
+ * created
+ * @since 1.5
+ */
+ public void reset() {
+
+ _method = null;
+ _encoding = null;
+ _sourceSystemId = null;
+ _errorListener = this;
+ _uriResolver = null;
+ _dom = null;
+ _parameters = null;
+ _indentNumber = 0;
+ setOutputProperties (null);
+ _tohFactory = null;
+ _ostream = null;
+
+ }
+}