| /* |
| * @(#)$Id$ |
| * |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 2001 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 Jacek Ambroziak |
| * @author Santiago Pericas-Geertsen |
| * @author Morten Jorgensen |
| * @author G. Todd Miller |
| */ |
| |
| package org.apache.xalan.xsltc.runtime; |
| |
| import java.util.Vector; |
| import java.util.Enumeration; |
| import java.text.DecimalFormat; |
| import java.text.DecimalFormatSymbols; |
| import org.apache.xalan.xsltc.*; |
| |
| import org.apache.xalan.xsltc.util.IntegerArray; |
| import org.apache.xalan.xsltc.dom.DOMAdapter; |
| import org.apache.xalan.xsltc.dom.DOMImpl; |
| import org.apache.xalan.xsltc.dom.StripWhitespaceFilter; |
| import org.apache.xalan.xsltc.dom.KeyIndex; |
| |
| // GTM added all these |
| import org.apache.xalan.xsltc.runtime.DefaultSAXOutputHandler; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.stream.StreamResult; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.URIResolver; |
| import javax.xml.transform.ErrorListener; |
| import java.lang.IllegalArgumentException; |
| import java.util.Properties; |
| import java.lang.IllegalArgumentException; |
| import javax.xml.parsers.SAXParserFactory; |
| import javax.xml.parsers.SAXParser; |
| import org.xml.sax.XMLReader; |
| import org.apache.xalan.xsltc.dom.DTDMonitor; |
| import java.io.File; |
| import java.io.Writer; |
| import java.io.OutputStream; |
| import java.io.FileOutputStream; |
| import java.io.FileNotFoundException; |
| import java.net.MalformedURLException; |
| import java.net.UnknownHostException; |
| // END. |
| |
| public abstract class AbstractTranslet extends Transformer implements Translet { |
| |
| protected String _encoding = "utf-8"; |
| |
| //!!! to be added only as needed |
| protected StringValueHandler stringValueHandler = new StringValueHandler(); |
| |
| //!! different handshake needed |
| protected String[] namesArray; |
| protected String[] namespaceArray; |
| |
| //!!! Temporary approach. To be added to translet only when needed. !!! |
| public Hashtable _formatSymbols = new Hashtable(); |
| public Hashtable _unparsedEntities = null; |
| |
| // Container for all indexes for xsl:key elements |
| private Hashtable _keyIndexes = new Hashtable(); |
| private KeyIndex _emptyKeyIndex = new KeyIndex(1); |
| private int _indexSize = 0; |
| |
| private MessageHandler _msgHandler = null; |
| |
| private DOMCache _domCache = null; |
| |
| private final static String EMPTYSTRING = ""; |
| |
| |
| public final DOMAdapter makeDOMAdapter(DOM dom) |
| throws TransletException { |
| if (dom instanceof DOMImpl) { |
| return new DOMAdapter((DOMImpl)dom, namesArray, namespaceArray); |
| } |
| else { |
| throw new TransletException("wrong type of source DOM"); |
| } |
| } |
| |
| public final void setMessageHandler(MessageHandler handler) { |
| _msgHandler = handler; |
| } |
| |
| public final void displayMessage(String msg) { |
| if (_msgHandler == null) { |
| System.err.println(msg); |
| } |
| else { |
| _msgHandler.displayMessage(msg); |
| } |
| } |
| |
| /** |
| * Variable's stack: <tt>vbase</tt> and <tt>vframe</tt> are used |
| * to denote the current variable frame. |
| */ |
| protected int vbase = 0, vframe = 0; |
| protected Vector varsStack = new Vector(); |
| |
| /** |
| * Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used |
| * to denote the current parameter frame. |
| */ |
| protected int pbase = 0, pframe = 0; |
| protected Vector paramsStack = new Vector(); |
| |
| /** |
| * Push a new parameter frame. |
| */ |
| public final void pushParamFrame() { |
| paramsStack.insertElementAt(new Integer(pbase), pframe); |
| pbase = ++pframe; |
| } |
| |
| /** |
| * Pop the topmost parameter frame. |
| */ |
| public final void popParamFrame() { |
| if (pbase > 0) { |
| pframe = pbase - 1; |
| pbase = ((Integer) paramsStack.elementAt(pframe)).intValue(); |
| } |
| } |
| |
| /** |
| * Add a new parameter if not already in the current frame. |
| * Returns the old value if already defined and the new value |
| * if added. |
| */ |
| public final Object addParameter(String name, Object value) { |
| for (int i = pframe - 1; i >= pbase; i--) { |
| final Parameter param = (Parameter) paramsStack.elementAt(i); |
| if (param.name.equals(name)) { |
| return param.value; |
| } |
| } |
| paramsStack.insertElementAt(new Parameter(name, value), pframe++); |
| return value; |
| } |
| |
| /** |
| * Get the value of a parameter from the current frame or |
| * <tt>null</tt> if undefined. |
| */ |
| public final Object getParameter(String name) { |
| for (int i = pframe - 1; i >= pbase; i--) { |
| final Parameter param = (Parameter)paramsStack.elementAt(i); |
| if (param.name.equals(name)) { |
| return param.value; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Push a new variable frame. |
| */ |
| public final void pushVarFrame(int frameSize) { |
| varsStack.insertElementAt(new Integer(vbase), vframe); |
| vbase = ++vframe; |
| vframe += frameSize; |
| } |
| |
| /** |
| * Pop the topmost variable frame. |
| */ |
| public final void popVarFrame() { |
| if (vbase > 0) { |
| vframe = vbase - 1; |
| vbase = ((Integer)varsStack.elementAt(vframe)).intValue(); |
| } |
| } |
| |
| /** |
| * Get the value of a variable given its index. |
| */ |
| public final Object getVariable(int vindex) { |
| return varsStack.elementAt(vbase + vindex); |
| } |
| |
| /** |
| * Set the value of a variable in the current frame. |
| */ |
| public final void addVariable(int vindex, Object value) { |
| varsStack.insertElementAt(value, vbase + vindex); |
| } |
| |
| /** |
| * Adds a DecimalFormat object to the _formatSymbols hashtable. |
| * The entry is created with the input DecimalFormatSymbols. |
| */ |
| public void addDecimalFormat(String name, DecimalFormatSymbols symbols) { |
| // Remove any existing entries with the same name. |
| if (name == null) name = EMPTYSTRING; |
| _formatSymbols.remove(name); |
| // Construct a DecimalFormat object containing the symbols we got |
| final DecimalFormat df = new DecimalFormat(); |
| if (symbols != null) { |
| df.setDecimalFormatSymbols(symbols); |
| } |
| _formatSymbols.put(name, df); |
| } |
| |
| /** |
| * Retrieves a named DecimalFormat object from _formatSymbols hashtable. |
| */ |
| public final DecimalFormat getDecimalFormat(String name) { |
| if (name == null) name = EMPTYSTRING; |
| final DecimalFormat df = (DecimalFormat)_formatSymbols.get(name); |
| if (df == null) { |
| // This should really result in an error |
| return((DecimalFormat)_formatSymbols.get(EMPTYSTRING)); |
| } |
| else { |
| return df; |
| } |
| } |
| |
| public final void addUnparsedEntity(String name, String uri) { |
| if (_unparsedEntities == null) |
| _unparsedEntities = new Hashtable(); |
| if (_unparsedEntities.containsKey(name) == false) |
| _unparsedEntities.put(name, uri); |
| } |
| |
| public final String getUnparsedEntity(String name) { |
| final String uri = (String)_unparsedEntities.get(name); |
| return uri == null ? EMPTYSTRING : uri; |
| } |
| |
| public final void setDTDMonitor(DTDMonitor monitor) { |
| setUnparsedEntityURIs(monitor.getUnparsedEntityURIs()); |
| } |
| |
| public final void setUnparsedEntityURIs(Hashtable table) { |
| if (_unparsedEntities == null) |
| _unparsedEntities = table; |
| else { |
| Enumeration keys = table.keys(); |
| while (keys.hasMoreElements()) { |
| String name = (String)keys.nextElement(); |
| _unparsedEntities.put(name,table.get(name)); |
| } |
| } |
| } |
| |
| public abstract void transform(DOM document, NodeIterator iterator, |
| TransletOutputHandler handler) |
| throws TransletException; |
| |
| protected TransletOutputHandler[] handlers; |
| |
| protected final TransletOutputHandler getOutputHandler(double port) { |
| try { |
| return handlers[(int) port]; |
| } |
| catch (IndexOutOfBoundsException e) { |
| BasisLibrary.runTimeError("Output port " + (int)port |
| + " out of range."); |
| return null; |
| } |
| } |
| |
| public final void transform(DOM document, TransletOutputHandler handler) |
| throws TransletException { |
| handlers = new TransletOutputHandler[] { handler }; |
| transform(document, document.getIterator(), handler); |
| } |
| |
| public final void transform(DOM document, |
| TransletOutputHandler[] handlers) |
| throws TransletException { |
| this.handlers = handlers; |
| transform(document, document.getIterator(), handlers[0]); |
| } |
| |
| private char[] _characterArray = new char[32]; |
| |
| public final void characters(final String string, |
| TransletOutputHandler handler) |
| throws TransletException { |
| if (string == null) return; |
| final int length = string.length(); |
| if (length > _characterArray.length) { |
| _characterArray = new char[length]; |
| } |
| string.getChars(0, length, _characterArray, 0); |
| handler.characters(_characterArray, 0, length); |
| } |
| |
| /** |
| * Pass the output encoding setting to the output handler. |
| */ |
| public String getOutputEncoding() { |
| return _encoding; |
| } |
| |
| public void setIndexSize(int size) { |
| if (size > _indexSize) |
| _indexSize = size; |
| } |
| |
| public void buildKeyIndex(String name, int node, String value) { |
| KeyIndex index = (KeyIndex)_keyIndexes.get(name); |
| if (index == null) { |
| _keyIndexes.put(name, index = new KeyIndex(_indexSize)); |
| } |
| index.add(value, node); |
| } |
| |
| public KeyIndex createKeyIndex() { |
| return(new KeyIndex(_indexSize)); |
| } |
| |
| public KeyIndex getKeyIndex(String name) { |
| final KeyIndex index = (KeyIndex)_keyIndexes.get(name); |
| return index != null ? index : _emptyKeyIndex; |
| } |
| |
| public void buildKeys(DOM document, NodeIterator iterator, |
| TransletOutputHandler handler, |
| int root) throws TransletException { |
| } |
| |
| public void setDOMCache(DOMCache cache) { |
| _domCache = cache; |
| } |
| |
| public DOMCache getDOMCache() { |
| return(_domCache); |
| } |
| |
| private String _transletName; |
| |
| public void setTransletName(String name) { |
| _transletName = name; |
| } |
| |
| public String getTransletName() { |
| return _transletName; |
| } |
| |
| /********************************************************* |
| * Transformer methods |
| *********************************************************/ |
| |
| public void transform(Source xmlsrc, Result outputTarget) |
| throws TransformerException |
| { |
| /******************** |
| doTransform( xmlsrc.getSystemId(), |
| ((StreamResult)outputTarget).getOutputStream() ); |
| *******************************/ |
| |
| // try to get the encoding from Translet |
| final Translet translet = (Translet)this; |
| String encoding = translet.getOutputEncoding(); |
| if (encoding == null) encoding = "UTF-8"; |
| |
| // create a DefaultSAXOutputHandler |
| DefaultSAXOutputHandler saxHandler = null; |
| StreamResult target = (StreamResult)outputTarget; |
| java.io.Writer writer = target.getWriter(); |
| java.io.OutputStream os = target.getOutputStream(); |
| String systemid = target.getSystemId(); |
| if (writer != null) { |
| // no constructor that takes encoding yet... |
| try { |
| saxHandler = new DefaultSAXOutputHandler(writer); |
| } catch (java.io.IOException e) { |
| throw new TransformerException( |
| "IOException creating DefaultSAXOutputHandler"); |
| } |
| } else if (os != null) { |
| try { |
| saxHandler = new DefaultSAXOutputHandler(os, encoding); |
| } catch (java.io.IOException e) { |
| throw new TransformerException( |
| "IOException creating DefaultSAXOutputHandler"); |
| } |
| } else if (systemid != null) { |
| String filePrefix = new String("file:///"); |
| if (systemid.startsWith(filePrefix)) { |
| systemid = systemid.substring(filePrefix.length()); |
| } |
| try { |
| saxHandler = new DefaultSAXOutputHandler( |
| ((OutputStream)new FileOutputStream(systemid)), |
| encoding); |
| } catch (java.io.FileNotFoundException e) { |
| throw new TransformerException( |
| "Transform output target could not be opened."); |
| } catch (java.io.IOException e) { |
| throw new TransformerException( |
| "Transform output target could not be opened."); |
| } |
| } |
| |
| // finally do the transformation... |
| doTransform(xmlsrc.getSystemId(), saxHandler, encoding); |
| } |
| |
| private void doTransform(String xmlDocName, |
| DefaultSAXOutputHandler saxHandler, String encoding) |
| { |
| try { |
| final Translet translet = (Translet)this; // GTM added |
| |
| // Create a SAX parser and get the XMLReader object it uses |
| final SAXParserFactory factory = SAXParserFactory.newInstance(); |
| final SAXParser parser = factory.newSAXParser(); |
| final XMLReader reader = parser.getXMLReader(); |
| |
| // Set the DOM's DOM builder as the XMLReader's SAX2 content handler |
| final DOMImpl dom = new DOMImpl(); |
| reader.setContentHandler(dom.getBuilder()); |
| // Create a DTD monitor and pass it to the XMLReader object |
| final DTDMonitor dtdMonitor = new DTDMonitor(); |
| dtdMonitor.handleDTD(reader); |
| |
| dom.setDocumentURI(xmlDocName); |
| /**************** |
| if (_uri) |
| reader.parse(xmlDocName); |
| else |
| *******************/ |
| reader.parse("file:"+(new File(xmlDocName).getAbsolutePath())); |
| |
| // Set size of key/id indices |
| setIndexSize(dom.getSize()); |
| // If there are any elements with ID attributes, build an index |
| dtdMonitor.buildIdIndex(dom, 0, this); |
| |
| setDTDMonitor(dtdMonitor); |
| |
| // Transform the document |
| TextOutput textOutput = new TextOutput(saxHandler, encoding); |
| translet.transform(dom, textOutput); |
| textOutput.flush(); |
| } |
| catch (TransletException e) { |
| if (_errorListener != null) { |
| postErrorToListener(e.getMessage()); |
| } else { |
| System.err.println("\nTranslet Error: " + e.getMessage()); |
| } |
| System.exit(1); |
| } |
| catch (RuntimeException e) { |
| if (_errorListener != null) { |
| postErrorToListener("Runtime Error: " + e.getMessage()); |
| } else { |
| System.err.println("\nRuntime Error: " + e.getMessage()); |
| } |
| System.exit(1); |
| } |
| catch (FileNotFoundException e) { |
| if (_errorListener != null) { |
| postErrorToListener("File Not Found: " + e.getMessage()); |
| } else { |
| //System.err.println("Error:File or URI '"+_fileName+"' |
| // not found."); |
| } |
| System.exit(1); |
| } |
| catch (MalformedURLException e) { |
| if (_errorListener != null) { |
| postErrorToListener("Malformed URL: " + e.getMessage()); |
| } else { |
| //System.err.println("Error: Invalid URI '"+_fileName+"'."); |
| } |
| System.exit(1); |
| } |
| catch (UnknownHostException e) { |
| if (_errorListener != null) { |
| postErrorToListener("Can't resolve URI: " + e.getMessage()); |
| } else { |
| //System.err.println("Error: Can't resolve URI specification '"+ |
| //_fileName+"'."); |
| } |
| System.exit(1); |
| } |
| catch (Exception e) { |
| if (_errorListener != null) { |
| postErrorToListener("Internal error: " + e.getMessage()); |
| } else { |
| System.err.println("Error: internal error."); |
| e.printStackTrace(); |
| } |
| System.exit(1); |
| } |
| } |
| |
| public void clearParameters() { |
| paramsStack.clear(); |
| } |
| |
| // TrAX support methods, get/setErrorListener |
| private ErrorListener _errorListener = null; |
| |
| public ErrorListener getErrorListener() { |
| return _errorListener; |
| } |
| |
| public void setErrorListener(ErrorListener listener) throws |
| IllegalArgumentException |
| { |
| if (listener == null) { |
| throw new IllegalArgumentException( |
| "Error: setErrorListener() call where ErrorListener is null"); |
| } |
| _errorListener = listener; |
| } |
| |
| /** |
| * inform TrAX error listener of this error |
| */ |
| private void postErrorToListener(String msg) { |
| try { |
| _errorListener.error(new TransformerException( |
| "Translet Error: " + msg)); |
| } catch (TransformerException e) { |
| // TBD |
| } |
| } |
| |
| /** |
| * inform TrAX error listener of this warning |
| */ |
| private void postWarningToListener(String msg) { |
| try { |
| _errorListener.warning(new TransformerException( |
| "Translet Warning: " + msg)); |
| } catch (TransformerException e) { |
| // TBD |
| } |
| } |
| |
| |
| public Properties getOutputProperties() throws IllegalArgumentException { |
| /*TBD*/ |
| throw new IllegalArgumentException( |
| "AbstractTranslet:getOutputProperties() " + |
| "not implemented yet."); |
| //return null; |
| } |
| |
| public String getOutputProperty(String name) throws |
| IllegalArgumentException |
| { |
| /*TBD*/ |
| throw new IllegalArgumentException( |
| "AbstractTranslet:getOutputProperty(String) " + |
| "not implemented yet."); |
| //return ""; |
| } |
| |
| public void setOutputProperties(Properties props) throws |
| IllegalArgumentException |
| { |
| /*TBD */ |
| throw new IllegalArgumentException( |
| "AbstractTranslet:setOutputProperty(Properties) " + |
| "not implemented yet."); |
| } |
| |
| public void setOutputProperty(String name, String value) throws |
| IllegalArgumentException |
| { |
| /*TBD*/ |
| throw new IllegalArgumentException( |
| "AbstractTranslet:setOutputProperty(String,String) " + |
| "not implemented yet."); |
| } |
| |
| public URIResolver getURIResolver() { /*TBD*/ return null; } |
| |
| public void setParameter(String name, Object value) { |
| addParameter(name, value); |
| } |
| |
| public void setURIResolver(URIResolver resolver) { |
| /*TBD*/ |
| } |
| |
| } |