alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (XMLStreamWriterImpl.java)

This example Java source code file (XMLStreamWriterImpl.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

arraylist, attribute, boolean, elementstate, ioexception, local, namespaceuri, outputstreamwriter, propertymanager, qname, string, stringbuffer, util, xml, xmlstreamexception, xmlstreamwriterimpl

The XMLStreamWriterImpl.java Java example source code

/*
 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.xml.internal.stream.writers;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.Vector;
import java.util.Set;
import java.util.Iterator;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.stream.StreamResult;

import com.sun.org.apache.xerces.internal.impl.Constants;
import com.sun.org.apache.xerces.internal.impl.PropertyManager;
import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
import com.sun.org.apache.xerces.internal.util.SymbolTable;
import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
import com.sun.org.apache.xerces.internal.xni.QName;

import com.sun.xml.internal.stream.util.ReadOnlyIterator;

/**
 * This class implements a StAX XMLStreamWriter. It extends
 * <code>AbstractMap in order to support a getter for
 * implementation-specific properties. For example, you can get
 * the underlying <code>OutputStream by casting an instance
 * of this class to <code>Map and calling
 * <code>getProperty(OUTPUTSTREAM_PROPERTY).
 *
 * @author Neeraj Bajaj
 * @author K.Venugopal
 * @author Santiago.Pericas-Geertsen@sun.com
 * @author Sunitha.Reddy@sun.com
 */
public final class XMLStreamWriterImpl extends AbstractMap implements XMLStreamWriter {

    public static final String START_COMMENT = "<!--";
    public static final String END_COMMENT = "-->";
    public static final String DEFAULT_ENCODING = " encoding=\"utf-8\"";
    public static final String DEFAULT_XMLDECL = "<?xml version=\"1.0\" ?>";
    public static final String DEFAULT_XML_VERSION = "1.0";
    public static final char CLOSE_START_TAG = '>';
    public static final char OPEN_START_TAG = '<';
    public static final String OPEN_END_TAG = "</";
    public static final char CLOSE_END_TAG = '>';
    public static final String START_CDATA = "<![CDATA[";
    public static final String END_CDATA = "]]>";
    public static final String CLOSE_EMPTY_ELEMENT = "/>";
    public static final String SPACE = " ";
    public static final String UTF_8 = "UTF-8";

    public static final String OUTPUTSTREAM_PROPERTY = "sjsxp-outputstream";

    /**
     * This flag can be used to turn escaping off for content. It does
     * not apply to attribute content.
     */
    boolean fEscapeCharacters = true;

    /**
     * Flag for the value of repairNamespace property
     */
    private boolean fIsRepairingNamespace = false;

    /**
     * Underlying Writer to which characters are written.
     */
    private Writer fWriter;

    /**
     * Underlying OutputStream to which <code>fWriter
     * writes to. May be null if unknown.
     */
    private OutputStream fOutputStream = null;

    /**
     * Collects attributes when the writer is in reparing mode.
     */
    private ArrayList fAttributeCache;

    /**
     * Collects namespace declarations when the writer is in reparing mode.
     */
    private ArrayList fNamespaceDecls;

    /**
     * Namespace context encapsulating user specified context
     * and context built by the writer
     */
    private NamespaceContextImpl fNamespaceContext = null;

    private NamespaceSupport fInternalNamespaceContext = null;

    private Random fPrefixGen = null;

    /**
     * Reference to PropertyManager
     */
    private PropertyManager fPropertyManager = null;

    /**
     * Flag to track if start tag is opened
     */
    private boolean fStartTagOpened = false;

    /**
     * Boolean flag  to indicate, if instance can be reused
     */
    private boolean fReuse;

    private SymbolTable fSymbolTable = new SymbolTable();

    private ElementStack fElementStack = new ElementStack(); //Change this .-Venu

    final private String DEFAULT_PREFIX = fSymbolTable.addSymbol("");

    private final ReadOnlyIterator fReadOnlyIterator = new ReadOnlyIterator();

    /**
     * In some cases, this charset encoder is used to determine if a char is
     * encodable by underlying writer. For example, an 8-bit char from the
     * extended ASCII set is not encodable by 7-bit ASCII encoder. Unencodable
     * chars are escaped using XML numeric entities.
     */
    private CharsetEncoder fEncoder = null;

     /**
     * This is used to hold the namespace for attributes which happen to have
     * the same uri as the default namespace; It's added to avoid changing the
     * current impl. which has many redundant code for the repair mode
     */
    HashMap fAttrNamespace = null;

    /**
     * Creates a new instance of XMLStreamWriterImpl. Uses platform's default
     * encoding.
     *
     * @param outputStream Underlying stream to write the bytes to
     * @param props        Properties used by this writer
     */
    public XMLStreamWriterImpl(OutputStream outputStream, PropertyManager props)
        throws IOException {

        // cannot call this(outputStream, null, props); for constructor,
        // OutputStreamWriter charsetName cannot be null

        // use default encoding
        this(new OutputStreamWriter(outputStream), props);
    }

    /**
     * Creates a new instance of XMLStreamWriterImpl.
     *
     * @param outputStream Underlying stream to write the bytes
     * @param encoding     Encoding used to convert chars into bytes
     * @param props        Properties used by this writer
     */
    public XMLStreamWriterImpl(OutputStream outputStream, String encoding,
        PropertyManager props) throws java.io.IOException {
        this(new StreamResult(outputStream), encoding, props);
    }

    /**
     * Creates a new instance of XMLStreamWriterImpl using a Writer.
     *
     * @param writer  Underlying writer to which chars are written
     * @param props   Properties used by this writer
     */
    public XMLStreamWriterImpl(Writer writer, PropertyManager props)
        throws java.io.IOException {
        this(new StreamResult(writer), null, props);
    }

    /**
     * Creates a new instance of XMLStreamWriterImpl using a StreamResult.
     * A StreamResult encasupates an OutputStream, a Writer or a SystemId.
     *
     * @param writer  Underlying writer to which chars are written
     * @param props   Properties used by this writer
     */
    public XMLStreamWriterImpl(StreamResult sr, String encoding,
        PropertyManager props) throws java.io.IOException {
        setOutput(sr, encoding);
        fPropertyManager = props;
        init();
    }

    /**
     * Initialize an instance of this XMLStreamWriter. Allocate new instances
     * for all the data structures. Set internal flags based on property values.
     */
    private void init() {
        fReuse = false;
        fNamespaceDecls = new ArrayList();
        fPrefixGen = new Random();
        fAttributeCache = new ArrayList();
        fInternalNamespaceContext = new NamespaceSupport();
        fInternalNamespaceContext.reset();
        fNamespaceContext = new NamespaceContextImpl();
        fNamespaceContext.internalContext = fInternalNamespaceContext;

        // Set internal state based on property values
        Boolean ob = (Boolean) fPropertyManager.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
        fIsRepairingNamespace = ob.booleanValue();
        ob = (Boolean) fPropertyManager.getProperty(Constants.ESCAPE_CHARACTERS);
        setEscapeCharacters(ob.booleanValue());
    }

    /**
     * Reset this instance so that it can be re-used. Do not read properties
     * again. The method <code>setOutput(StreamResult, encoding) must
     * be called after this one.
     */
    public void reset() {
        reset(false);
    }

    /**
     * Reset this instance so that it can be re-used. Clears but does not
     * re-allocate internal data structures.
     *
     * @param resetProperties Indicates if properties should be read again
     */
    void reset(boolean resetProperties) {
        if (!fReuse) {
            throw new java.lang.IllegalStateException(
                "close() Must be called before calling reset()");
        }

        fReuse = false;
        fNamespaceDecls.clear();
        fAttributeCache.clear();

        // reset Element/NamespaceContext stacks
        fElementStack.clear();
        fInternalNamespaceContext.reset();

        fStartTagOpened = false;
        fNamespaceContext.userContext = null;

        if (resetProperties) {
            Boolean ob = (Boolean) fPropertyManager.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES);
            fIsRepairingNamespace = ob.booleanValue();
            ob = (Boolean) fPropertyManager.getProperty(Constants.ESCAPE_CHARACTERS);
            setEscapeCharacters(ob.booleanValue());
        }
    }

    /**
     * Use a StreamResult to initialize the output for this XMLStreamWriter. Check
     * for OutputStream, Writer and then systemId, in that order.
     *
     * @param sr        StreamResult encapsulating output information
     * @param encoding  Encoding to be used except when a Writer is available
     */
    public void setOutput(StreamResult sr, String encoding)
        throws IOException {

        if (sr.getOutputStream() != null) {
            setOutputUsingStream(sr.getOutputStream(), encoding);
        }
        else if (sr.getWriter() != null) {
            setOutputUsingWriter(sr.getWriter());
        }
        else if (sr.getSystemId() != null) {
            setOutputUsingStream(new FileOutputStream(sr.getSystemId()),
                encoding);
        }
    }

     private void setOutputUsingWriter(Writer writer)
        throws IOException
     {
         fWriter = writer;

         if (writer instanceof OutputStreamWriter) {
             String charset = ((OutputStreamWriter) writer).getEncoding();
             if (charset != null && !charset.equalsIgnoreCase("utf-8")) {
                 fEncoder = Charset.forName(charset).newEncoder();
             }
         }
     }

    /**
     * Utility method to create a writer when passed an OutputStream. Make
     * sure to wrap an <code>OutputStreamWriter using an
     * <code>XMLWriter for performance reasons.
     *
     * @param os        Underlying OutputStream
     * @param encoding  Encoding used to convert chars into bytes
     */
    private void setOutputUsingStream(OutputStream os, String encoding)
        throws IOException {
        fOutputStream = os;

        if (encoding != null) {
            if (encoding.equalsIgnoreCase("utf-8")) {
                fWriter = new UTF8OutputStreamWriter(os);
            }
            else {
                fWriter = new XMLWriter(new OutputStreamWriter(os, encoding));
                fEncoder = Charset.forName(encoding).newEncoder();
            }
        } else {
            encoding = SecuritySupport.getSystemProperty("file.encoding");
            if (encoding != null && encoding.equalsIgnoreCase("utf-8")) {
                fWriter = new UTF8OutputStreamWriter(os);
            } else {
                fWriter = new XMLWriter(new OutputStreamWriter(os));
            }
        }
    }

    /** Can this instance be reused
     *
     * @return boolean boolean value to indicate if this instance can be reused or not
     */
    public boolean canReuse() {
        return fReuse;
    }

    public void setEscapeCharacters(boolean escape) {
        fEscapeCharacters = escape;
    }

    public boolean getEscapeCharacters() {
        return fEscapeCharacters;
    }

    /**
     * Close this XMLStreamWriter by closing underlying writer.
     */
    public void close() throws XMLStreamException {
        if (fWriter != null) {
            try {
                //fWriter.close();
                fWriter.flush();
            } catch (IOException e) {
                throw new XMLStreamException(e);
            }
        }
        fWriter = null;
        fOutputStream = null;
        fNamespaceDecls.clear();
        fAttributeCache.clear();
        fElementStack.clear();
        fInternalNamespaceContext.reset();
        fReuse = true;
        fStartTagOpened = false;
        fNamespaceContext.userContext = null;
    }

    /**
     * Flush this XMLStreamWriter by flushin underlying writer.
     */
    public void flush() throws XMLStreamException {
        try {
            fWriter.flush();
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    /**
     * Return <code>NamespaceContext being used by the writer.
     *
     * @return NamespaceContext
     */
    public NamespaceContext getNamespaceContext() {
        return fNamespaceContext;
    }

    /**
     * Return a prefix associated with specified uri, or null if the
     * uri is unknown.
     *
     * @param  uri The namespace uri
     * @throws XMLStreamException if uri specified is "" or null
     */
    public String getPrefix(String uri) throws XMLStreamException {
        return fNamespaceContext.getPrefix(uri);
    }

    /**
     * Returns value associated with the specified property name.
     *
     * @param  str Property name
     * @throws IllegalArgumentException if the specified property is not supported
     * @return value associated with the specified property.
     */
    public Object getProperty(String str)
        throws IllegalArgumentException {
        if (str == null) {
            throw new NullPointerException();
        }

        if (!fPropertyManager.containsProperty(str)) {
            throw new IllegalArgumentException("Property '" + str +
                "' is not supported");
        }

        return fPropertyManager.getProperty(str);
    }

    /**
     * Set the specified URI as default namespace in the current namespace context.
     *
     * @param uri Namespace URI
     */
    public void setDefaultNamespace(String uri) throws XMLStreamException {
        if (uri != null) {
            uri = fSymbolTable.addSymbol(uri);
        }

        if (fIsRepairingNamespace) {
            if (isDefaultNamespace(uri)) {
                return;
            }

            QName qname = new QName();
            qname.setValues(DEFAULT_PREFIX, "xmlns", null, uri);
            fNamespaceDecls.add(qname);
        } else {
            fInternalNamespaceContext.declarePrefix(DEFAULT_PREFIX, uri);
        }
    }

    /**
     * Sets the current <code>NamespaceContext for prefix and uri bindings.
     * This context becomes the root namespace context for writing and
     * will replace the current root namespace context. Subsequent calls
     * to setPrefix and setDefaultNamespace will bind namespaces using
     * the context passed to the method as the root context for resolving
     * namespaces. This method may only be called once at the start of the
     * document. It does not cause the namespaces to be declared. If a
     * namespace URI to prefix mapping is found in the namespace context
     * it is treated as declared and the prefix may be used by the
     * <code>XMLStreamWriter.
     *
     * @param namespaceContext the namespace context to use for this writer, may not be null
     * @throws XMLStreamException
     */
    public void setNamespaceContext(NamespaceContext namespaceContext)
        throws XMLStreamException {
        fNamespaceContext.userContext = namespaceContext;
    }

    /**
     * Sets the prefix the uri is bound to. This prefix is bound in the scope of
     * the current START_ELEMENT / END_ELEMENT pair. If this method is called before
     * a START_ELEMENT has been written the prefix is bound in the root scope.
     *
     * @param prefix
     * @param uri
     * @throws XMLStreamException
     */
    public void setPrefix(String prefix, String uri) throws XMLStreamException {

        if (prefix == null) {
            throw new XMLStreamException("Prefix cannot be null");
        }

        if (uri == null) {
            throw new XMLStreamException("URI cannot be null");
        }

        prefix = fSymbolTable.addSymbol(prefix);
        uri = fSymbolTable.addSymbol(uri);

        if (fIsRepairingNamespace) {
            String tmpURI = fInternalNamespaceContext.getURI(prefix);

            if ((tmpURI != null) && (tmpURI == uri)) {
                return;
            }

            if(checkUserNamespaceContext(prefix,uri))
                return;
            QName qname = new QName();
            qname.setValues(prefix,XMLConstants.XMLNS_ATTRIBUTE, null,uri);
            fNamespaceDecls.add(qname);

            return;
        }

        fInternalNamespaceContext.declarePrefix(prefix, uri);
    }

    public void writeAttribute(String localName, String value)
        throws XMLStreamException {
        try {
            if (!fStartTagOpened) {
                throw new XMLStreamException(
                    "Attribute not associated with any element");
            }

            if (fIsRepairingNamespace) {
                Attribute attr = new Attribute(value); // Revisit:Dont create new one's. Reuse.-Venu
                attr.setValues(null, localName, null, null);
                fAttributeCache.add(attr);

                return;
            }

            fWriter.write(" ");
            fWriter.write(localName);
            fWriter.write("=\"");
            writeXMLContent(
                    value,
                    true,   // true = escapeChars
                    true);  // true = escapeDoubleQuotes
            fWriter.write("\"");
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeAttribute(String namespaceURI, String localName,
        String value) throws XMLStreamException {
        try {
            if (!fStartTagOpened) {
                throw new XMLStreamException(
                    "Attribute not associated with any element");
            }

            if (namespaceURI == null) {
                throw new XMLStreamException("NamespaceURI cannot be null");
            }

            namespaceURI = fSymbolTable.addSymbol(namespaceURI);

            String prefix = fInternalNamespaceContext.getPrefix(namespaceURI);

            if (!fIsRepairingNamespace) {
                if (prefix == null) {
                    throw new XMLStreamException("Prefix cannot be null");
                }

                writeAttributeWithPrefix(prefix, localName, value);
            } else {
                Attribute attr = new Attribute(value);
                attr.setValues(null, localName, null, namespaceURI);
                fAttributeCache.add(attr);
            }
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    private void writeAttributeWithPrefix(String prefix, String localName,
        String value) throws IOException {
        fWriter.write(SPACE);

        if ((prefix != null) && (prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
            fWriter.write(prefix);
            fWriter.write(":");
        }

        fWriter.write(localName);
        fWriter.write("=\"");
        writeXMLContent(value,
                true,   // true = escapeChars
                true);  // true = escapeDoubleQuotes
        fWriter.write("\"");
    }

    public void writeAttribute(String prefix, String namespaceURI,
        String localName, String value) throws XMLStreamException {
        try {
            if (!fStartTagOpened) {
                throw new XMLStreamException(
                    "Attribute not associated with any element");
            }

            if (namespaceURI == null) {
                throw new XMLStreamException("NamespaceURI cannot be null");
            }

            if (localName == null) {
                throw new XMLStreamException("Local name cannot be null");
            }

            if (!fIsRepairingNamespace) {
                if (prefix == null || prefix.equals("")){
                    if (!namespaceURI.equals("")) {
                        throw new XMLStreamException("prefix cannot be null or empty");
                    } else {
                        writeAttributeWithPrefix(null, localName, value);
                        return;
                    }
                }

                if (!prefix.equals(XMLConstants.XML_NS_PREFIX) || !namespaceURI.equals(XMLConstants.XML_NS_URI)) {

                    prefix = fSymbolTable.addSymbol(prefix);
                    namespaceURI = fSymbolTable.addSymbol(namespaceURI);

                    if (fInternalNamespaceContext.containsPrefixInCurrentContext(prefix)){

                        String tmpURI = fInternalNamespaceContext.getURI(prefix);

                        if (tmpURI != null && tmpURI != namespaceURI){
                            throw new XMLStreamException("Prefix "+prefix+" is " +
                                    "already bound to "+tmpURI+
                                    ". Trying to rebind it to "+namespaceURI+" is an error.");
                        }
                    }
                    fInternalNamespaceContext.declarePrefix(prefix, namespaceURI);
                }
                writeAttributeWithPrefix(prefix, localName, value);
            } else {
                if (prefix != null) {
                    prefix = fSymbolTable.addSymbol(prefix);
                }

                namespaceURI = fSymbolTable.addSymbol(namespaceURI);

                Attribute attr = new Attribute(value);
                attr.setValues(prefix, localName, null, namespaceURI);
                fAttributeCache.add(attr);
            }
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeCData(String cdata) throws XMLStreamException {
        try {
            if (cdata == null) {
                throw new XMLStreamException("cdata cannot be null");
            }

            if (fStartTagOpened) {
                closeStartTag();
            }

            fWriter.write(START_CDATA);
            fWriter.write(cdata);
            fWriter.write(END_CDATA);
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeCharacters(String data) throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            writeXMLContent(data);
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeCharacters(char[] data, int start, int len)
        throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            writeXMLContent(data, start, len, fEscapeCharacters);
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeComment(String comment) throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            fWriter.write(START_COMMENT);

            if (comment != null) {
                fWriter.write(comment);
            }

            fWriter.write(END_COMMENT);
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeDTD(String dtd) throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            fWriter.write(dtd);
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    /*
     * Write default Namespace.
     *
     * If namespaceURI == null,
     * then it is assumed to be equivilent to {@link XMLConstants.NULL_NS_URI},
     * i.e. there is no Namespace.
     *
     * @param namespaceURI NamespaceURI to declare.
     *
     * @throws XMLStreamException
     *
     * @see <a href="http://www.w3.org/TR/REC-xml-names/#defaulting">
     *   Namespaces in XML, 5.2 Namespace Defaulting</a>
     */
    public void writeDefaultNamespace(String namespaceURI)
        throws XMLStreamException {

        // normalize namespaceURI
        String namespaceURINormalized = null;
        if (namespaceURI == null) {
            namespaceURINormalized = ""; // XMLConstants.NULL_NS_URI
        } else {
            namespaceURINormalized = namespaceURI;
        }

        try {
            if (!fStartTagOpened) {
                throw new IllegalStateException(
                    "Namespace Attribute not associated with any element");
            }

            if (fIsRepairingNamespace) {
                QName qname = new QName();
                qname.setValues(XMLConstants.DEFAULT_NS_PREFIX,
                    XMLConstants.XMLNS_ATTRIBUTE, null, namespaceURINormalized);
                fNamespaceDecls.add(qname);

                return;
            }

            namespaceURINormalized = fSymbolTable.addSymbol(namespaceURINormalized);

            if (fInternalNamespaceContext.containsPrefixInCurrentContext("")){

                String tmp = fInternalNamespaceContext.getURI("");

                if (tmp != null && tmp != namespaceURINormalized) {
                        throw new XMLStreamException(
                                "xmlns has been already bound to " +tmp +
                                ". Rebinding it to "+ namespaceURINormalized +
                                " is an error");
                    }
            }
            fInternalNamespaceContext.declarePrefix("", namespaceURINormalized);

            // use common namespace code with a prefix == null for xmlns="..."
            writenamespace(null, namespaceURINormalized);
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeEmptyElement(String localName) throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            openStartTag();
            fElementStack.push(null, localName, null, null, true);
            fInternalNamespaceContext.pushContext();

            if (!fIsRepairingNamespace) {
                fWriter.write(localName);
            }
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeEmptyElement(String namespaceURI, String localName)
        throws XMLStreamException {
        if (namespaceURI == null) {
            throw new XMLStreamException("NamespaceURI cannot be null");
        }

        namespaceURI = fSymbolTable.addSymbol(namespaceURI);

        String prefix = fNamespaceContext.getPrefix(namespaceURI);
        writeEmptyElement(prefix, localName, namespaceURI);
    }

    public void writeEmptyElement(String prefix, String localName,
        String namespaceURI) throws XMLStreamException {
        try {
            if (localName == null) {
                throw new XMLStreamException("Local Name cannot be null");
            }

            if (namespaceURI == null) {
                throw new XMLStreamException("NamespaceURI cannot be null");
            }

            if (prefix != null) {
                prefix = fSymbolTable.addSymbol(prefix);
            }

            namespaceURI = fSymbolTable.addSymbol(namespaceURI);

            if (fStartTagOpened) {
                closeStartTag();
            }

            openStartTag();

            fElementStack.push(prefix, localName, null, namespaceURI, true);
            fInternalNamespaceContext.pushContext();

            if (!fIsRepairingNamespace) {
                if (prefix == null) {
                    throw new XMLStreamException("NamespaceURI " +
                        namespaceURI + " has not been bound to any prefix");
                }
            } else {
                return;
            }

            if ((prefix != null) && (prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
                fWriter.write(prefix);
                fWriter.write(":");
            }

            fWriter.write(localName);
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    public void writeEndDocument() throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            ElementState elem = null;

            while (!fElementStack.empty()) {
                elem = (ElementState) fElementStack.pop();
                fInternalNamespaceContext.popContext();

                if (elem.isEmpty) {
                    //fWriter.write(CLOSE_EMPTY_ELEMENT);
                } else {
                    fWriter.write(OPEN_END_TAG);

                    if ((elem.prefix != null) && !(elem.prefix).equals("")) {
                        fWriter.write(elem.prefix);
                        fWriter.write(":");
                    }

                    fWriter.write(elem.localpart);
                    fWriter.write(CLOSE_END_TAG);
                }
            }
        } catch (IOException e) {
            throw new XMLStreamException(e);
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new XMLStreamException("No more elements to write");
        }
    }

    public void writeEndElement() throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            ElementState currentElement = (ElementState) fElementStack.pop();

            if (currentElement == null) {
                throw new XMLStreamException("No element was found to write");
            }

            if (currentElement.isEmpty) {
                //fWriter.write(CLOSE_EMPTY_ELEMENT);
                return;
            }

            fWriter.write(OPEN_END_TAG);

            if ((currentElement.prefix != null) &&
                    !(currentElement.prefix).equals("")) {
                fWriter.write(currentElement.prefix);
                fWriter.write(":");
            }

            fWriter.write(currentElement.localpart);
            fWriter.write(CLOSE_END_TAG);
            fInternalNamespaceContext.popContext();
        } catch (IOException e) {
            throw new XMLStreamException(e);
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new XMLStreamException(
                    "No element was found to write: "
                    + e.toString(), e);
        }
    }

    public void writeEntityRef(String refName) throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            fWriter.write('&');
            fWriter.write(refName);
            fWriter.write(';');
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    /**
     * Write a Namespace declaration.
     *
     * If namespaceURI == null,
     * then it is assumed to be equivilent to {@link XMLConstants.NULL_NS_URI},
     * i.e. there is no Namespace.
     *
     * @param prefix Prefix to bind.
     * @param namespaceURI NamespaceURI to declare.
     *
     * @throws XMLStreamException
     *
     * @see <a href="http://www.w3.org/TR/REC-xml-names/#defaulting">
     *   Namespaces in XML, 5.2 Namespace Defaulting</a>
     */
    public void writeNamespace(String prefix, String namespaceURI)
        throws XMLStreamException {

        // normalize namespaceURI
        String namespaceURINormalized = null;
        if (namespaceURI == null) {
            namespaceURINormalized = ""; // XMLConstants.NULL_NS_URI
        } else {
            namespaceURINormalized = namespaceURI;
        }

        try {
            QName qname = null;

            if (!fStartTagOpened) {
                throw new IllegalStateException(
                        "Invalid state: start tag is not opened at writeNamespace("
                        + prefix
                        + ", "
                        + namespaceURINormalized
                        + ")");
            }

            // is this the default Namespace?
            if (prefix == null
                    || prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)
                    || prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
                writeDefaultNamespace(namespaceURINormalized);
                return;
            }

            if (prefix.equals(XMLConstants.XML_NS_PREFIX) && namespaceURINormalized.equals(XMLConstants.XML_NS_URI))
                return;

            prefix = fSymbolTable.addSymbol(prefix);
            namespaceURINormalized = fSymbolTable.addSymbol(namespaceURINormalized);

            if (fIsRepairingNamespace) {
                String tmpURI = fInternalNamespaceContext.getURI(prefix);

                if ((tmpURI != null) && (tmpURI == namespaceURINormalized)) {
                    return;
                }

                qname = new QName();
                qname.setValues(prefix, XMLConstants.XMLNS_ATTRIBUTE, null,
                    namespaceURINormalized);
                fNamespaceDecls.add(qname);

                return;
            }


            if (fInternalNamespaceContext.containsPrefixInCurrentContext(prefix)){

                String tmp = fInternalNamespaceContext.getURI(prefix);

                if (tmp != null && tmp != namespaceURINormalized) {

                       throw new XMLStreamException("prefix "+prefix+
                            " has been already bound to " +tmp +
                            ". Rebinding it to "+ namespaceURINormalized+
                            " is an error");
                }
            }

            fInternalNamespaceContext.declarePrefix(prefix, namespaceURINormalized);
            writenamespace(prefix, namespaceURINormalized);

        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    private void writenamespace(String prefix, String namespaceURI)
        throws IOException {
        fWriter.write(" xmlns");

        if ((prefix != null) && (prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
            fWriter.write(":");
            fWriter.write(prefix);
        }

        fWriter.write("=\"");
        writeXMLContent(
                namespaceURI,
                true,   // true = escapeChars
                true);  // true = escapeDoubleQuotes
        fWriter.write("\"");
    }

    public void writeProcessingInstruction(String target)
        throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            if (target != null) {
                fWriter.write("<?");
                fWriter.write(target);
                fWriter.write("?>");

                return;
            }
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }

        throw new XMLStreamException("PI target cannot be null");
    }

    /**
     * @param target
     * @param data
     * @throws XMLStreamException
     */
    public void writeProcessingInstruction(String target, String data)
        throws XMLStreamException {
        try {
            if (fStartTagOpened) {
                closeStartTag();
            }

            if ((target == null) || (data == null)) {
                throw new XMLStreamException("PI target cannot be null");
            }

            fWriter.write("<?");
            fWriter.write(target);
            fWriter.write(SPACE);
            fWriter.write(data);
            fWriter.write("?>");
        } catch (IOException e) {
            throw new XMLStreamException(e);
        }
    }

    /**
     * @throws XMLStreamException
     */
    public void writeStartDocument() throws XMLStreamException {
        try {
            fWriter.write(DEFAULT_XMLDECL);
        } catch (IOException ex) {
            throw new XMLStreamException(ex);
        }
    }

    /**
     * @param version
     * @throws XMLStreamException
     */
    public void writeStartDocument(String version) throws XMLStreamException {
        try {
            if ((version == null) || version.equals("")) {
                writeStartDocument();

                return;
            }

            fWriter.write("<?xml version=\"");
            fWriter.write(version);
            fWriter.write("\"");

            //fWriter.write(DEFAULT_ENCODING);
            fWriter.write("?>");
        } catch (IOException ex) {
            throw new XMLStreamException(ex);
        }
    }

    /**
     * @param encoding
     * @param version
     * @throws XMLStreamException
     */
    public void writeStartDocument(String encoding, String version)
        throws XMLStreamException {
        //Revisit : What about standalone ?
        try {
            if ((encoding == null) && (version == null)) {
                writeStartDocument();

                return;
            }

            if (encoding == null) {
                writeStartDocument(version);

                return;
            }

            String streamEncoding = null;
            if (fWriter instanceof OutputStreamWriter) {
                streamEncoding = ((OutputStreamWriter) fWriter).getEncoding();
            }
            else if (fWriter instanceof UTF8OutputStreamWriter) {
                streamEncoding = ((UTF8OutputStreamWriter) fWriter).getEncoding();
            }
            else if (fWriter instanceof XMLWriter) {
                streamEncoding = ((OutputStreamWriter) ((XMLWriter)fWriter).getWriter()).getEncoding();
            }

            if (streamEncoding != null && !streamEncoding.equalsIgnoreCase(encoding)) {
                // If the equality check failed, check for charset encoding aliases
                boolean foundAlias = false;
                Set aliases = Charset.forName(encoding).aliases();
                for (Iterator it = aliases.iterator(); !foundAlias && it.hasNext(); ) {
                    if (streamEncoding.equalsIgnoreCase((String) it.next())) {
                        foundAlias = true;
                    }
                }
                // If no alias matches the encoding name, then report error
                if (!foundAlias) {
                    throw new XMLStreamException("Underlying stream encoding '"
                            + streamEncoding
                            + "' and input paramter for writeStartDocument() method '"
                            + encoding + "' do not match.");
                }
            }


            fWriter.write("<?xml version=\"");

            if ((version == null) || version.equals("")) {
                fWriter.write(DEFAULT_XML_VERSION);
            } else {
                fWriter.write(version);
            }

            if (!encoding.equals("")) {
                fWriter.write("\" encoding=\"");
                fWriter.write(encoding);
            }

            fWriter.write("\"?>");
        } catch (IOException ex) {
            throw new XMLStreamException(ex);
        }
    }

    /**
     * @param localName
     * @throws XMLStreamException
     */
    public void writeStartElement(String localName) throws XMLStreamException {
        try {
            if (localName == null) {
                throw new XMLStreamException("Local Name cannot be null");
            }

            if (fStartTagOpened) {
                closeStartTag();
            }

            openStartTag();
            fElementStack.push(null, localName, null, null, false);
            fInternalNamespaceContext.pushContext();

            if (fIsRepairingNamespace) {
                return;
            }

            fWriter.write(localName);
        } catch (IOException ex) {
            throw new XMLStreamException(ex);
        }
    }

    /**
     * @param namespaceURI
     * @param localName
     * @throws XMLStreamException
     */
    public void writeStartElement(String namespaceURI, String localName)
        throws XMLStreamException {
        if (localName == null) {
            throw new XMLStreamException("Local Name cannot be null");
        }

        if (namespaceURI == null) {
            throw new XMLStreamException("NamespaceURI cannot be null");
        }

        namespaceURI = fSymbolTable.addSymbol(namespaceURI);

        String prefix = null;

        if (!fIsRepairingNamespace) {
            prefix = fNamespaceContext.getPrefix(namespaceURI);

            if (prefix != null) {
                prefix = fSymbolTable.addSymbol(prefix);
            }
        }

        writeStartElement(prefix, localName, namespaceURI);
    }

    /**
     * @param prefix
     * @param localName
     * @param namespaceURI
     * @throws XMLStreamException
     */
    public void writeStartElement(String prefix, String localName,
        String namespaceURI) throws XMLStreamException {
        try {
            if (localName == null) {
                throw new XMLStreamException("Local Name cannot be null");
            }

            if (namespaceURI == null) {
                throw new XMLStreamException("NamespaceURI cannot be null");
            }

            if (!fIsRepairingNamespace) {
                if (prefix == null) {
                    throw new XMLStreamException("Prefix cannot be null");
                }
            }

            if (fStartTagOpened) {
                closeStartTag();
            }

            openStartTag();
            namespaceURI = fSymbolTable.addSymbol(namespaceURI);

            if (prefix != null) {
                prefix = fSymbolTable.addSymbol(prefix);
            }

            fElementStack.push(prefix, localName, null, namespaceURI, false);
            fInternalNamespaceContext.pushContext();

            String tmpPrefix = fNamespaceContext.getPrefix(namespaceURI);


            if ((prefix != null) &&
                    ((tmpPrefix == null) || !prefix.equals(tmpPrefix))) {
                fInternalNamespaceContext.declarePrefix(prefix, namespaceURI);

            }

            if (fIsRepairingNamespace) {
                if ((prefix == null) ||
                        ((tmpPrefix != null) && prefix.equals(tmpPrefix))) {
                    return;
                }

                QName qname = new QName();
                qname.setValues(prefix, XMLConstants.XMLNS_ATTRIBUTE, null,
                    namespaceURI);
                fNamespaceDecls.add(qname);

                return;
            }

            if ((prefix != null) && (prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
                fWriter.write(prefix);
                fWriter.write(":");
            }

            fWriter.write(localName);

        } catch (IOException ex) {
            throw new XMLStreamException(ex);
        }
    }

    /**
     * Writes XML content to underlying writer. Escapes characters unless
     * escaping character feature is turned off.
     */
    private void writeXMLContent(char[] content, int start, int length,
        boolean escapeChars) throws IOException {
        if (!escapeChars) {
            fWriter.write(content, start, length);

            return;
        }

        // Index of the next char to be written
        int startWritePos = start;

        final int end = start + length;

        for (int index = start; index < end; index++) {
            char ch = content[index];

            if (fEncoder != null && !fEncoder.canEncode(ch)){
                fWriter.write(content, startWritePos, index - startWritePos );

                // Escape this char as underlying encoder cannot handle it
                fWriter.write( "&#x" );
                fWriter.write(Integer.toHexString(ch));
                fWriter.write( ';' );
                startWritePos = index + 1;
                continue;
            }

            switch (ch) {
            case '<':
                fWriter.write(content, startWritePos, index - startWritePos);
                fWriter.write("<");
                startWritePos = index + 1;

                break;

            case '&':
                fWriter.write(content, startWritePos, index - startWritePos);
                fWriter.write("&");
                startWritePos = index + 1;

                break;

            case '>':
                fWriter.write(content, startWritePos, index - startWritePos);
                fWriter.write(">");
                startWritePos = index + 1;

                break;
            }
        }

        // Write any pending data
        fWriter.write(content, startWritePos, end - startWritePos);
    }

    private void writeXMLContent(String content) throws IOException {
        if ((content != null) && (content.length() > 0)) {
            writeXMLContent(content,
                    fEscapeCharacters,  // boolean = escapeChars
                    false);             // false = escapeDoubleQuotes
        }
    }

    /**
     * Writes XML content to underlying writer. Escapes characters unless
     * escaping character feature is turned off.
     */
    private void writeXMLContent(
            String content,
            boolean escapeChars,
            boolean escapeDoubleQuotes)
        throws IOException {

        if (!escapeChars) {
            fWriter.write(content);

            return;
        }

        // Index of the next char to be written
        int startWritePos = 0;

        final int end = content.length();

        for (int index = 0; index < end; index++) {
            char ch = content.charAt(index);

            if (fEncoder != null && !fEncoder.canEncode(ch)){
                fWriter.write(content, startWritePos, index - startWritePos );

                // Escape this char as underlying encoder cannot handle it
                fWriter.write( "&#x" );
                fWriter.write(Integer.toHexString(ch));
                fWriter.write( ';' );
                startWritePos = index + 1;
                continue;
            }

            switch (ch) {
            case '<':
                fWriter.write(content, startWritePos, index - startWritePos);
                fWriter.write("<");
                startWritePos = index + 1;

                break;

            case '&':
                fWriter.write(content, startWritePos, index - startWritePos);
                fWriter.write("&");
                startWritePos = index + 1;

                break;

            case '>':
                fWriter.write(content, startWritePos, index - startWritePos);
                fWriter.write(">");
                startWritePos = index + 1;

                break;

            case '"':
                fWriter.write(content, startWritePos, index - startWritePos);
                if (escapeDoubleQuotes) {
                    fWriter.write(""");
                } else {
                    fWriter.write('"');
                }
                startWritePos = index + 1;

                break;
            }
        }

        // Write any pending data
        fWriter.write(content, startWritePos, end - startWritePos);
    }

    /**
     * marks close of start tag and writes the same into the writer.
     */
    private void closeStartTag() throws XMLStreamException {
        try {
            ElementState currentElement = fElementStack.peek();

            if (fIsRepairingNamespace) {
                repair();
                correctPrefix(currentElement, XMLStreamConstants.START_ELEMENT);

                if ((currentElement.prefix != null) &&
                        (currentElement.prefix != XMLConstants.DEFAULT_NS_PREFIX)) {
                    fWriter.write(currentElement.prefix);
                    fWriter.write(":");
                }

                fWriter.write(currentElement.localpart);

                int len = fNamespaceDecls.size();
                QName qname = null;

                for (int i = 0; i < len; i++) {
                    qname = (QName) fNamespaceDecls.get(i);

                    if (qname != null) {
                        if (fInternalNamespaceContext.declarePrefix(qname.prefix,
                            qname.uri)) {
                            writenamespace(qname.prefix, qname.uri);
                        }
                    }
                }

                fNamespaceDecls.clear();

                Attribute attr = null;

                for (int j = 0; j < fAttributeCache.size(); j++) {
                    attr = (Attribute) fAttributeCache.get(j);

                    if ((attr.prefix != null) && (attr.uri != null)) {
                        if (!attr.prefix.equals("") && !attr.uri.equals("") ) {
                            String tmp = fInternalNamespaceContext.getPrefix(attr.uri);

                            if ((tmp == null) || (tmp != attr.prefix)) {
                                tmp = getAttrPrefix(attr.uri);
                                if (tmp == null) {
                                    if (fInternalNamespaceContext.declarePrefix(attr.prefix,
                                        attr.uri)) {
                                        writenamespace(attr.prefix, attr.uri);
                                    }
                                } else {
                                    writenamespace(attr.prefix, attr.uri);
                                }
                            }
                        }
                    }

                    writeAttributeWithPrefix(attr.prefix, attr.localpart,
                        attr.value);
                }
                fAttrNamespace = null;
                fAttributeCache.clear();
            }

            if (currentElement.isEmpty) {
                fElementStack.pop();
                fInternalNamespaceContext.popContext();
                fWriter.write(CLOSE_EMPTY_ELEMENT);
            } else {
                fWriter.write(CLOSE_START_TAG);
            }

            fStartTagOpened = false;
        } catch (IOException ex) {
            fStartTagOpened = false;
            throw new XMLStreamException(ex);
        }
    }

    /**
     * marks open of start tag and writes the same into the writer.
     */
    private void openStartTag() throws IOException {
        fStartTagOpened = true;
        fWriter.write(OPEN_START_TAG);
    }

    /**
     *
     * @param uri
     * @return
     */
    private void correctPrefix(QName attr, int type) {
        String tmpPrefix = null;
        String prefix;
        String uri;
        prefix = attr.prefix;
        uri = attr.uri;
        boolean isSpecialCaseURI = false;

        if (prefix == null || prefix.equals("")) {
            if (uri == null) {
                return;
            }

            if (prefix == XMLConstants.DEFAULT_NS_PREFIX && uri == XMLConstants.DEFAULT_NS_PREFIX)
                return;

            uri = fSymbolTable.addSymbol(uri);

            QName decl = null;

            for (int i = 0; i < fNamespaceDecls.size(); i++) {
                decl = (QName) fNamespaceDecls.get(i);

                if ((decl != null) && (decl.uri == attr.uri)) {
                    attr.prefix = decl.prefix;

                    return;
                }
            }

            tmpPrefix = fNamespaceContext.getPrefix(uri);

            if (tmpPrefix == XMLConstants.DEFAULT_NS_PREFIX) {
                if (type == XMLStreamConstants.START_ELEMENT) {
                    return;
                }
                else if (type == XMLStreamConstants.ATTRIBUTE) {
                    //the uri happens to be the same as that of the default namespace
                    tmpPrefix = getAttrPrefix(uri);
                    isSpecialCaseURI = true;
                }
            }

            if (tmpPrefix == null) {
                StringBuffer genPrefix = new StringBuffer("zdef");

                for (int i = 0; i < 1; i++) {
                    genPrefix.append(fPrefixGen.nextInt());
                }

                prefix = genPrefix.toString();
                prefix = fSymbolTable.addSymbol(prefix);
            } else {
                prefix = fSymbolTable.addSymbol(tmpPrefix);
            }

            if (tmpPrefix == null) {
                if (isSpecialCaseURI) {
                    addAttrNamespace(prefix, uri);
                } else {
                    QName qname = new QName();
                    qname.setValues(prefix, XMLConstants.XMLNS_ATTRIBUTE, null, uri);
                    fNamespaceDecls.add(qname);
                    fInternalNamespaceContext.declarePrefix(fSymbolTable.addSymbol(
                        prefix), uri);
                }
            }
        }

        attr.prefix = prefix;
    }

    /**
     * return the prefix if the attribute has an uri the same as that of the default namespace
     */
    private String getAttrPrefix(String uri) {
        if (fAttrNamespace != null) {
            return (String)fAttrNamespace.get(uri);
        }
        return null;
    }
    private void addAttrNamespace(String prefix, String uri) {
        if (fAttrNamespace == null) {
            fAttrNamespace = new HashMap();
        }
        fAttrNamespace.put(prefix, uri);
    }
    /**
     * @param uri
     * @return
     */
    private boolean isDefaultNamespace(String uri) {
        String defaultNamespace = fInternalNamespaceContext.getURI(DEFAULT_PREFIX);

        if (uri == defaultNamespace) {
            return true;
        }

        return false;
    }

    /**
     * @param prefix
     * @param uri
     * @return
     */
    private boolean checkUserNamespaceContext(String prefix, String uri) {
        if (fNamespaceContext.userContext != null) {
            String tmpURI = fNamespaceContext.userContext.getNamespaceURI(prefix);

            if ((tmpURI != null) && tmpURI.equals(uri)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Correct's namespaces  as per requirements of isReparisingNamespace property.
     */
    protected void repair() {
        Attribute attr = null;
        Attribute attr2 = null;
        ElementState currentElement = fElementStack.peek();
        removeDuplicateDecls();

        for(int i=0 ; i< fAttributeCache.size();i++){
            attr = (Attribute)fAttributeCache.get(i);
            if((attr.prefix != null && !attr.prefix.equals("")) || (attr.uri != null && !attr.uri.equals(""))) {
                correctPrefix(currentElement,attr);
            }
        }

        if (!isDeclared(currentElement)) {
            if ((currentElement.prefix != null) &&
                    (currentElement.uri != null)) {
                if ((!currentElement.prefix.equals("")) && (!currentElement.uri.equals(""))) {
                    fNamespaceDecls.add(currentElement);
                }
            }
        }

        for(int i=0 ; i< fAttributeCache.size();i++){
            attr = (Attribute)fAttributeCache.get(i);
            for(int j=i+1;j<fAttributeCache.size();j++){
                attr2 = (Attribute)fAttributeCache.get(j);
                if(!"".equals(attr.prefix)&& !"".equals(attr2.prefix)){
                    correctPrefix(attr,attr2);
                }
            }
        }

        repairNamespaceDecl(currentElement);

        int i = 0;

        for (i = 0; i < fAttributeCache.size(); i++) {
            attr = (Attribute) fAttributeCache.get(i);
            /* If 'attr' is an attribute and it is in no namespace(which means that prefix="", uri=""), attr's
               namespace should not be redinded. See [http://www.w3.org/TR/REC-xml-names/#defaulting].
             */
            if (attr.prefix != null && attr.prefix.equals("") && attr.uri != null && attr.uri.equals("")){
                repairNamespaceDecl(attr);
            }
        }

        QName qname = null;

        for (i = 0; i < fNamespaceDecls.size(); i++) {
            qname = (QName) fNamespaceDecls.get(i);

            if (qname != null) {
                fInternalNamespaceContext.declarePrefix(qname.prefix, qname.uri);
            }
        }

        for (i = 0; i < fAttributeCache.size(); i++) {
            attr = (Attribute) fAttributeCache.get(i);
            correctPrefix(attr, XMLStreamConstants.ATTRIBUTE);
        }
    }

    /*
     *If element and/or attribute names in the same start or empty-element tag
     *are bound to different namespace URIs and are using the same prefix then
     *the element or the first occurring attribute retains the original prefix
     *and the following attributes have their prefixes replaced with a new prefix
     *that is bound to the namespace URIs of those attributes.
     */
    void correctPrefix(QName attr1, QName attr2) {
        String tmpPrefix = null;
        QName decl = null;
        boolean done = false;

        checkForNull(attr1);
        checkForNull(attr2);

        if(attr1.prefix.equals(attr2.prefix) && !(attr1.uri.equals(attr2.uri))){

            tmpPrefix = fNamespaceContext.getPrefix(attr2.uri);

            if (tmpPrefix != null) {
                attr2.prefix = fSymbolTable.addSymbol(tmpPrefix);
            } else {
                decl = null;
                for(int n=0;n<fNamespaceDecls.size();n++){
                    decl = (QName)fNamespaceDecls.get(n);
                    if(decl != null && (decl.uri == attr2.uri)){
                        attr2.prefix = decl.prefix;

                        return;
                    }
                }

                //No namespace mapping found , so declare prefix.
                StringBuffer genPrefix = new StringBuffer("zdef");

                for (int k = 0; k < 1; k++) {
                    genPrefix.append(fPrefixGen.nextInt());
                }

                tmpPrefix = genPrefix.toString();
                tmpPrefix = fSymbolTable.addSymbol(tmpPrefix);
                attr2.prefix = tmpPrefix;

                QName qname = new QName();
                qname.setValues(tmpPrefix, XMLConstants.XMLNS_ATTRIBUTE, null,
                    attr2.uri);
                fNamespaceDecls.add(qname);
            }
        }
    }

    void checkForNull(QName attr) {
        if (attr.prefix == null) attr.prefix = XMLConstants.DEFAULT_NS_PREFIX;
        if (attr.uri == null) attr.uri = XMLConstants.DEFAULT_NS_PREFIX;
    }

    void removeDuplicateDecls(){
        QName decl1,decl2;
        for(int i =0;i<fNamespaceDecls.size();i++){
            decl1 = (QName)fNamespaceDecls.get(i);
            if(decl1!=null) {
                for(int j=i+1;j<fNamespaceDecls.size();j++){
                    decl2 = (QName)fNamespaceDecls.get(j);
                    // QName.equals relies on identity equality, so we can't use it,
                    // because prefixes aren't interned
                    if(decl2!=null && decl1.prefix.equals(decl2.prefix) && decl1.uri.equals(decl2.uri))
                        fNamespaceDecls.remove(j);
                }
            }
        }
    }

    /*
     *If an element or attribute name is bound to a prefix and there is a namespace
     *declaration that binds that prefix to a different URI then that namespace declaration
     *is either removed if the correct mapping is inherited from the parent context of that element,
     *or changed to the namespace URI of the element or attribute using that prefix.
     *
     */
    void repairNamespaceDecl(QName attr) {
        QName decl = null;
        String tmpURI;

        //check for null prefix.
        for (int j = 0; j < fNamespaceDecls.size(); j++) {
            decl = (QName) fNamespaceDecls.get(j);

            if (decl != null) {
                if ((attr.prefix != null) &&
                        (attr.prefix.equals(decl.prefix) &&
                        !(attr.uri.equals(decl.uri)))) {
                    tmpURI = fNamespaceContext.getNamespaceURI(attr.prefix);

                    //see if you need to add to symbole table.
                    if (tmpURI != null) {
                        if (tmpURI.equals(attr.uri)) {
                            fNamespaceDecls.set(j, null);
                        } else {
                            decl.uri = attr.uri;
                        }
                    }
                }
            }
        }
    }

    boolean isDeclared(QName attr) {
        QName decl = null;

        for (int n = 0; n < fNamespaceDecls.size(); n++) {
            decl = (QName) fNamespaceDecls.get(n);

            if ((attr.prefix != null) &&
                    ((attr.prefix == decl.prefix) && (decl.uri == attr.uri))) {
                return true;
            }
        }

        if (attr.uri != null) {
            if (fNamespaceContext.getPrefix(attr.uri) != null) {
                return true;
            }
        }

        return false;
    }

    /*
     * Start of Internal classes.
     *
     */
    protected class ElementStack {
        /** The stack data. */
        protected ElementState[] fElements;

        /** The size of the stack. */
        protected short fDepth;

        /** Default constructor. */
        public ElementStack() {
            fElements = new ElementState[10];

            for (int i = 0; i < fElements.length; i++) {
                fElements[i] = new ElementState();
            }
        }

        /**
         * Pushes an element on the stack.
         * <p>
         * <strong>Note: The QName values are copied into the
         * stack. In other words, the caller does <em>not orphan
         * the element to the stack. Also, the QName object returned
         * is <em>not orphaned to the caller. It should be
         * considered read-only.
         *
         * @param element The element to push onto the stack.
         *
         * @return Returns the actual QName object that stores the
         */
        public ElementState push(ElementState element) {
            if (fDepth == fElements.length) {
                ElementState[] array = new ElementState[fElements.length * 2];
                System.arraycopy(fElements, 0, array, 0, fDepth);
                fElements = array;

                for (int i = fDepth; i < fElements.length; i++) {
                    fElements[i] = new ElementState();
                }
            }

            fElements[fDepth].setValues(element);

            return fElements[fDepth++];
        }

        /**
         *
         * @param prefix
         * @param localpart
         * @param rawname
         * @param uri
         * @param isEmpty
         * @return
         */
        public ElementState push(String prefix, String localpart,
            String rawname, String uri, boolean isEmpty) {
            if (fDepth == fElements.length) {
                ElementState[] array = new ElementState[fElements.length * 2];
                System.arraycopy(fElements, 0, array, 0, fDepth);
                fElements = array;

                for (int i = fDepth; i < fElements.length; i++) {
                    fElements[i] = new ElementState();
                }
            }

            fElements[fDepth].setValues(prefix, localpart, rawname, uri, isEmpty);

            return fElements[fDepth++];
        }

        /**
         * Pops an element off of the stack by setting the values of
         * the specified QName.
         * <p>
         * <strong>Note: The object returned is not
         * orphaned to the caller. Therefore, the caller should consider
         * the object to be read-only.
         */
        public ElementState pop() {
            return fElements[--fDepth];
        }

        /** Clears the stack without throwing away existing QName objects. */
        public void clear() {
            fDepth = 0;
        }

        /**
         * This function is as a result of optimization done for endElement --
         * we dont need to set the value for every end element we encouter.
         * For Well formedness checks we can have the same QName object that was pushed.
         * the values will be set only if application need to know about the endElement
         * -- neeraj.bajaj@sun.com
         */
        public ElementState peek() {
            return fElements[fDepth - 1];
        }

        /**
         *
         * @return
         */
        public boolean empty() {
            return (fDepth > 0) ? false : true;
        }
    }

    /**
     * Maintains element state . localName for now.
     */
    class ElementState extends QName {
        public boolean isEmpty = false;

        public ElementState() {}

        public ElementState(String prefix, String localpart, String rawname,
            String uri) {
            super(prefix, localpart, rawname, uri);
        }

        public void setValues(String prefix, String localpart, String rawname,
            String uri, boolean isEmpty) {
            super.setValues(prefix, localpart, rawname, uri);
            this.isEmpty = isEmpty;
        }
    }

    /**
     * Attributes
     */
    class Attribute extends QName {
        String value;

        Attribute(String value) {
            super();
            this.value = value;
        }
    }

    /**
     * Implementation of NamespaceContext .
     *
     */
    class NamespaceContextImpl implements NamespaceContext {
        //root namespace context set by user.
        NamespaceContext userContext = null;

        //context built by the writer.
        NamespaceSupport internalContext = null;

        public String getNamespaceURI(String prefix) {
            String uri = null;

            if (prefix != null) {
                prefix = fSymbolTable.addSymbol(prefix);
            }

            if (internalContext != null) {
                uri = internalContext.getURI(prefix);

                if (uri != null) {
                    return uri;
                }
            }

            if (userContext != null) {
                uri = userContext.getNamespaceURI(prefix);

                return uri;
            }

            return null;
        }

        public String getPrefix(String uri) {
            String prefix = null;

            if (uri != null) {
                uri = fSymbolTable.addSymbol(uri);
            }

            if (internalContext != null) {
                prefix = internalContext.getPrefix(uri);

                if (prefix != null) {
                    return prefix;
                }
            }

            if (userContext != null) {
                return userContext.getPrefix(uri);
            }

            return null;
        }

        public java.util.Iterator getPrefixes(String uri) {
            Vector prefixes = null;
            Iterator itr = null;

            if (uri != null) {
                uri = fSymbolTable.addSymbol(uri);
            }

            if (userContext != null) {
                itr = userContext.getPrefixes(uri);
            }

            if (internalContext != null) {
                prefixes = internalContext.getPrefixes(uri);
            }

            if ((prefixes == null) && (itr != null)) {
                return itr;
            } else if ((prefixes != null) && (itr == null)) {
                return new ReadOnlyIterator(prefixes.iterator());
            } else if ((prefixes != null) && (itr != null)) {
                String ob = null;

                while (itr.hasNext()) {
                    ob = (String) itr.next();

                    if (ob != null) {
                        ob = fSymbolTable.addSymbol(ob);
                    }

                    if (!prefixes.contains(ob)) {
                        prefixes.add(ob);
                    }
                }

                return new ReadOnlyIterator(prefixes.iterator());
            }

            return fReadOnlyIterator;
        }
    }

    // -- Map Interface --------------------------------------------------

    public int size() {
        return 1;
    }

    public boolean isEmpty() {
        return false;
    }

    public boolean containsKey(Object key) {
        return key.equals(OUTPUTSTREAM_PROPERTY);
    }

    /**
     * Returns the value associated to an implementation-specific
     * property.
     */
    public Object get(Object key) {
        if (key.equals(OUTPUTSTREAM_PROPERTY)) {
            return fOutputStream;
        }
        return null;
    }

    public java.util.Set entrySet() {
        throw new UnsupportedOperationException();
    }

    /**
     * Overrides the method defined in AbstractMap which is
     * not completely implemented. Calling toString() in
     * AbstractMap would cause an unsupported exection to
     * be thrown.
     */
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    /**
     * Overrides the method defined in AbstractMap
     * This is required by the toString() method
     */
    public int hashCode() {
        return fElementStack.hashCode();
    }
    /**
     * Overrides the method defined in AbstractMap
     * This is required to satisfy the contract for hashCode.
     */
    public boolean equals(Object obj) {
        return (this == obj);
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java XMLStreamWriterImpl.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.