jaxp/src/com/sun/org/apache/xml/internal/serializer/SerializerBase.java
changeset 12457 c348e06f0e82
parent 6 7f561c08de6b
child 12458 d601e4bba306
--- /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)
+    }
+
+}