Package org.apache.xalan.xsltc.trax

Source Code of org.apache.xalan.xsltc.trax.TransformerImpl

/*
* @(#)$Id: TransformerImpl.java,v 1.63 2003/02/18 18:42:44 ilene Exp $
*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001-2003 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) 2001, Sun
* Microsystems., http://www.sun.com.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* @author Morten Jorgensen
* @author G. Todd Miller
* @author Santiago Pericas-Geertsen
*
*/

package org.apache.xalan.xsltc.trax;

import java.io.File;
import java.io.FileNotFoundException;
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.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.net.UnknownServiceException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.URIResolver;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.xalan.xsltc.DOMCache;
import org.apache.xalan.xsltc.Translet;
import org.apache.xalan.xsltc.TransletException;
import org.apache.xalan.xsltc.TransletOutputHandler;
import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
import org.apache.xalan.xsltc.dom.DOMBuilder;
import org.apache.xalan.xsltc.dom.DOMImpl;
import org.apache.xalan.xsltc.dom.DTDMonitor;
import org.apache.xalan.xsltc.runtime.AbstractTranslet;
import org.apache.xalan.xsltc.runtime.Hashtable;
import org.apache.xalan.xsltc.runtime.output.TransletOutputHandlerFactory;

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;

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";
   
    /**
     * 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 DOMImpl _dom = null;

    /**
     * DTD monitor needed for id()/key().
     */
    private DTDMonitor _dtdMonitor = 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 flag indicating whether this transformer implements the identity
     * transform.
     */
    private boolean _isIdentity = 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 org.apache.xalan.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;
    }

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

  if (result instanceof DOMResult) {
      ((DOMResult)result).setNode(_tohFactory.getNode());
  }
    }

    /**
     * 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 TransletOutputHandler 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);
    if (handler instanceof LexicalHandler) {
        _tohFactory.setLexicalHandler((LexicalHandler) handler);
    }
    _tohFactory.setOutputType(TransletOutputHandlerFactory.SAX);
    return _tohFactory.getTransletOutputHandler();
            }
      else if (result instanceof DOMResult) {
    _tohFactory.setNode(((DOMResult) result).getNode());
    _tohFactory.setOutputType(TransletOutputHandlerFactory.DOM);
    return _tohFactory.getTransletOutputHandler();
            }
      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.getTransletOutputHandler();
    }

    // or try to get an OutputStream from Result object
    final OutputStream ostream = target.getOutputStream();
    if (ostream != null) {
        _tohFactory.setOutputStream(ostream);
        return _tohFactory.getTransletOutputHandler();
    }

    // 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:")) {
                    url = new URL(systemId);
        _tohFactory.setOutputStream(
      new FileOutputStream(url.getFile()));
        return _tohFactory.getTransletOutputHandler();
                }
                else if (systemId.startsWith("http:")) {
                    url = new URL(systemId);
                    final URLConnection connection = url.openConnection();
        _tohFactory.setOutputStream(connection.getOutputStream());
        return _tohFactory.getTransletOutputHandler();
                }
                else {
                    // system id is just a filename
                    url = new File(systemId).toURL();
        _tohFactory.setOutputStream(
      new FileOutputStream(url.getFile()));
        return _tohFactory.getTransletOutputHandler();
                }
      }
  }
        // 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 DOMImpl that will be used for the next transformation
     */
    protected void setDOM(DOMImpl dom) {
  _dom = dom;
    }

    /**
     * Set the internal DOMImpl that will be used for the next transformation
     */
    protected void setDTDMonitor(DTDMonitor dtdMonitor) {
  _dtdMonitor = dtdMonitor;
    }

    /**
     * Builds an internal DOM from a TrAX Source object
     */
    private DOMImpl getDOM(Source source, int mask)
  throws TransformerException
    {
  try {
      DOMImpl dom = null;
      DTDMonitor dtd = null;

      // Get systemId from source
      if (source != null) {
    _sourceSystemId = source.getSystemId();
      }

      if (source instanceof SAXSource) {
    // Get all info from the input SAXSource object
    final SAXSource sax = (SAXSource)source;
    XMLReader reader = sax.getXMLReader();
    final InputSource input = sax.getInputSource();

    // Create a reader if not set by user
    if (reader == null) {
        reader = _tfactory.getXMLReader();
    }

    // Create a DTD monitor to trap all DTD/declarative events
    dtd = new DTDMonitor();
    dtd.handleDTD(reader);

    // Create a new internal DOM and set up its builder
    dom = new DOMImpl();
    final DOMBuilder builder = dom.getBuilder();
    try {
        reader.setProperty(LEXICAL_HANDLER_PROPERTY, builder);
    }
    catch (SAXException e) {
        // quitely ignored
    }
    reader.setContentHandler(builder);

    // Parse the input and build the internal DOM
    reader.parse(input);
    dom.setDocumentURI(_sourceSystemId);
      }
      else if (source instanceof DOMSource) {
    final DOMSource domsrc = (DOMSource) source;
    final org.w3c.dom.Node node = domsrc.getNode();
    final DOM2SAX dom2sax = new DOM2SAX(node);

    // Create a DTD monitor to trap all DTD/declarative events
    dtd = new DTDMonitor();
    dtd.handleDTD(dom2sax);

    // Create a new internal DOM and set up its builder to trap
    // all content/lexical events
    dom = new DOMImpl();
    final DOMBuilder builder = dom.getBuilder();
    dom2sax.setContentHandler(builder);

    // Parse the input and build the internal DOM
    dom2sax.parse();
    dom.setDocumentURI(_sourceSystemId);
      }
      else if (source instanceof StreamSource) {
    // Get all info from the input StreamSource object
    final StreamSource stream = (StreamSource)source;
    final InputStream streamInput = stream.getInputStream();
    final Reader streamReader = stream.getReader();
    final XMLReader reader = _tfactory.getXMLReader();

    // Create a DTD monitor to trap all DTD/declarative events
    dtd = new DTDMonitor();
    dtd.handleDTD(reader);

    // Create a new internal DOM and set up its builder to trap
    // all content/lexical events
    dom = new DOMImpl();
    final DOMBuilder builder = dom.getBuilder();
    try {
        reader.setProperty(LEXICAL_HANDLER_PROPERTY, builder);
    }
    catch (SAXException e) {
        // quitely ignored
    }
    reader.setContentHandler(builder);

    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());
    }

    // Parse the input and build the internal DOM
    reader.parse(input);
    dom.setDocumentURI(_sourceSystemId);
      }
      else if (source instanceof XSLTCSource) {
    final XSLTCSource xsltcsrc = (XSLTCSource)source;
    dtd = xsltcsrc.getDTD();
    dom = xsltcsrc.getDOM();
      }
      // DOM already set via a call to setDOM()
      else if (_dom != null) {
    dtd = _dtdMonitor;     // must be set via setDTDMonitor()
    dom = _dom; _dom = null;   // use only once, so reset to 'null'
      }
      else {
    return null;
      }

      // Set size of key/id indices
      if (!_isIdentity) {
    _translet.setIndexSize(dom.getSize());

    // If there are any elements with ID attributes, build an index
    dtd.buildIdIndex(dom, mask, _translet);

    // Pass unparsed entity URIs to the translet
    _translet.setDTDMonitor(dtd);
      }
      return dom;

  }
  catch (FileNotFoundException e) {
      if (_errorListener != nullpostErrorToListener(e.getMessage());
      throw new TransformerException(e);
  }
  catch (MalformedURLException e) {
      if (_errorListener != nullpostErrorToListener(e.getMessage());
      throw new TransformerException(e);
  }
  catch (UnknownHostException e) {
      if (_errorListener != nullpostErrorToListener(e.getMessage());
      throw new TransformerException(e);
  }
  catch (Exception e) {
      if (_errorListener != nullpostErrorToListener(e.getMessage());
      throw new TransformerException(e);
  }
    }
    private void transformIdentity(Source source, TransletOutputHandler 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 = _tfactory.getXMLReader();

      // Hook up reader and output handler
      try {
    reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
      }
      catch (SAXException e) {
    // Falls through
      }
      reader.setContentHandler(new SAX2TO(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);
  }
  else if (source instanceof SAXSource) {
      final SAXSource sax = (SAXSource) source;
      XMLReader reader = sax.getXMLReader();
      final InputSource input = sax.getInputSource();

      // Create a reader if not set by user
      if (reader == null) {
    reader = _tfactory.getXMLReader();
      }

      // Hook up reader and output handler
      try {
    reader.setProperty(LEXICAL_HANDLER_PROPERTY, handler);
      }
      catch (SAXException e) {
    // Falls through
      }
      reader.setContentHandler(new SAX2TO(handler));

      // Start pushing SAX events
      reader.parse(input);
  }
  else if (source instanceof DOMSource) {
      final DOMSource domsrc = (DOMSource) source;
      new DOM2TO(domsrc.getNode(), handler).parse();
  }
  else if (source instanceof XSLTCSource) {
      final DOMImpl dom = ((XSLTCSource) source).getDOM();
      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, TransletOutputHandler handler,
  String encoding) throws TransformerException
    {
  try {
      if (_isIdentity) {
    transformIdentity(source, handler);
      }
      else {
    _translet.transform(getDOM(source, 0), handler);
      }
  }
  catch (TransletException e) {
      if (_errorListener != nullpostErrorToListener(e.getMessage());
      throw new TransformerException(e);
  }
  catch (RuntimeException e) {
      if (_errorListener != nullpostErrorToListener(e.getMessage());
      throw new TransformerException(e);
  }
  catch (Exception e) {
      if (_errorListener != nullpostErrorToListener(e.getMessage());
      throw new TransformerException(e);
  }
    }

    /**
     * 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(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(TransletOutputHandler 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.omitHeader(
        value != null && value.toLowerCase().equals("yes"));
      }
      else if (name.equals(OutputKeys.INDENT)) {
    handler.setIndent(
        value != null && value.toLowerCase().equals("yes"));
      }
      else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
    if (value != null) {
        Hashtable table = new Hashtable();
        StringTokenizer e = new StringTokenizer(value);
        while (e.hasMoreTokens()) {
      final String token = e.nextToken();
      table.put(token, token);
        }
        handler.setCdataElements(table);
    }
      }
  }

  // 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();
  defaults.setProperty(OutputKeys.ENCODING, "UTF-8");
  defaults.setProperty(OutputKeys.METHOD, XML_STRING);
  defaults.setProperty(OutputKeys.INDENT, NO_STRING);
  defaults.setProperty(OutputKeys.MEDIA_TYPE, "text/xml");
  defaults.setProperty(OutputKeys.OMIT_XML_DECLARATION, NO_STRING);
  defaults.setProperty(OutputKeys.STANDALONE, NO_STRING);
  defaults.setProperty(OutputKeys.VERSION, "1.0");

  // 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")) {
    defaults.setProperty(OutputKeys.INDENT, "yes");
    defaults.setProperty(OutputKeys.VERSION, "4.0");
    defaults.setProperty(OutputKeys.MEDIA_TYPE, "text/html");
      }
      else if (method.equals("text")) {
    defaults.setProperty(OutputKeys.MEDIA_TYPE, "text/plain");
      }
  }

  return base;
    }

    /**
     * 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 (_isIdentity) {
      if (_parameters == null) {
    _parameters = new Hashtable();
      }
      _parameters.put(name, value);
  }
  else {
      _translet.addParameter(name, value, false);
  }
    }

    /**
     * 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().
     *
     * @returns 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 uri  An URI pointing to the document location
     * @param mask Contains a document ID (passed from the translet)
     * @param translet A reference to the translet requesting the document
     */
    public DOMImpl retrieveDocument(String uri, int mask, Translet translet) {
  try {
      return getDOM(_uriResolver.resolve(uri, _sourceSystemId), mask);
  }
  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 exception 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 exception 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 exception 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()));
        }
    }

}
TOP

Related Classes of org.apache.xalan.xsltc.trax.TransformerImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.