diff -r 1d7e6da6adc8 -r c348e06f0e82 jaxp/src/com/sun/org/apache/xml/internal/serializer/SerializerBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/src/com/sun/org/apache/xml/internal/serializer/SerializerBase.java Thu Apr 12 08:38:26 2012 -0700 @@ -0,0 +1,1387 @@ +/* + * 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: SerializerBase.java,v 1.5 2006/04/14 12:09:19 sunithareddy Exp $ + */ +package com.sun.org.apache.xml.internal.serializer; + +import java.io.IOException; +import java.util.Vector; + +import javax.xml.transform.SourceLocator; +import javax.xml.transform.Transformer; + +import com.sun.org.apache.xml.internal.serializer.utils.MsgKey; +import com.sun.org.apache.xml.internal.serializer.utils.Utils; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.ext.Locator2; + + +/** + * This class acts as a base class for the XML "serializers" + * and the stream serializers. + * It contains a number of common fields and methods. + * + * @xsl.usage internal + */ +public abstract class SerializerBase + implements SerializationHandler, SerializerConstants +{ + + + /** + * To fire off the end element trace event + * @param name Name of element + */ + protected void fireEndElem(String name) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDELEMENT,name, (Attributes)null); + } + } + + /** + * Report the characters trace event + * @param chars content of characters + * @param start starting index of characters to output + * @param length number of characters to output + */ + protected void fireCharEvent(char[] chars, int start, int length) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CHARACTERS, chars, start,length); + } + } + + /** + * true if we still need to call startDocumentInternal() + */ + protected boolean m_needToCallStartDocument = true; + + /** True if a trailing "]]>" still needs to be written to be + * written out. Used to merge adjacent CDATA sections + */ + protected boolean m_cdataTagOpen = false; + + /** + * All the attributes of the current element, collected from + * startPrefixMapping() calls, or addAddtribute() calls, or + * from the SAX attributes in a startElement() call. + */ + protected AttributesImplSerializer m_attributes = new AttributesImplSerializer(); + + /** + * Tells if we're in an EntityRef event. + */ + protected boolean m_inEntityRef = false; + + /** This flag is set while receiving events from the external DTD */ + protected boolean m_inExternalDTD = false; + + /** + * The System ID for the doc type. + */ + private String m_doctypeSystem; + + /** + * The public ID for the doc type. + */ + private String m_doctypePublic; + + /** + * Flag to tell that we need to add the doctype decl, which we can't do + * until the first element is encountered. + */ + boolean m_needToOutputDocTypeDecl = true; + + /** + * The character encoding. Must match the encoding used for the + * printWriter. + */ + private String m_encoding = null; + + /** + * Tells if we should write the XML declaration. + */ + private boolean m_shouldNotWriteXMLHeader = false; + + /** + * The standalone value for the doctype. + */ + private String m_standalone; + + /** + * True if standalone was specified. + */ + protected boolean m_standaloneWasSpecified = false; + + /** + * Flag to tell if indenting (pretty-printing) is on. + */ + protected boolean m_doIndent = false; + /** + * Amount to indent. + */ + protected int m_indentAmount = 0; + + /** + * Tells the XML version, for writing out to the XML decl. + */ + private String m_version = null; + + /** + * The mediatype. Not used right now. + */ + private String m_mediatype; + + /** + * The transformer that was around when this output handler was created (if + * any). + */ + private Transformer m_transformer; + + /** + * Pairs of local names and corresponding URIs of CDATA sections. This list + * comes from the cdata-section-elements attribute. Every second one is a + * local name, and every other second one is the URI for the local name. + */ + protected Vector m_cdataSectionElements = null; + + /** + * Namespace support, that keeps track of currently defined + * prefix/uri mappings. As processed elements come and go, so do + * the associated mappings for that element. + */ + protected NamespaceMappings m_prefixMap; + + /** + * Handle for firing generate events. This interface may be implemented + * by the referenced transformer object. + */ + protected SerializerTrace m_tracer; + + protected SourceLocator m_sourceLocator; + + + /** + * The writer to send output to. This field is only used in the ToStream + * serializers, but exists here just so that the fireStartDoc() and + * other fire... methods can flush this writer when tracing. + */ + protected java.io.Writer m_writer = null; + + /** + * A reference to "stack frame" corresponding to + * the current element. Such a frame is pushed at a startElement() + * and popped at an endElement(). This frame contains information about + * the element, such as its namespace URI. + */ + protected ElemContext m_elemContext = new ElemContext(); + + /** + * A utility buffer for converting Strings passed to + * character() methods to character arrays. + * Reusing this buffer means not creating a new character array + * everytime and it runs faster. + */ + protected char[] m_charsBuff = new char[60]; + + /** + * A utility buffer for converting Strings passed to + * attribute methods to character arrays. + * Reusing this buffer means not creating a new character array + * everytime and it runs faster. + */ + protected char[] m_attrBuff = new char[30]; + + private Locator m_locator = null; + + protected boolean m_needToCallSetDocumentInfo = true; + + /** + * Receive notification of a comment. + * + * @see ExtendedLexicalHandler#comment(String) + */ + public void comment(String data) throws SAXException + { + final int length = data.length(); + if (length > m_charsBuff.length) + { + m_charsBuff = new char[length * 2 + 1]; + } + data.getChars(0, length, m_charsBuff, 0); + comment(m_charsBuff, 0, length); + } + + /** + * If at runtime, when the qname of the attribute is + * known, another prefix is specified for the attribute, then we can + * patch or hack the name with this method. For + * a qname of the form "ns?:otherprefix:name", this function patches the + * qname by simply ignoring "otherprefix". + * TODO: This method is a HACK! We do not have access to the + * XML file, it sometimes generates a NS prefix of the form "ns?" for + * an attribute. + */ + protected String patchName(String qname) + { + + + 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 = m_prefixMap.lookupNamespace(prefix); + if (uri != null && uri.length() == 0) { + return localName; + } + else if (firstColon != lastColon) { + return prefix + ':' + localName; + } + } + return qname; + } + + /** + * Returns the local name of a qualified name. If the name has no prefix, + * then it works as the identity (SAX2). + * @param qname the qualified name + * @return the name, but excluding any prefix and colon. + */ + protected static String getLocalName(String qname) + { + final int col = qname.lastIndexOf(':'); + return (col > 0) ? qname.substring(col + 1) : qname; + } + + /** + * Receive an object for locating the origin of SAX document events. + * + * @param locator An object that can return the location of any SAX document + * event. + * + * Receive an object for locating the origin of SAX document events. + * + *

SAX parsers are strongly encouraged (though not absolutely + * required) to supply a locator: if it does so, it must supply + * the locator to the application by invoking this method before + * invoking any of the other methods in the DocumentHandler + * interface.

+ * + *

The locator allows the application to determine the end + * position of any document-related event, even if the parser is + * not reporting an error. Typically, the application will + * use this information for reporting its own errors (such as + * character content that does not match an application's + * business rules). The information returned by the locator + * is probably not sufficient for use with a search engine.

+ * + *

Note that the locator will return correct information only + * during the invocation of the events in this interface. The + * application should not attempt to use it at any other time.

+ */ + public void setDocumentLocator(Locator locator) + { + m_locator = locator; + } + + /** + * Adds the given attribute to the set of collected attributes , but only if + * there is a currently open element. + * + * An element is currently open if a startElement() notification has + * occured but the start of the element has not yet been written to the + * output. In the stream case this means that we have not yet been forced + * to close the elements opening tag by another notification, such as a + * character notification. + * + * @param uri the URI of the attribute + * @param localName the local name of the attribute + * @param rawName the qualified name of the attribute + * @param type the type of the attribute (probably CDATA) + * @param value the value of the attribute + * @param XSLAttribute true if this attribute is coming from an xsl:attriute element + * @see ExtendedContentHandler#addAttribute(String, String, String, String, String) + */ + public void addAttribute( + String uri, + String localName, + String rawName, + String type, + String value, + boolean XSLAttribute) + throws SAXException + { + if (m_elemContext.m_startTagOpen) + { + addAttributeAlways(uri, localName, rawName, type, value, XSLAttribute); + } + + } + + /** + * Adds the given attribute to the set of attributes, even if there is + * no currently open element. This is useful if a SAX startPrefixMapping() + * should need to add an attribute before the element name is seen. + * + * @param uri the URI of the attribute + * @param localName the local name of the attribute + * @param rawName the qualified name of the attribute + * @param type the type of the attribute (probably CDATA) + * @param value the value of the attribute + * @param XSLAttribute true if this attribute is coming from an xsl:attribute element + * @return true if the attribute was added, + * false if an existing value was replaced. + */ + public boolean addAttributeAlways( + String uri, + String localName, + String rawName, + String type, + String value, + boolean XSLAttribute) + { + boolean was_added; +// final int index = +// (localName == null || uri == null) ? +// m_attributes.getIndex(rawName):m_attributes.getIndex(uri, localName); + int index; +// if (localName == null || uri == null){ +// index = m_attributes.getIndex(rawName); +// } +// else { +// index = m_attributes.getIndex(uri, localName); +// } + + if (localName == null || uri == null || uri.length() == 0) + index = m_attributes.getIndex(rawName); + else { + index = m_attributes.getIndex(uri,localName); + } + if (index >= 0) + { + /* We've seen the attribute before. + * We may have a null uri or localName, but all + * we really want to re-set is the value anyway. + */ + m_attributes.setValue(index,value); + was_added = false; + } + else + { + // the attribute doesn't exist yet, create it + m_attributes.addAttribute(uri, localName, rawName, type, value); + was_added = true; + } + return was_added; + + } + + + /** + * Adds the given attribute to the set of collected attributes, + * but only if there is a currently open element. + * + * @param name the attribute's qualified name + * @param value the value of the attribute + */ + public void addAttribute(String name, final String value) + { + if (m_elemContext.m_startTagOpen) + { + final String patchedName = patchName(name); + final String localName = getLocalName(patchedName); + final String uri = getNamespaceURI(patchedName, false); + + addAttributeAlways(uri,localName, patchedName, "CDATA", value, false); + } + } + + /** + * Adds the given xsl:attribute to the set of collected attributes, + * but only if there is a currently open element. + * + * @param name the attribute's qualified name (prefix:localName) + * @param value the value of the attribute + * @param uri the URI that the prefix of the name points to + */ + public void addXSLAttribute(String name, final String value, final String uri) + { + if (m_elemContext.m_startTagOpen) + { + final String patchedName = patchName(name); + final String localName = getLocalName(patchedName); + + addAttributeAlways(uri,localName, patchedName, "CDATA", value, true); + } + } + + /** + * Add the given attributes to the currently collected ones. These + * attributes are always added, regardless of whether on not an element + * is currently open. + * @param atts List of attributes to add to this list + */ + public void addAttributes(Attributes atts) throws SAXException + { + + int nAtts = atts.getLength(); + for (int i = 0; i < nAtts; i++) + { + String uri = atts.getURI(i); + + if (null == uri) + uri = ""; + + addAttributeAlways( + uri, + atts.getLocalName(i), + atts.getQName(i), + atts.getType(i), + atts.getValue(i), + false); + + } + } + + /** + * Return a {@link ContentHandler} interface into this serializer. + * If the serializer does not support the {@link ContentHandler} + * interface, it should return null. + * + * @return A {@link ContentHandler} interface into this serializer, + * or null if the serializer is not SAX 2 capable + * @throws IOException An I/O exception occured + */ + public ContentHandler asContentHandler() throws IOException + { + return this; + } + + /** + * Report the end of an entity. + * + * @param name The name of the entity that is ending. + * @throws org.xml.sax.SAXException The application may raise an exception. + * @see #startEntity + */ + public void endEntity(String name) throws org.xml.sax.SAXException + { + if (name.equals("[dtd]")) + m_inExternalDTD = false; + m_inEntityRef = false; + + if (m_tracer != null) + this.fireEndEntity(name); + } + + /** + * Flush and close the underlying java.io.Writer. This method applies to + * ToStream serializers, not ToSAXHandler serializers. + * @see ToStream + */ + public void close() + { + // do nothing (base behavior) + } + + /** + * Initialize global variables + */ + protected void initCDATA() + { + // CDATA stack + // _cdataStack = new Stack(); + // _cdataStack.push(new Integer(-1)); // push dummy value + } + + /** + * Returns the character encoding to be used in the output document. + * @return the character encoding to be used in the output document. + */ + public String getEncoding() + { + return m_encoding; + } + + /** + * Sets the character encoding coming from the xsl:output encoding stylesheet attribute. + * @param m_encoding the character encoding + */ + public void setEncoding(String m_encoding) + { + this.m_encoding = m_encoding; + } + + /** + * Sets the value coming from the xsl:output omit-xml-declaration stylesheet attribute + * @param b true if the XML declaration is to be omitted from the output + * document. + */ + public void setOmitXMLDeclaration(boolean b) + { + this.m_shouldNotWriteXMLHeader = b; + } + + + /** + * @return true if the XML declaration is to be omitted from the output + * document. + */ + public boolean getOmitXMLDeclaration() + { + return m_shouldNotWriteXMLHeader; + } + + /** + * Returns the previously set value of the value to be used as the public + * identifier in the document type declaration (DTD). + * + *@return the public identifier to be used in the DOCTYPE declaration in the + * output document. + */ + public String getDoctypePublic() + { + return m_doctypePublic; + } + + /** Set the value coming from the xsl:output doctype-public stylesheet attribute. + * @param doctypePublic the public identifier to be used in the DOCTYPE + * declaration in the output document. + */ + public void setDoctypePublic(String doctypePublic) + { + this.m_doctypePublic = doctypePublic; + } + + + /** + * Returns the previously set value of the value to be used + * as the system identifier in the document type declaration (DTD). + * @return the system identifier to be used in the DOCTYPE declaration in + * the output document. + * + */ + public String getDoctypeSystem() + { + return m_doctypeSystem; + } + + /** Set the value coming from the xsl:output doctype-system stylesheet attribute. + * @param doctypeSystem the system identifier to be used in the DOCTYPE + * declaration in the output document. + */ + public void setDoctypeSystem(String doctypeSystem) + { + this.m_doctypeSystem = doctypeSystem; + } + + /** Set the value coming from the xsl:output doctype-public and doctype-system stylesheet properties + * @param doctypeSystem the system identifier to be used in the DOCTYPE + * declaration in the output document. + * @param doctypePublic the public identifier to be used in the DOCTYPE + * declaration in the output document. + */ + public void setDoctype(String doctypeSystem, String doctypePublic) + { + this.m_doctypeSystem = doctypeSystem; + this.m_doctypePublic = doctypePublic; + } + + /** + * Sets the value coming from the xsl:output standalone stylesheet attribute. + * @param standalone a value of "yes" indicates that the + * standalone delaration is to be included in the output + * document. This method remembers if the value was explicitly set using + * this method, verses if the value is the default value. + */ + public void setStandalone(String standalone) + { + if (standalone != null) + { + m_standaloneWasSpecified = true; + setStandaloneInternal(standalone); + } + } + /** + * Sets the XSL standalone attribute, but does not remember if this is a + * default or explicite setting. + * @param standalone "yes" | "no" + */ + protected void setStandaloneInternal(String standalone) + { + if ("yes".equals(standalone)) + m_standalone = "yes"; + else + m_standalone = "no"; + + } + + /** + * Gets the XSL standalone attribute + * @return a value of "yes" if the standalone delaration is to + * be included in the output document. + * @see XSLOutputAttributes#getStandalone() + */ + public String getStandalone() + { + return m_standalone; + } + + /** + * @return true if the output document should be indented to visually + * indicate its structure. + */ + public boolean getIndent() + { + return m_doIndent; + } + /** + * Gets the mediatype the media-type or MIME type associated with the output + * document. + * @return the mediatype the media-type or MIME type associated with the + * output document. + */ + public String getMediaType() + { + return m_mediatype; + } + + /** + * Gets the version of the output format. + * @return the version of the output format. + */ + public String getVersion() + { + return m_version; + } + + /** + * Sets the value coming from the xsl:output version attribute. + * @param version the version of the output format. + * @see SerializationHandler#setVersion(String) + */ + public void setVersion(String version) + { + m_version = version; + } + + /** + * Sets the value coming from the xsl:output media-type stylesheet attribute. + * @param mediaType the non-null media-type or MIME type associated with the + * output document. + * @see javax.xml.transform.OutputKeys#MEDIA_TYPE + * @see SerializationHandler#setMediaType(String) + */ + public void setMediaType(String mediaType) + { + m_mediatype = mediaType; + } + + /** + * @return the number of spaces to indent for each indentation level. + */ + public int getIndentAmount() + { + return m_indentAmount; + } + + /** + * Sets the indentation amount. + * @param m_indentAmount The m_indentAmount to set + */ + public void setIndentAmount(int m_indentAmount) + { + this.m_indentAmount = m_indentAmount; + } + + /** + * Sets the value coming from the xsl:output indent stylesheet + * attribute. + * @param doIndent true if the output document should be indented to + * visually indicate its structure. + * @see XSLOutputAttributes#setIndent(boolean) + */ + public void setIndent(boolean doIndent) + { + m_doIndent = doIndent; + } + + /** + * This method is used when a prefix/uri namespace mapping + * is indicated after the element was started with a + * startElement() and before and endElement(). + * startPrefixMapping(prefix,uri) would be used before the + * startElement() call. + * @param uri the URI of the namespace + * @param prefix the prefix associated with the given URI. + * + * @see ExtendedContentHandler#namespaceAfterStartElement(String, String) + */ + public void namespaceAfterStartElement(String uri, String prefix) + throws SAXException + { + // default behavior is to do nothing + } + + /** + * Return a {@link DOMSerializer} interface into this serializer. If the + * serializer does not support the {@link DOMSerializer} interface, it should + * return null. + * + * @return A {@link DOMSerializer} interface into this serializer, or null + * if the serializer is not DOM capable + * @throws IOException An I/O exception occured + * @see Serializer#asDOMSerializer() + */ + public DOMSerializer asDOMSerializer() throws IOException + { + return this; + } + + /** + * Push a boolean state based on if the name of the current element + * is found in the list of qnames. A state is only pushed if + * there were some cdata-section-names were specified. + *

+ * Hidden parameters are the vector of qualified elements specified in + * cdata-section-names attribute, and the m_cdataSectionStates stack + * onto which whether the current element is in the list is pushed (true or + * false). Other hidden parameters are the current elements namespaceURI, + * localName and qName + */ + protected boolean isCdataSection() + { + + boolean b = false; + + if (null != m_cdataSectionElements) + { + if (m_elemContext.m_elementLocalName == null) + m_elemContext.m_elementLocalName = + getLocalName(m_elemContext.m_elementName); + if (m_elemContext.m_elementURI == null) + { + String prefix = getPrefixPart(m_elemContext.m_elementName); + if (prefix != null) + m_elemContext.m_elementURI = + m_prefixMap.lookupNamespace(prefix); + + } + + if ((null != m_elemContext.m_elementURI) + && m_elemContext.m_elementURI.length() == 0) + m_elemContext.m_elementURI = null; + + int nElems = m_cdataSectionElements.size(); + + // loop through 2 at a time, as these are pairs of URI and localName + for (int i = 0; i < nElems; i += 2) + { + String uri = (String) m_cdataSectionElements.elementAt(i); + String loc = (String) m_cdataSectionElements.elementAt(i + 1); + if (loc.equals(m_elemContext.m_elementLocalName) + && subPartMatch(m_elemContext.m_elementURI, uri)) + { + b = true; + + break; + } + } + } + return b; + } + + /** + * Tell if two strings are equal, without worry if the first string is null. + * + * @param p String reference, which may be null. + * @param t String reference, which may be null. + * + * @return true if strings are equal. + */ + private static final boolean subPartMatch(String p, String t) + { + return (p == t) || ((null != p) && (p.equals(t))); + } + + /** + * Returns the local name of a qualified name. + * If the name has no prefix, + * then it works as the identity (SAX2). + * + * @param qname a qualified name + * @return returns the prefix of the qualified name, + * or null if there is no prefix. + */ + protected static final String getPrefixPart(String qname) + { + final int col = qname.indexOf(':'); + return (col > 0) ? qname.substring(0, col) : null; + //return (col > 0) ? qname.substring(0,col) : ""; + } + + /** + * Some users of the serializer may need the current namespace mappings + * @return the current namespace mappings (prefix/uri) + * @see ExtendedContentHandler#getNamespaceMappings() + */ + public NamespaceMappings getNamespaceMappings() + { + return m_prefixMap; + } + + /** + * Returns the prefix currently pointing to the given URI (if any). + * @param namespaceURI the uri of the namespace in question + * @return a prefix pointing to the given URI (if any). + * @see ExtendedContentHandler#getPrefix(String) + */ + public String getPrefix(String namespaceURI) + { + String prefix = m_prefixMap.lookupPrefix(namespaceURI); + return prefix; + } + + /** + * Returns the URI of an element or attribute. Note that default namespaces + * do not apply directly to attributes. + * @param qname a qualified name + * @param isElement true if the qualified name is the name of + * an element. + * @return returns the namespace URI associated with the qualified name. + */ + public String getNamespaceURI(String qname, boolean isElement) + { + String uri = EMPTYSTRING; + int col = qname.lastIndexOf(':'); + final String prefix = (col > 0) ? qname.substring(0, col) : EMPTYSTRING; + + if (!EMPTYSTRING.equals(prefix) || isElement) + { + if (m_prefixMap != null) + { + uri = m_prefixMap.lookupNamespace(prefix); + if (uri == null && !prefix.equals(XMLNS_PREFIX)) + { + throw new RuntimeException( + Utils.messages.createMessage( + MsgKey.ER_NAMESPACE_PREFIX, + new Object[] { qname.substring(0, col) } )); + } + } + } + return uri; + } + + /** + * Returns the URI of prefix (if any) + * + * @param prefix the prefix whose URI is searched for + * @return the namespace URI currently associated with the + * prefix, null if the prefix is undefined. + */ + public String getNamespaceURIFromPrefix(String prefix) + { + String uri = null; + if (m_prefixMap != null) + uri = m_prefixMap.lookupNamespace(prefix); + return uri; + } + + /** + * Entity reference event. + * + * @param name Name of entity + * + * @throws org.xml.sax.SAXException + */ + public void entityReference(String name) throws org.xml.sax.SAXException + { + + flushPending(); + + startEntity(name); + endEntity(name); + + if (m_tracer != null) + fireEntityReference(name); + } + + /** + * Sets the transformer associated with this serializer + * @param t the transformer associated with this serializer. + * @see SerializationHandler#setTransformer(Transformer) + */ + public void setTransformer(Transformer t) + { + m_transformer = t; + + // If this transformer object implements the SerializerTrace interface + // then assign m_tracer to the transformer object so it can be used + // to fire trace events. + if ((m_transformer instanceof SerializerTrace) && + (((SerializerTrace) m_transformer).hasTraceListeners())) { + m_tracer = (SerializerTrace) m_transformer; + } else { + m_tracer = null; + } + } + /** + * Gets the transformer associated with this serializer + * @return returns the transformer associated with this serializer. + * @see SerializationHandler#getTransformer() + */ + public Transformer getTransformer() + { + return m_transformer; + } + + /** + * This method gets the nodes 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 + { + flushPending(); + String data = node.getNodeValue(); + if (data != null) + { + final int length = data.length(); + if (length > m_charsBuff.length) + { + m_charsBuff = new char[length * 2 + 1]; + } + data.getChars(0, length, m_charsBuff, 0); + characters(m_charsBuff, 0, length); + } + } + + + /** + * @see org.xml.sax.ErrorHandler#error(SAXParseException) + */ + public void error(SAXParseException exc) throws SAXException { + } + + /** + * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException) + */ + public void fatalError(SAXParseException exc) throws SAXException { + + m_elemContext.m_startTagOpen = false; + + } + + /** + * @see org.xml.sax.ErrorHandler#warning(SAXParseException) + */ + public void warning(SAXParseException exc) throws SAXException + { + } + + /** + * To fire off start entity trace event + * @param name Name of entity + */ + protected void fireStartEntity(String name) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENTITYREF, name); + } + } + + /** + * Report the characters event + * @param chars content of characters + * @param start starting index of characters to output + * @param length number of characters to output + */ +// protected void fireCharEvent(char[] chars, int start, int length) +// throws org.xml.sax.SAXException +// { +// if (m_tracer != null) +// m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CHARACTERS, chars, start,length); +// } +// + + /** + * This method is only used internally when flushing the writer from the + * various fire...() trace events. Due to the writer being wrapped with + * SerializerTraceWriter it may cause the flush of these trace events: + * EVENTTYPE_OUTPUT_PSEUDO_CHARACTERS + * EVENTTYPE_OUTPUT_CHARACTERS + * which trace the output written to the output stream. + * + */ + private void flushMyWriter() + { + if (m_writer != null) + { + try + { + m_writer.flush(); + } + catch(IOException ioe) + { + + } + } + } + /** + * Report the CDATA trace event + * @param chars content of CDATA + * @param start starting index of characters to output + * @param length number of characters to output + */ + protected void fireCDATAEvent(char[] chars, int start, int length) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_CDATA, chars, start,length); + } + } + + /** + * Report the comment trace event + * @param chars content of comment + * @param start starting index of comment to output + * @param length number of characters to output + */ + protected void fireCommentEvent(char[] chars, int start, int length) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_COMMENT, new String(chars, start, length)); + } + } + + + /** + * To fire off end entity trace event + * @param name Name of entity + */ + public void fireEndEntity(String name) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + flushMyWriter(); + // we do not need to handle this. + } + + /** + * To fire off start document trace event + */ + protected void fireStartDoc() + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_STARTDOCUMENT); + } + } + + + /** + * To fire off end document trace event + */ + protected void fireEndDoc() + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDDOCUMENT); + } + } + + /** + * Report the start element trace event. This trace method needs to be + * called just before the attributes are cleared. + * + * @param elemName the qualified name of the element + * + */ + protected void fireStartElem(String elemName) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_STARTELEMENT, + elemName, m_attributes); + } + } + + + /** + * To fire off the end element event + * @param name Name of element + */ +// protected void fireEndElem(String name) +// throws org.xml.sax.SAXException +// { +// if (m_tracer != null) +// m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENDELEMENT,name, (Attributes)null); +// } + + + /** + * To fire off the PI trace event + * @param name Name of PI + */ + protected void fireEscapingEvent(String name, String data) + throws org.xml.sax.SAXException + { + + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_PI,name, data); + } + } + + + /** + * To fire off the entity reference trace event + * @param name Name of entity reference + */ + protected void fireEntityReference(String name) + throws org.xml.sax.SAXException + { + if (m_tracer != null) + { + flushMyWriter(); + m_tracer.fireGenerateEvent(SerializerTrace.EVENTTYPE_ENTITYREF,name, (Attributes)null); + } + } + + /** + * Receive notification of the beginning of a document. + * This method is never a self generated call, + * but only called externally. + * + *

The SAX parser will invoke this method only once, before any + * other methods in this interface or in DTDHandler (except for + * setDocumentLocator).

+ * + * @throws org.xml.sax.SAXException Any SAX exception, possibly + * wrapping another exception. + * + * @throws org.xml.sax.SAXException + */ + public void startDocument() throws org.xml.sax.SAXException + { + + // if we do get called with startDocument(), handle it right away + startDocumentInternal(); + m_needToCallStartDocument = false; + return; + } + + /** + * This method handles what needs to be done at a startDocument() call, + * whether from an external caller, or internally called in the + * serializer. For historical reasons the serializer is flexible to + * startDocument() not always being called. + * Even if no external call is + * made into startDocument() this method will always be called as a self + * generated internal startDocument, it handles what needs to be done at a + * startDocument() call. + * + * This method exists just to make sure that startDocument() is only ever + * called from an external caller, which in principle is just a matter of + * style. + * + * @throws SAXException + */ + protected void startDocumentInternal() throws org.xml.sax.SAXException + { + if (m_tracer != null) + this.fireStartDoc(); + + } + + /* This method extracts version and encoding information from SAX events. + */ + protected void setDocumentInfo() { + if (m_locator == null) + return; + try{ + String strVersion = ((Locator2)m_locator).getXMLVersion(); + if (strVersion != null) + setVersion(strVersion); + /*String strEncoding = ((Locator2)m_locator).getEncoding(); + if (strEncoding != null) + setEncoding(strEncoding); */ + + }catch(ClassCastException e){} + } + + /** + * This method is used to set the source locator, which might be used to + * generated an error message. + * @param locator the source locator + * + * @see ExtendedContentHandler#setSourceLocator(javax.xml.transform.SourceLocator) + */ + public void setSourceLocator(SourceLocator locator) + { + m_sourceLocator = locator; + } + + + /** + * Used only by TransformerSnapshotImpl to restore the serialization + * to a previous state. + * + * @param mappings NamespaceMappings + */ + public void setNamespaceMappings(NamespaceMappings mappings) { + m_prefixMap = mappings; + } + + public boolean reset() + { + resetSerializerBase(); + return true; + } + + /** + * Reset all of the fields owned by SerializerBase + * + */ + private void resetSerializerBase() + { + this.m_attributes.clear(); + this.m_cdataSectionElements = null; + this.m_elemContext = new ElemContext(); + this.m_doctypePublic = null; + this.m_doctypeSystem = null; + this.m_doIndent = false; + this.m_encoding = null; + this.m_indentAmount = 0; + this.m_inEntityRef = false; + this.m_inExternalDTD = false; + this.m_mediatype = null; + this.m_needToCallStartDocument = true; + this.m_needToOutputDocTypeDecl = false; + if (this.m_prefixMap != null) + this.m_prefixMap.reset(); + this.m_shouldNotWriteXMLHeader = false; + this.m_sourceLocator = null; + this.m_standalone = null; + this.m_standaloneWasSpecified = false; + this.m_tracer = null; + this.m_transformer = null; + this.m_version = null; + // don't set writer to null, so that it might be re-used + //this.m_writer = null; + } + + /** + * Returns true if the serializer is used for temporary output rather than + * final output. + * + * This concept is made clear in the XSLT 2.0 draft. + */ + final boolean inTemporaryOutputState() + { + /* This is a hack. We should really be letting the serializer know + * that it is in temporary output state with an explicit call, but + * from a pragmatic point of view (for now anyways) having no output + * encoding at all, not even the default UTF-8 indicates that the serializer + * is being used for temporary RTF. + */ + return (getEncoding() == null); + + } + + /** + * This method adds an attribute the the current element, + * but should not be used for an xsl:attribute child. + * @see ExtendedContentHandler#addAttribute(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public void addAttribute(String uri, String localName, String rawName, String type, String value) throws SAXException + { + if (m_elemContext.m_startTagOpen) + { + addAttributeAlways(uri, localName, rawName, type, value, false); + } + } + + /** + * @see org.xml.sax.DTDHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String) + */ + public void notationDecl(String arg0, String arg1, String arg2) + throws SAXException { + // This method just provides a definition to satisfy the interface + // A particular sub-class of SerializerBase provides the implementation (if desired) + } + + /** + * @see org.xml.sax.DTDHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + public void unparsedEntityDecl( + String arg0, + String arg1, + String arg2, + String arg3) + throws SAXException { + // This method just provides a definition to satisfy the interface + // A particular sub-class of SerializerBase provides the implementation (if desired) + } + + /** + * If set to false the serializer does not expand DTD entities, + * but leaves them as is, the default value is true. + */ + public void setDTDEntityExpansion(boolean expand) { + // This method just provides a definition to satisfy the interface + // A particular sub-class of SerializerBase provides the implementation (if desired) + } + +}