--- /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.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ */
+ 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
+ * <code>standalone</code> 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 <code>standalone</code> 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.
+ * <p>
+ * 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.
+ *
+ * <p>The SAX parser will invoke this method only once, before any
+ * other methods in this interface or in DTDHandler (except for
+ * setDocumentLocator).</p>
+ *
+ * @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)
+ }
+
+}