blob: 0373f1dd457ba4ff3cc7c6ad3a19db318592eb55 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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$
*/
package org.apache.xml.serializer;
import java.util.Vector;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.LexicalHandler;
/**
* This class is used to provide a base behavior to be inherited
* by other To...SAXHandler serializers.
*
* This class is not a public API.
*
* @xsl.usage internal
*/
public abstract class ToSAXHandler extends SerializerBase
{
public ToSAXHandler()
{
}
public ToSAXHandler(
ContentHandler hdlr,
LexicalHandler lex,
String encoding)
{
setContentHandler(hdlr);
setLexHandler(lex);
setEncoding(encoding);
}
public ToSAXHandler(ContentHandler handler, String encoding)
{
setContentHandler(handler);
setEncoding(encoding);
}
/**
* Underlying SAX handler. Taken from XSLTC
*/
protected ContentHandler m_saxHandler;
/**
* Underlying LexicalHandler. Taken from XSLTC
*/
protected LexicalHandler m_lexHandler;
/**
* A startPrefixMapping() call on a ToSAXHandler will pass that call
* on to the wrapped ContentHandler, but should we also mirror these calls
* with matching attributes, if so this field is true.
* For example if this field is true then a call such as
* startPrefixMapping("prefix1","uri1") will also cause the additional
* internally generated attribute xmlns:prefix1="uri1" to be effectively added
* to the attributes passed to the wrapped ContentHandler.
*/
private boolean m_shouldGenerateNSAttribute = true;
/** If this is true, then the content handler wrapped by this
* serializer implements the TransformState interface which
* will give the content handler access to the state of
* the transform. */
protected TransformStateSetter m_state = null;
/**
* Pass callback to the SAX Handler
*/
protected void startDocumentInternal() throws SAXException
{
if (m_needToCallStartDocument)
{
super.startDocumentInternal();
m_saxHandler.startDocument();
m_needToCallStartDocument = false;
}
}
/**
* Do nothing.
* @see org.xml.sax.ext.LexicalHandler#startDTD(String, String, String)
*/
public void startDTD(String arg0, String arg1, String arg2)
throws SAXException
{
// do nothing for now
}
/**
* Receive notification of character data.
*
* @param characters The string of characters to process.
*
* @throws org.xml.sax.SAXException
*
* @see ExtendedContentHandler#characters(String)
*/
public void characters(String characters) throws SAXException
{
final int len = characters.length();
if (len > m_charsBuff.length)
{
m_charsBuff = new char[len*2 + 1];
}
characters.getChars(0,len, m_charsBuff, 0);
characters(m_charsBuff, 0, len);
}
/**
* Receive notification of a comment.
*
* @see ExtendedLexicalHandler#comment(String)
*/
public void comment(String comment) throws SAXException
{
flushPending();
// Ignore if a lexical handler has not been set
if (m_lexHandler != null)
{
final int len = comment.length();
if (len > m_charsBuff.length)
{
m_charsBuff = new char[len*2 + 1];
}
comment.getChars(0,len, m_charsBuff, 0);
m_lexHandler.comment(m_charsBuff, 0, len);
// time to fire off comment event
if (m_tracer != null)
super.fireCommentEvent(m_charsBuff, 0, len);
}
}
/**
* Do nothing as this is an abstract class. All subclasses will need to
* define their behavior if it is different.
* @see org.xml.sax.ContentHandler#processingInstruction(String, String)
*/
public void processingInstruction(String target, String data)
throws SAXException
{
// Redefined in SAXXMLOutput
}
protected void closeStartTag() throws SAXException
{
}
protected void closeCDATA() throws SAXException
{
// Redefined in SAXXMLOutput
}
/**
* Receive notification of the beginning of an element, although this is a
* SAX method additional namespace or attribute information can occur before
* or after this call, that is associated with this element.
*
* @throws org.xml.sax.SAXException Any SAX exception, possibly
* wrapping another exception.
* @see org.xml.sax.ContentHandler#startElement
* @see org.xml.sax.ContentHandler#endElement
* @see org.xml.sax.AttributeList
*
* @throws org.xml.sax.SAXException
*
* @see org.xml.sax.ContentHandler#startElement(String,String,String,Attributes)
*/
public void startElement(
String arg0,
String arg1,
String arg2,
Attributes arg3)
throws SAXException
{
if (m_state != null) {
m_state.resetState(getTransformer());
}
// fire off the start element event
if (m_tracer != null)
super.fireStartElem(arg2);
}
/**
* Sets the LexicalHandler.
* @param _lexHandler The LexicalHandler to set
*/
public void setLexHandler(LexicalHandler _lexHandler)
{
this.m_lexHandler = _lexHandler;
}
/**
* Sets the SAX ContentHandler.
* @param _saxHandler The ContentHandler to set
*/
public void setContentHandler(ContentHandler _saxHandler)
{
this.m_saxHandler = _saxHandler;
if (m_lexHandler == null && _saxHandler instanceof LexicalHandler)
{
// we are not overwriting an existing LexicalHandler, and _saxHandler
// is also implements LexicalHandler, so lets use it
m_lexHandler = (LexicalHandler) _saxHandler;
}
}
/**
* Does nothing. The setting of CDATA section elements has an impact on
* stream serializers.
* @see SerializationHandler#setCdataSectionElements(java.util.Vector)
*/
public void setCdataSectionElements(Vector URI_and_localNames)
{
// do nothing
}
/** Set whether or not namespace declarations (e.g.
* xmlns:foo) should appear as attributes of
* elements
* @param doOutputNSAttr whether or not namespace declarations
* should appear as attributes
*/
public void setShouldOutputNSAttr(boolean doOutputNSAttr)
{
m_shouldGenerateNSAttribute = doOutputNSAttr;
}
/**
* Returns true if namespace declarations from calls such as
* startPrefixMapping("prefix1","uri1") should
* also be mirrored with self generated additional attributes of elements
* that declare the namespace, for example the attribute xmlns:prefix1="uri1"
*/
boolean getShouldOutputNSAttr()
{
return m_shouldGenerateNSAttribute;
}
/**
* This method flushes any pending events, which can be startDocument()
* closing the opening tag of an element, or closing an open CDATA section.
*/
public void flushPending() throws SAXException
{
if (m_needToCallStartDocument)
{
startDocumentInternal();
m_needToCallStartDocument = false;
}
if (m_elemContext.m_startTagOpen)
{
closeStartTag();
m_elemContext.m_startTagOpen = false;
}
if (m_cdataTagOpen)
{
closeCDATA();
m_cdataTagOpen = false;
}
}
/**
* Pass in a reference to a TransformState object, which
* can be used during SAX ContentHandler events to obtain
* information about he state of the transformation. This
* method will be called before each startDocument event.
*
* @param ts A reference to a TransformState object
*/
public void setTransformState(TransformStateSetter ts) {
this.m_state = ts;
}
/**
* Receives notification that an element starts, but attributes are not
* fully known yet.
*
* @param uri the URI of the namespace of the element (optional)
* @param localName the element name, but without prefix (optional)
* @param qName the element name, with prefix, if any (required)
*
* @see ExtendedContentHandler#startElement(String, String, String)
*/
public void startElement(String uri, String localName, String qName)
throws SAXException {
if (m_state != null) {
m_state.resetState(getTransformer());
}
// fire off the start element event
if (m_tracer != null)
super.fireStartElem(qName);
}
/**
* An element starts, but attributes are not fully known yet.
*
* @param qName the element name, with prefix (if any).
* @see ExtendedContentHandler#startElement(String)
*/
public void startElement(String qName) throws SAXException {
if (m_state != null) {
m_state.resetState(getTransformer());
}
// fire off the start element event
if (m_tracer != null)
super.fireStartElem(qName);
}
/**
* This method gets the node's value as a String and uses that String as if
* it were an input character notification.
* @param node the Node to serialize
* @throws org.xml.sax.SAXException
*/
public void characters(org.w3c.dom.Node node)
throws org.xml.sax.SAXException
{
// remember the current node
if (m_state != null)
{
m_state.setCurrentNode(node);
}
// Get the node's value as a String and use that String as if
// it were an input character notification.
String data = node.getNodeValue();
if (data != null) {
this.characters(data);
}
}
/**
* @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
*/
public void fatalError(SAXParseException exc) throws SAXException {
super.fatalError(exc);
m_needToCallStartDocument = false;
if (m_saxHandler instanceof ErrorHandler) {
((ErrorHandler)m_saxHandler).fatalError(exc);
}
}
/**
* @see org.xml.sax.ErrorHandler#error(SAXParseException)
*/
public void error(SAXParseException exc) throws SAXException {
super.error(exc);
if (m_saxHandler instanceof ErrorHandler)
((ErrorHandler)m_saxHandler).error(exc);
}
/**
* @see org.xml.sax.ErrorHandler#warning(SAXParseException)
*/
public void warning(SAXParseException exc) throws SAXException {
super.warning(exc);
if (m_saxHandler instanceof ErrorHandler)
((ErrorHandler)m_saxHandler).warning(exc);
}
/**
* Try's to reset the super class and reset this class for
* re-use, so that you don't need to create a new serializer
* (mostly for performance reasons).
*
* @return true if the class was successfuly reset.
* @see Serializer#reset()
*/
public boolean reset()
{
boolean wasReset = false;
if (super.reset())
{
resetToSAXHandler();
wasReset = true;
}
return wasReset;
}
/**
* Reset all of the fields owned by ToSAXHandler class
*
*/
private void resetToSAXHandler()
{
this.m_lexHandler = null;
this.m_saxHandler = null;
this.m_state = null;
this.m_shouldGenerateNSAttribute = false;
}
/**
* Add a unique attribute
*/
public void addUniqueAttribute(String qName, String value, int flags)
throws SAXException
{
addAttribute(qName, value);
}
}