blob: 15520c5beb0c1dc89b028b19e7276083eec1b6d8 [file] [log] [blame]
/*
* @(#)$Id$
*
* 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 Santiago Pericas-Geertsen
* @author G. Todd Miller
*
*/
package org.apache.xalan.xsltc.runtime.output;
import java.util.Stack;
import org.apache.xalan.xsltc.*;
import org.apache.xalan.xsltc.runtime.*;
import org.apache.xalan.xsltc.runtime.Hashtable;
import org.apache.xalan.xsltc.TransletException;
import org.apache.xalan.xsltc.TransletOutputHandler;
import org.apache.xalan.xsltc.runtime.Hashtable;
public abstract class OutputBase implements TransletOutputHandler, Constants {
/**
* Document system identifier
*/
protected String _doctypeSystem = null;
/**
* Document public identifier
*/
protected String _doctypePublic = null;
/**
* Holds the current tree depth.
*/
protected int _depth = 0;
/**
* Each entry (prefix) in this hashtable points to a Stack of URIs
*/
protected Hashtable _namespaces;
/**
* The top of this stack contains an id of the element that last declared
* a namespace. Used to ensure prefix/uri map scopes are closed correctly
*/
protected Stack _nodeStack;
/**
* The top of this stack is the prefix that was last mapped to an URI
*/
protected Stack _prefixStack;
/**
* Contains all elements that should be output as CDATA sections.
*/
protected Hashtable _cdata = null;
/**
* The top of this stack contains the element id of the last element whose
* contents should be output as CDATA sections.
*/
protected Stack _cdataStack;
/**
* Set to true when a CDATA section is being output.
*/
protected boolean _cdataTagOpen = false;
/**
* Set to true when a start tag is being output.
*/
protected boolean _startTagOpen = false;
/**
* Set to false after processing first element.
*/
protected boolean _firstElement = true;
/**
* Initialize global variables
*/
protected void initCDATA() {
// CDATA stack
_cdataStack = new Stack();
_cdataStack.push(new Integer(-1)); // push dummy value
}
protected void initNamespaces() {
// Namespaces
_namespaces = new Hashtable();
_nodeStack = new Stack();
_prefixStack = new Stack();
// Define the default namespace (initially maps to "" uri)
Stack stack;
_namespaces.put(EMPTYSTRING, stack = new Stack());
stack.push(EMPTYSTRING);
_prefixStack.push(EMPTYSTRING);
_namespaces.put(XML_PREFIX, stack = new Stack());
stack.push("http://www.w3.org/XML/1998/namespace");
_prefixStack.push(XML_PREFIX);
_nodeStack.push(new Integer(-1));
_depth = 0;
}
/**
* Set the output document system/public identifiers
*/
public void setDoctype(String system, String pub) {
_doctypeSystem = system;
_doctypePublic = pub;
}
public void setCdataElements(Hashtable elements) {
_cdata = elements;
}
/**
* TODO: This method is a HACK! Since XSLTC does not have access to the
* XML file, it sometimes generates a NS prefix of the form "ns?" for
* an attribute. If at runtime, when the qname of the attribute is
* known, another prefix is specified for the attribute, then we can get
* a qname of the form "ns?:otherprefix:name". This function patches the
* qname by simply ignoring "otherprefix". In addition, this method
* ignores prefixes bound to the empty string "".
*/
protected String patchName(String qname) throws TransletException {
final int lastColon = qname.lastIndexOf(':');
if (lastColon > 0) {
final int firstColon = qname.indexOf(':');
final String prefix = qname.substring(0, firstColon);
final String localName = qname.substring(lastColon + 1);
// If uri is "" then ignore prefix
final String uri = lookupNamespace(prefix);
if (uri != null && uri.length() == 0) {
return localName;
}
else if (firstColon != lastColon) {
return prefix + ':' + localName;
}
}
return qname;
}
/**
* Declare a prefix to point to a namespace URI
*/
protected boolean pushNamespace(String prefix, String uri) {
// Prefixes "xml" and "xmlns" cannot be redefined
if (prefix.startsWith(XML_PREFIX)) {
return false;
}
Stack stack;
// Get the stack that contains URIs for the specified prefix
if ((stack = (Stack)_namespaces.get(prefix)) == null) {
_namespaces.put(prefix, stack = new Stack());
}
if (!stack.empty() && uri.equals(stack.peek())) {
return false;
}
stack.push(uri);
_prefixStack.push(prefix);
_nodeStack.push(new Integer(_depth));
return true;
}
/**
* Undeclare the namespace that is currently pointed to by a given prefix
*/
protected boolean popNamespace(String prefix) {
// Prefixes "xml" and "xmlns" cannot be redefined
if (prefix.startsWith(XML_PREFIX)) {
return false;
}
Stack stack;
if ((stack = (Stack)_namespaces.get(prefix)) != null) {
stack.pop();
return true;
}
return false;
}
/**
* Pop all namespace definitions that were delcared by the current element
*/
protected void popNamespaces() {
while (true) {
if (_nodeStack.isEmpty()) return;
Integer i = (Integer)(_nodeStack.peek());
if (i.intValue() != _depth) return;
_nodeStack.pop();
popNamespace((String)_prefixStack.pop());
}
}
/**
* Use a namespace prefix to lookup a namespace URI
*/
protected String lookupNamespace(String prefix) {
final Stack stack = (Stack)_namespaces.get(prefix);
return stack != null && !stack.isEmpty() ? (String)stack.peek() : null;
}
/**
* Returns the local name of a qualified name. If the name has
* no prefix, then it works as the identity (SAX2).
*/
protected static String getLocalName(String qname) {
final int col = qname.lastIndexOf(':');
return (col > 0) ? qname.substring(col + 1) : qname;
}
/**
* Returns the URI of an element or attribute. Note that default namespaces
* do not apply directly to attributes.
*/
protected String getNamespaceURI(String qname, boolean isElement)
throws TransletException
{
String uri = EMPTYSTRING;
int col = qname.lastIndexOf(':');
final String prefix = (col > 0) ? qname.substring(0, col) : EMPTYSTRING;
if (prefix != EMPTYSTRING || isElement) {
uri = lookupNamespace(prefix);
if (uri == null && !prefix.equals(XMLNS_PREFIX)) {
BasisLibrary.runTimeError(BasisLibrary.NAMESPACE_PREFIX_ERR,
qname.substring(0, col));
}
}
return uri;
}
public void startCDATA() throws TransletException { }
public void endCDATA() throws TransletException { }
public void namespace(String prefix, String uri) throws TransletException { }
public void setType(int type) { }
public void setIndent(boolean indent) { }
public void omitHeader(boolean value) { }
public boolean setEscaping(boolean escape) throws TransletException { return true; }
public void setMediaType(String mediaType) { }
public void setStandalone(String standalone) { }
public void setVersion(String version) { }
public void close() { }
}