jaxp/src/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java
changeset 25834 aba3efbf4ec5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java	Tue Jul 29 20:52:36 2014 -0700
@@ -0,0 +1,1405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the  "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * $Id:  $
+ */
+
+package com.sun.org.apache.xml.internal.serializer.dom3;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Properties;
+
+import com.sun.org.apache.xml.internal.serializer.DOM3Serializer;
+import com.sun.org.apache.xml.internal.serializer.Encodings;
+import com.sun.org.apache.xml.internal.serializer.Serializer;
+import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;
+import com.sun.org.apache.xml.internal.serializer.SerializerFactory;
+import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
+import com.sun.org.apache.xml.internal.serializer.utils.Utils;
+import com.sun.org.apache.xml.internal.serializer.utils.SystemIDResolver;
+import org.w3c.dom.DOMConfiguration;
+import org.w3c.dom.DOMError;
+import org.w3c.dom.DOMErrorHandler;
+import org.w3c.dom.DOMException;
+import org.w3c.dom.DOMStringList;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.ls.LSException;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSSerializer;
+import org.w3c.dom.ls.LSSerializerFilter;
+
+
+/**
+ * Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer and
+ * org.w3c.dom.ls.DOMConfiguration.  Serialization is achieved by delegating
+ * serialization calls to <CODE>org.apache.xml.serializer.ToStream</CODE> or
+ * one of its derived classes depending on the serialization method, while walking
+ * the DOM in DOM3TreeWalker.
+ * @see <a href="http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html#LS-LSSerializer">org.w3c.dom.ls.LSSerializer</a>
+ * @see <a href="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMConfiguration">org.w3c.dom.DOMConfiguration</a>
+ *
+ * @version $Id:
+ *
+ * @xsl.usage internal
+ */
+final public class LSSerializerImpl implements DOMConfiguration, LSSerializer {
+
+    /** private data members */
+    private Serializer fXMLSerializer = null;
+
+    // Tracks DOMConfiguration features.
+    protected int fFeatures = 0;
+
+    // Common DOM serializer
+    private  DOM3Serializer fDOMSerializer = null;
+
+    // A filter set on the LSSerializer
+    private LSSerializerFilter fSerializerFilter = null;
+
+    // Stores the nodeArg parameter to speed up multiple writes of the same node.
+    private Node fVisitedNode = null;
+
+    // The end-of-line character sequence used in serialization.  "\n" is whats used on the web.
+    private String fEndOfLine = "\n";
+
+    // The DOMErrorhandler.
+    private DOMErrorHandler fDOMErrorHandler = null;
+
+    // The Configuration parameter to pass to the Underlying serilaizer.
+    private Properties fDOMConfigProperties = null;
+
+    // The encoding to use during serialization.
+    private String fEncoding;
+
+    // ************************************************************************
+    // DOM Level 3 DOM Configuration parameter names
+    // ************************************************************************
+    // Parameter canonical-form, true [optional] - NOT SUPPORTED
+    private final static int CANONICAL = 0x1 << 0;
+
+    // Parameter cdata-sections, true [required] (default)
+    private final static int CDATA = 0x1 << 1;
+
+    // Parameter check-character-normalization, true [optional] - NOT SUPPORTED
+    private final static int CHARNORMALIZE = 0x1 << 2;
+
+    // Parameter comments, true [required] (default)
+    private final static int COMMENTS = 0x1 << 3;
+
+    // Parameter datatype-normalization, true [optional] - NOT SUPPORTED
+    private final static int DTNORMALIZE = 0x1 << 4;
+
+    // Parameter element-content-whitespace, true [required] (default) - value - false [optional] NOT SUPPORTED
+    private final static int ELEM_CONTENT_WHITESPACE = 0x1 << 5;
+
+    // Parameter entities, true [required] (default)
+    private final static int ENTITIES = 0x1 << 6;
+
+    // Parameter infoset, true [required] (default), false has no effect --> True has no effect for the serializer
+    private final static int INFOSET = 0x1 << 7;
+
+    // Parameter namespaces, true [required] (default)
+    private final static int NAMESPACES = 0x1 << 8;
+
+    // Parameter namespace-declarations, true [required] (default)
+    private final static int NAMESPACEDECLS = 0x1 << 9;
+
+    // Parameter normalize-characters, true [optional] - NOT SUPPORTED
+    private final static int NORMALIZECHARS = 0x1 << 10;
+
+    // Parameter split-cdata-sections, true [required] (default)
+    private final static int SPLITCDATA = 0x1 << 11;
+
+    // Parameter validate, true [optional] - NOT SUPPORTED
+    private final static int VALIDATE = 0x1 << 12;
+
+    // Parameter validate-if-schema, true [optional] - NOT SUPPORTED
+    private final static int SCHEMAVALIDATE = 0x1 << 13;
+
+    // Parameter split-cdata-sections, true [required] (default)
+    private final static int WELLFORMED = 0x1 << 14;
+
+    // Parameter discard-default-content, true [required] (default)
+    // Not sure how this will be used in level 2 Documents
+    private final static int DISCARDDEFAULT = 0x1 << 15;
+
+    // Parameter format-pretty-print, true [optional]
+    private final static int PRETTY_PRINT = 0x1 << 16;
+
+    // Parameter ignore-unknown-character-denormalizations, true [required] (default)
+    // We currently do not support XML 1.1 character normalization
+    private final static int IGNORE_CHAR_DENORMALIZE = 0x1 << 17;
+
+    // Parameter discard-default-content, true [required] (default)
+    private final static int XMLDECL = 0x1 << 18;
+    // ************************************************************************
+
+    // Recognized parameters for which atleast one value can be set
+    private String fRecognizedParameters [] = {
+            DOMConstants.DOM_CANONICAL_FORM,
+            DOMConstants.DOM_CDATA_SECTIONS,
+            DOMConstants.DOM_CHECK_CHAR_NORMALIZATION,
+            DOMConstants.DOM_COMMENTS,
+            DOMConstants.DOM_DATATYPE_NORMALIZATION,
+            DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
+            DOMConstants.DOM_ENTITIES,
+            DOMConstants.DOM_INFOSET,
+            DOMConstants.DOM_NAMESPACES,
+            DOMConstants.DOM_NAMESPACE_DECLARATIONS,
+            //DOMConstants.DOM_NORMALIZE_CHARACTERS,
+            DOMConstants.DOM_SPLIT_CDATA,
+            DOMConstants.DOM_VALIDATE,
+            DOMConstants.DOM_VALIDATE_IF_SCHEMA,
+            DOMConstants.DOM_WELLFORMED,
+            DOMConstants.DOM_DISCARD_DEFAULT_CONTENT,
+            DOMConstants.DOM_FORMAT_PRETTY_PRINT,
+            DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS,
+            DOMConstants.DOM_XMLDECL,
+            DOMConstants.DOM_ERROR_HANDLER
+    };
+
+
+    /**
+     * Constructor:  Creates a LSSerializerImpl object.  The underlying
+     * XML 1.0 or XML 1.1 org.apache.xml.serializer.Serializer object is
+     * created and initialized the first time any of the write methods are
+     * invoked to serialize the Node.  Subsequent write methods on the same
+     * LSSerializerImpl object will use the previously created Serializer object.
+     */
+    public LSSerializerImpl () {
+        // set default parameters
+        fFeatures |= CDATA;
+        fFeatures |= COMMENTS;
+        fFeatures |= ELEM_CONTENT_WHITESPACE;
+        fFeatures |= ENTITIES;
+        fFeatures |= NAMESPACES;
+        fFeatures |= NAMESPACEDECLS;
+        fFeatures |= SPLITCDATA;
+        fFeatures |= WELLFORMED;
+        fFeatures |= DISCARDDEFAULT;
+        fFeatures |= XMLDECL;
+
+        // New OutputFormat properties
+        fDOMConfigProperties = new Properties();
+
+        // Initialize properties to be passed on the underlying serializer
+        initializeSerializerProps();
+
+        // Read output_xml.properties and System Properties to initialize properties
+        Properties  configProps = OutputPropertiesFactory.getDefaultMethodProperties("xml");
+
+        // change xml version from 1.0 to 1.1
+        //configProps.setProperty("version", "1.1");
+
+        // Get a serializer that seriailizes according to the properties,
+        // which in this case is to xml
+        fXMLSerializer = SerializerFactory.getSerializer(configProps);
+
+        // Initialize Serializer
+        fXMLSerializer.setOutputFormat(fDOMConfigProperties);
+    }
+
+    /**
+     * Initializes the underlying serializer's configuration depending on the
+     * default DOMConfiguration parameters. This method must be called before a
+     * node is to be serialized.
+     *
+     * @xsl.usage internal
+     */
+    public void initializeSerializerProps () {
+        // canonical-form
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_CANONICAL_FORM, DOMConstants.DOM3_DEFAULT_FALSE);
+
+        // cdata-sections
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // "check-character-normalization"
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_CHECK_CHAR_NORMALIZATION,
+                DOMConstants.DOM3_DEFAULT_FALSE);
+
+        // comments
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // datatype-normalization
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_DATATYPE_NORMALIZATION,
+                DOMConstants.DOM3_DEFAULT_FALSE);
+
+        // element-content-whitespace
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
+                DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // entities
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_TRUE);
+        // preserve entities
+        fDOMConfigProperties.setProperty(
+                OutputPropertiesFactory.S_KEY_ENTITIES, DOMConstants.S_XSL_VALUE_ENTITIES);
+
+        // error-handler
+        // Should we set our default ErrorHandler
+        /*
+         * if (fDOMConfig.getParameter(Constants.DOM_ERROR_HANDLER) != null) {
+         * fDOMErrorHandler =
+         * (DOMErrorHandler)fDOMConfig.getParameter(Constants.DOM_ERROR_HANDLER); }
+         */
+
+        // infoset
+        if ((fFeatures & INFOSET) != 0) {
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_DEFAULT_TRUE);
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_NAMESPACE_DECLARATIONS,
+                    DOMConstants.DOM3_DEFAULT_TRUE);
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_DEFAULT_TRUE);
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
+                    DOMConstants.DOM3_DEFAULT_TRUE);
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_DEFAULT_TRUE);
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_FALSE);
+            // preserve entities
+            fDOMConfigProperties.setProperty(
+                    OutputPropertiesFactory.S_KEY_ENTITIES, "");
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_CDATA_SECTIONS,
+                    DOMConstants.DOM3_DEFAULT_FALSE);
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_VALIDATE_IF_SCHEMA,
+                    DOMConstants.DOM3_DEFAULT_FALSE);
+            fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                    + DOMConstants.DOM_DATATYPE_NORMALIZATION,
+                    DOMConstants.DOM3_DEFAULT_FALSE);
+        }
+
+        // namespaces
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // namespace-declarations
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_NAMESPACE_DECLARATIONS,
+                DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // normalize-characters
+        /*
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_NORMALIZE_CHARACTERS,
+                DOMConstants.DOM3_DEFAULT_FALSE);
+        */
+
+        // split-cdata-sections
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // validate
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_VALIDATE, DOMConstants.DOM3_DEFAULT_FALSE);
+
+        // validate-if-schema
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_VALIDATE_IF_SCHEMA,
+                DOMConstants.DOM3_DEFAULT_FALSE);
+
+        // well-formed
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // pretty-print
+        fDOMConfigProperties.setProperty(
+                DOMConstants.S_XSL_OUTPUT_INDENT,
+                DOMConstants.DOM3_DEFAULT_FALSE);
+        fDOMConfigProperties.setProperty(
+                OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, Integer.toString(4));
+
+        //
+
+        // discard-default-content
+        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT,
+                DOMConstants.DOM3_DEFAULT_TRUE);
+
+        // xml-declaration
+        fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "no");
+
+    }
+
+    // ************************************************************************
+    // DOMConfiguraiton implementation
+    // ************************************************************************
+
+    /**
+     * Checks if setting a parameter to a specific value is supported.
+     *
+     * @see org.w3c.dom.DOMConfiguration#canSetParameter(java.lang.String, java.lang.Object)
+     * @since DOM Level 3
+     * @param name A String containing the DOMConfiguration parameter name.
+     * @param value An Object specifying the value of the corresponding parameter.
+     */
+    public boolean canSetParameter(String name, Object value) {
+        if (value instanceof Boolean){
+            if ( name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)){
+                // both values supported
+                return true;
+            }
+            else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
+                    // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
+                    ) {
+                // true is not supported
+                return !((Boolean)value).booleanValue();
+            }
+            else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
+                // false is not supported
+                return ((Boolean)value).booleanValue();
+            }
+        }
+        else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER) &&
+                value == null || value instanceof DOMErrorHandler){
+            return true;
+        }
+        return false;
+    }
+    /**
+     * This method returns the value of a parameter if known.
+     *
+     * @see org.w3c.dom.DOMConfiguration#getParameter(java.lang.String)
+     *
+     * @param name A String containing the DOMConfiguration parameter name
+     *             whose value is to be returned.
+     * @return Object The value of the parameter if known.
+     */
+    public Object getParameter(String name) throws DOMException {
+
+        if(name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)){
+                      return null;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)) {
+            return ((fFeatures & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)) {
+            return ((fFeatures & CDATA) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)) {
+            return ((fFeatures & ENTITIES) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)) {
+            return ((fFeatures & NAMESPACES) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)) {
+            return ((fFeatures & NAMESPACEDECLS) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)) {
+            return ((fFeatures & SPLITCDATA) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)) {
+            return ((fFeatures & WELLFORMED) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        }  else if (name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)) {
+            return ((fFeatures & DISCARDDEFAULT) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
+            return ((fFeatures & PRETTY_PRINT) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)) {
+            return ((fFeatures & XMLDECL) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
+            return ((fFeatures & ELEM_CONTENT_WHITESPACE) != 0) ? Boolean.TRUE : Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
+            return Boolean.TRUE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
+                || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
+                || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
+                // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
+                || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
+                || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
+            return Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)){
+            if ((fFeatures & ENTITIES) == 0 &&
+                    (fFeatures & CDATA) == 0 &&
+                    (fFeatures & ELEM_CONTENT_WHITESPACE) != 0 &&
+                    (fFeatures & NAMESPACES) != 0 &&
+                    (fFeatures & NAMESPACEDECLS) != 0 &&
+                    (fFeatures & WELLFORMED) != 0 &&
+                    (fFeatures & COMMENTS) != 0) {
+                return Boolean.TRUE;
+            }
+            return Boolean.FALSE;
+        } else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER)) {
+            return fDOMErrorHandler;
+        } else if (
+                name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION)
+                || name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)) {
+            return null;
+        } else {
+            // Here we have to add the Xalan specific DOM Message Formatter
+            String msg = Utils.messages.createMessage(
+                    MsgKey.ER_FEATURE_NOT_FOUND,
+                    new Object[] { name });
+            throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
+        }
+    }
+
+    /**
+     * This method returns a of the parameters supported by this DOMConfiguration object
+     * and for which at least one value can be set by the application
+     *
+     * @see org.w3c.dom.DOMConfiguration#getParameterNames()
+     *
+     * @return DOMStringList A list of DOMConfiguration parameters recognized
+     *                       by the serializer
+     */
+    public DOMStringList getParameterNames() {
+        return new DOMStringListImpl(fRecognizedParameters);
+    }
+
+    /**
+     * This method sets the value of the named parameter.
+     *
+     * @see org.w3c.dom.DOMConfiguration#setParameter(java.lang.String, java.lang.Object)
+     *
+     * @param name A String containing the DOMConfiguration parameter name.
+     * @param value An Object contaiing the parameters value to set.
+     */
+    public void setParameter(String name, Object value) throws DOMException {
+        // If the value is a boolean
+        if (value instanceof Boolean) {
+            boolean state = ((Boolean) value).booleanValue();
+
+            if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)) {
+                fFeatures = state ? fFeatures | COMMENTS : fFeatures
+                        & ~COMMENTS;
+                // comments
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)) {
+                fFeatures =  state ? fFeatures | CDATA : fFeatures
+                        & ~CDATA;
+                // cdata-sections
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)) {
+                fFeatures = state ? fFeatures | ENTITIES : fFeatures
+                        & ~ENTITIES;
+                // entities
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_TRUE);
+                    fDOMConfigProperties.setProperty(
+                            OutputPropertiesFactory.S_KEY_ENTITIES, DOMConstants.S_XSL_VALUE_ENTITIES);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)) {
+                fFeatures = state ? fFeatures | NAMESPACES : fFeatures
+                        & ~NAMESPACES;
+                // namespaces
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name
+                    .equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)) {
+                fFeatures = state ? fFeatures | NAMESPACEDECLS
+                        : fFeatures & ~NAMESPACEDECLS;
+                // namespace-declarations
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)) {
+                fFeatures = state ? fFeatures | SPLITCDATA : fFeatures
+                        & ~SPLITCDATA;
+                // split-cdata-sections
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)) {
+                fFeatures = state ? fFeatures | WELLFORMED : fFeatures
+                        & ~WELLFORMED;
+                // well-formed
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name
+                    .equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)) {
+                fFeatures = state ? fFeatures | DISCARDDEFAULT
+                        : fFeatures & ~DISCARDDEFAULT;
+                // discard-default-content
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
+                fFeatures = state ? fFeatures | PRETTY_PRINT : fFeatures
+                        & ~PRETTY_PRINT;
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_INDENT,DOMConstants.DOM3_EXPLICIT_TRUE);
+                    fDOMConfigProperties.setProperty(OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, Integer.toString(4));
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_INDENT,DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)) {
+                fFeatures = state ? fFeatures | XMLDECL : fFeatures
+                        & ~XMLDECL;
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "no");
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "yes");
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
+                fFeatures = state ? fFeatures | ELEM_CONTENT_WHITESPACE : fFeatures
+                        & ~ELEM_CONTENT_WHITESPACE;
+                // element-content-whitespace
+                if (state) {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_TRUE);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_FALSE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
+                // false is not supported
+                if (!state) {
+                    // Here we have to add the Xalan specific DOM Message Formatter
+                    String msg = Utils.messages.createMessage(
+                            MsgKey.ER_FEATURE_NOT_SUPPORTED,
+                            new Object[] { name });
+                    throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
+                } else {
+                    fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                            + DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
+                    || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
+                    // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
+                    ) {
+                // true is not supported
+                if (state) {
+                    String msg = Utils.messages.createMessage(
+                            MsgKey.ER_FEATURE_NOT_SUPPORTED,
+                            new Object[] { name });
+                    throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
+                } else {
+                    if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)) {
+                        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                                + DOMConstants.DOM_CANONICAL_FORM, DOMConstants.DOM3_EXPLICIT_FALSE);
+                    } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
+                        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                                + DOMConstants.DOM_VALIDATE_IF_SCHEMA, DOMConstants.DOM3_EXPLICIT_FALSE);
+                    } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)) {
+                        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                                + DOMConstants.DOM_VALIDATE, DOMConstants.DOM3_EXPLICIT_FALSE);
+                    } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
+                        fDOMConfigProperties.setProperty(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION
+                                + DOMConstants.DOM_CHECK_CHAR_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
+                    } else if (name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)) {
+                        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                                + DOMConstants.DOM_DATATYPE_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
+                    } /* else if (name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)) {
+                        fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                                + DOMConstants.DOM_NORMALIZE_CHARACTERS, DOMConstants.DOM3_EXPLICIT_FALSE);
+                    } */
+                }
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)) {
+                if (state) {
+                    fFeatures &= ~ENTITIES;
+                    fFeatures &= ~CDATA;
+                    fFeatures &= ~SCHEMAVALIDATE;
+                    fFeatures &= ~DTNORMALIZE;
+                    fFeatures |= NAMESPACES;
+                    fFeatures |= NAMESPACEDECLS;
+                    fFeatures |= WELLFORMED;
+                    fFeatures |= ELEM_CONTENT_WHITESPACE;
+                    fFeatures |= COMMENTS;
+                }
+
+                // infoset
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_TRUE);
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_TRUE);
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_TRUE);
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_TRUE);
+
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
+                fDOMConfigProperties.setProperty(
+                        OutputPropertiesFactory.S_KEY_ENTITIES, "");
+
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_VALIDATE_IF_SCHEMA, DOMConstants.DOM3_EXPLICIT_FALSE);
+                fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
+                        + DOMConstants.DOM_DATATYPE_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
+            } else if (name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)) {
+                String msg = Utils.messages.createMessage(
+                    MsgKey.ER_FEATURE_NOT_SUPPORTED,
+                    new Object[] { name });
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
+            } else {
+                // Setting this to false has no effect
+            }
+        } // If the parameter value is not a boolean
+        else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER)) {
+            if (value == null || value instanceof DOMErrorHandler) {
+                fDOMErrorHandler = (DOMErrorHandler)value;
+            } else {
+                String msg = Utils.messages.createMessage(
+                        MsgKey.ER_TYPE_MISMATCH_ERR,
+                        new Object[] { name });
+                throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
+            }
+        } else if (
+                name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION)
+                || name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)
+                || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
+                && value != null) {
+            String msg = Utils.messages.createMessage(
+                    MsgKey.ER_FEATURE_NOT_SUPPORTED,
+                    new Object[] { name });
+            throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
+        } else {
+            String msg = Utils.messages.createMessage(
+                    MsgKey.ER_FEATURE_NOT_FOUND,
+                    new Object[] { name });
+            throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
+        }
+    }
+    // ************************************************************************
+
+
+    // ************************************************************************
+    // DOMConfiguraiton implementation
+    // ************************************************************************
+
+    /**
+     * Returns the DOMConfiguration of the LSSerializer.
+     *
+     * @see org.w3c.dom.ls.LSSerializer#getDomConfig()
+     * @since DOM Level 3
+     * @return A DOMConfiguration object.
+     */
+    public DOMConfiguration getDomConfig() {
+        return (DOMConfiguration)this;
+    }
+
+    /**
+     * Returns the DOMConfiguration of the LSSerializer.
+     *
+     * @see org.w3c.dom.ls.LSSerializer#getFilter()
+     * @since DOM Level 3
+     * @return A LSSerializerFilter object.
+     */
+    public LSSerializerFilter getFilter() {
+        return fSerializerFilter;
+    }
+
+    /**
+     * Returns the End-Of-Line sequence of characters to be used in the XML
+     * being serialized.  If none is set a default "\n" is returned.
+     *
+     * @see org.w3c.dom.ls.LSSerializer#getNewLine()
+     * @since DOM Level 3
+     * @return A String containing the end-of-line character sequence  used in
+     * serialization.
+     */
+    public String getNewLine() {
+        return fEndOfLine;
+    }
+
+    /**
+     * Set a LSSerilizerFilter on the LSSerializer.  When set, the filter is
+     * called before each node is serialized which depending on its implemention
+     * determines if the node is to be serialized or not.
+     *
+     * @see org.w3c.dom.ls.LSSerializer#setFilter
+     * @since DOM Level 3
+     * @param filter A LSSerializerFilter to be applied to the stream to serialize.
+     */
+    public void setFilter(LSSerializerFilter filter) {
+        fSerializerFilter = filter;
+    }
+
+    /**
+     * Sets the End-Of-Line sequence of characters to be used in the XML
+     * being serialized.  Setting this attribute to null will reset its
+     * value to the default value i.e. "\n".
+     *
+     * @see org.w3c.dom.ls.LSSerializer#setNewLine
+     * @since DOM Level 3
+     * @param newLine a String that is the end-of-line character sequence to be used in
+     * serialization.
+     */
+    public void setNewLine(String newLine) {
+        fEndOfLine = newLine !=null? newLine: fEndOfLine;
+    }
+
+    /**
+     * Serializes the specified node to the specified LSOutput and returns true if the Node
+     * was successfully serialized.
+     *
+     * @see org.w3c.dom.ls.LSSerializer#write(org.w3c.dom.Node, org.w3c.dom.ls.LSOutput)
+     * @since DOM Level 3
+     * @param nodeArg The Node to serialize.
+     * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
+     * LSSerializer was unable to serialize the node.
+     *
+     */
+    public boolean write(Node nodeArg, LSOutput destination) throws LSException {
+        // If the destination is null
+        if (destination == null) {
+            String msg = Utils.messages
+            .createMessage(
+                    MsgKey.ER_NO_OUTPUT_SPECIFIED,
+                    null);
+            if (fDOMErrorHandler != null) {
+                fDOMErrorHandler.handleError(new DOMErrorImpl(
+                        DOMError.SEVERITY_FATAL_ERROR, msg,
+                        MsgKey.ER_NO_OUTPUT_SPECIFIED));
+            }
+            throw new LSException(LSException.SERIALIZE_ERR, msg);
+        }
+
+        // If nodeArg is null, return false.  Should we throw and LSException instead?
+        if (nodeArg == null ) {
+            return false;
+        }
+
+        // Obtain a reference to the serializer to use
+        // Serializer serializer = getXMLSerializer(xmlVersion);
+        Serializer serializer = fXMLSerializer;
+        serializer.reset();
+
+        // If the node has not been seen
+        if ( nodeArg != fVisitedNode) {
+            // Determine the XML Document version of the Node
+            String xmlVersion = getXMLVersion(nodeArg);
+
+            // Determine the encoding: 1.LSOutput.encoding, 2.Document.inputEncoding, 3.Document.xmlEncoding.
+            fEncoding = destination.getEncoding();
+            if (fEncoding == null ) {
+                fEncoding = getInputEncoding(nodeArg);
+                fEncoding = fEncoding != null ? fEncoding : getXMLEncoding(nodeArg) == null? "UTF-8": getXMLEncoding(nodeArg);
+            }
+
+            // If the encoding is not recognized throw an exception.
+            // Note: The serializer defaults to UTF-8 when created
+            if (!Encodings.isRecognizedEncoding(fEncoding)) {
+                String msg = Utils.messages
+                .createMessage(
+                        MsgKey.ER_UNSUPPORTED_ENCODING,
+                        null);
+                if (fDOMErrorHandler != null) {
+                    fDOMErrorHandler.handleError(new DOMErrorImpl(
+                            DOMError.SEVERITY_FATAL_ERROR, msg,
+                            MsgKey.ER_UNSUPPORTED_ENCODING));
+                }
+                throw new LSException(LSException.SERIALIZE_ERR, msg);
+            }
+
+            serializer.getOutputFormat().setProperty("version", xmlVersion);
+
+            // Set the output encoding and xml version properties
+            fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
+            fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, fEncoding);
+
+            // If the node to be serialized is not a Document, Element, or Entity
+            // node
+            // then the XML declaration, or text declaration, should be never be
+            // serialized.
+            if ( (nodeArg.getNodeType() != Node.DOCUMENT_NODE
+                    || nodeArg.getNodeType() != Node.ELEMENT_NODE
+                    || nodeArg.getNodeType() != Node.ENTITY_NODE)
+                    && ((fFeatures & XMLDECL) != 0)) {
+                fDOMConfigProperties.setProperty(
+                        DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
+                        DOMConstants.DOM3_DEFAULT_FALSE);
+            }
+
+            fVisitedNode = nodeArg;
+        }
+
+        // Update the serializer properties
+        fXMLSerializer.setOutputFormat(fDOMConfigProperties);
+
+        //
+        try {
+
+            // The LSSerializer will use the LSOutput object to determine
+            // where to serialize the output to in the following order the
+            // first one that is not null and not an empty string will be
+            // used: 1.LSOutput.characterStream, 2.LSOutput.byteStream,
+            // 3. LSOutput.systemId
+            // 1.LSOutput.characterStream
+            Writer writer = destination.getCharacterStream();
+            if (writer == null ) {
+
+                // 2.LSOutput.byteStream
+                OutputStream outputStream = destination.getByteStream();
+                if ( outputStream == null) {
+
+                    // 3. LSOutput.systemId
+                    String uri = destination.getSystemId();
+                    if (uri == null) {
+                        String msg = Utils.messages
+                        .createMessage(
+                                MsgKey.ER_NO_OUTPUT_SPECIFIED,
+                                null);
+                        if (fDOMErrorHandler != null) {
+                            fDOMErrorHandler.handleError(new DOMErrorImpl(
+                                    DOMError.SEVERITY_FATAL_ERROR, msg,
+                                    MsgKey.ER_NO_OUTPUT_SPECIFIED));
+                        }
+                        throw new LSException(LSException.SERIALIZE_ERR, msg);
+
+                    } else {
+                        // Expand the System Id and obtain an absolute URI for it.
+                        String absoluteURI = SystemIDResolver.getAbsoluteURI(uri);
+
+                        URL url = new URL(absoluteURI);
+                        OutputStream urlOutStream = null;
+                        String protocol = url.getProtocol();
+                        String host = url.getHost();
+
+                        // For file protocols, there is no need to use a URL to get its
+                        // corresponding OutputStream
+
+                        // Scheme names consist of a sequence of characters. The lower case
+                        // letters "a"--"z", digits, and the characters plus ("+"), period
+                        // ("."), and hyphen ("-") are allowed. For resiliency, programs
+                        // interpreting URLs should treat upper case letters as equivalent to
+                        // lower case in scheme names (e.g., allow "HTTP" as well as "http").
+                        if (protocol.equalsIgnoreCase("file")
+                                && (host == null || host.length() == 0 || host.equals("localhost"))) {
+                            // do we also need to check for host.equals(hostname)
+                            urlOutStream = new FileOutputStream(new File(url.getPath()));
+
+                        } else {
+                            // This should support URL's whose schemes are mentioned in
+                            // RFC1738 other than file
+
+                            URLConnection urlCon = url.openConnection();
+                            urlCon.setDoInput(false);
+                            urlCon.setDoOutput(true);
+                            urlCon.setUseCaches(false);
+                            urlCon.setAllowUserInteraction(false);
+
+                            // When writing to a HTTP URI, a HTTP PUT is performed.
+                            if (urlCon instanceof HttpURLConnection) {
+                                HttpURLConnection httpCon = (HttpURLConnection) urlCon;
+                                httpCon.setRequestMethod("PUT");
+                            }
+                            urlOutStream = urlCon.getOutputStream();
+                        }
+                        // set the OutputStream to that obtained from the systemId
+                        serializer.setWriter(new OutputStreamWriter(urlOutStream));
+                    }
+                } else {
+                    // 2.LSOutput.byteStream
+                    serializer.setWriter(new OutputStreamWriter(outputStream, fEncoding));
+                }
+            } else {
+                // 1.LSOutput.characterStream
+                serializer.setWriter(writer);
+            }
+
+            // The associated media type by default is set to text/xml on
+            // org.apache.xml.serializer.SerializerBase.
+
+            // Get a reference to the serializer then lets you serilize a DOM
+            // Use this hack till Xalan support JAXP1.3
+            if (fDOMSerializer == null) {
+               fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
+            }
+
+            // Set the error handler on the DOM3Serializer interface implementation
+            if (fDOMErrorHandler != null) {
+                fDOMSerializer.setErrorHandler(fDOMErrorHandler);
+            }
+
+            // Set the filter on the DOM3Serializer interface implementation
+            if (fSerializerFilter != null) {
+                fDOMSerializer.setNodeFilter(fSerializerFilter);
+            }
+
+            // Set the NewLine character to be used
+            fDOMSerializer.setNewLine(fEndOfLine);
+
+            // Serializer your DOM, where node is an org.w3c.dom.Node
+            // Assuming that Xalan's serializer can serialize any type of DOM node
+            fDOMSerializer.serializeDOM3(nodeArg);
+
+        } catch( UnsupportedEncodingException ue) {
+
+            String msg = Utils.messages
+            .createMessage(
+                    MsgKey.ER_UNSUPPORTED_ENCODING,
+                    null);
+            if (fDOMErrorHandler != null) {
+                fDOMErrorHandler.handleError(new DOMErrorImpl(
+                        DOMError.SEVERITY_FATAL_ERROR, msg,
+                        MsgKey.ER_UNSUPPORTED_ENCODING, ue));
+            }
+            throw new LSException(LSException.SERIALIZE_ERR, ue.getMessage());
+        } catch (LSException lse) {
+            // Rethrow LSException.
+            throw lse;
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+            throw new LSException(LSException.SERIALIZE_ERR, e!=null?e.getMessage():"NULL Exception") ;
+        }  catch (Exception e) {
+            if (fDOMErrorHandler != null) {
+                fDOMErrorHandler.handleError(new DOMErrorImpl(
+                        DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
+                        null, e));
+            }
+            e.printStackTrace();
+            throw new LSException(LSException.SERIALIZE_ERR, e.toString());
+        }
+        return true;
+    }
+
+    /**
+     * Serializes the specified node and returns a String with the serialized
+     * data to the caller.
+     *
+     * @see org.w3c.dom.ls.LSSerializer#writeToString(org.w3c.dom.Node)
+     * @since DOM Level 3
+     * @param nodeArg The Node to serialize.
+     * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
+     * LSSerializer was unable to serialize the node.
+     *
+     */
+    public String writeToString(Node nodeArg) throws DOMException, LSException {
+        // return null is nodeArg is null.  Should an Exception be thrown instead?
+        if (nodeArg == null) {
+            return null;
+        }
+
+        // Should we reset the serializer configuration before each write operation?
+        // Obtain a reference to the serializer to use
+        Serializer serializer = fXMLSerializer;
+        serializer.reset();
+
+        if (nodeArg != fVisitedNode){
+            // Determine the XML Document version of the Node
+            String xmlVersion = getXMLVersion(nodeArg);
+
+            serializer.getOutputFormat().setProperty("version", xmlVersion);
+
+            // Set the output encoding and xml version properties
+            fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
+            fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, "UTF-16");
+
+            // If the node to be serialized is not a Document, Element, or Entity
+            // node
+            // then the XML declaration, or text declaration, should be never be
+            // serialized.
+            if  ((nodeArg.getNodeType() != Node.DOCUMENT_NODE
+                    || nodeArg.getNodeType() != Node.ELEMENT_NODE
+                    || nodeArg.getNodeType() != Node.ENTITY_NODE)
+                    && ((fFeatures & XMLDECL) != 0)) {
+                fDOMConfigProperties.setProperty(
+                        DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
+                        DOMConstants.DOM3_DEFAULT_FALSE);
+            }
+
+            fVisitedNode = nodeArg;
+        }
+        // Update the serializer properties
+        fXMLSerializer.setOutputFormat(fDOMConfigProperties);
+
+        // StringWriter to Output to
+        StringWriter output = new StringWriter();
+
+        //
+        try {
+
+            // Set the Serializer's Writer to a StringWriter
+            serializer.setWriter(output);
+
+            // Get a reference to the serializer then lets you serilize a DOM
+            // Use this hack till Xalan support JAXP1.3
+            if (fDOMSerializer == null) {
+                fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
+            }
+
+            // Set the error handler on the DOM3Serializer interface implementation
+            if (fDOMErrorHandler != null) {
+                fDOMSerializer.setErrorHandler(fDOMErrorHandler);
+            }
+
+            // Set the filter on the DOM3Serializer interface implementation
+            if (fSerializerFilter != null) {
+                fDOMSerializer.setNodeFilter(fSerializerFilter);
+            }
+
+            // Set the NewLine character to be used
+            fDOMSerializer.setNewLine(fEndOfLine);
+
+            // Serializer your DOM, where node is an org.w3c.dom.Node
+            fDOMSerializer.serializeDOM3(nodeArg);
+        } catch (LSException lse) {
+            // Rethrow LSException.
+            throw lse;
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+            throw new LSException(LSException.SERIALIZE_ERR, e.toString());
+        }  catch (Exception e) {
+            if (fDOMErrorHandler != null) {
+                fDOMErrorHandler.handleError(new DOMErrorImpl(
+                        DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
+                        null, e));
+            }
+            e.printStackTrace();
+            throw new LSException(LSException.SERIALIZE_ERR, e.toString());
+        }
+
+        // return the serialized string
+        return output.toString();
+    }
+
+    /**
+     * Serializes the specified node to the specified URI and returns true if the Node
+     * was successfully serialized.
+     *
+     * @see org.w3c.dom.ls.LSSerializer#writeToURI(org.w3c.dom.Node, String)
+     * @since DOM Level 3
+     * @param nodeArg The Node to serialize.
+     * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
+     * LSSerializer was unable to serialize the node.
+     *
+     */
+    public boolean writeToURI(Node nodeArg, String uri) throws LSException {
+        // If nodeArg is null, return false.  Should we throw and LSException instead?
+        if (nodeArg == null ) {
+            return false;
+        }
+
+        // Obtain a reference to the serializer to use
+        Serializer serializer = fXMLSerializer;
+        serializer.reset();
+
+        if (nodeArg != fVisitedNode) {
+            // Determine the XML Document version of the Node
+            String xmlVersion = getXMLVersion(nodeArg);
+
+            // Determine the encoding: 1.LSOutput.encoding,
+            // 2.Document.inputEncoding, 3.Document.xmlEncoding.
+            fEncoding = getInputEncoding(nodeArg);
+            if (fEncoding == null ) {
+                fEncoding = fEncoding != null ? fEncoding : getXMLEncoding(nodeArg) == null? "UTF-8": getXMLEncoding(nodeArg);
+            }
+
+            serializer.getOutputFormat().setProperty("version", xmlVersion);
+
+            // Set the output encoding and xml version properties
+            fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
+            fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, fEncoding);
+
+            // If the node to be serialized is not a Document, Element, or Entity
+            // node
+            // then the XML declaration, or text declaration, should be never be
+            // serialized.
+            if ( (nodeArg.getNodeType() != Node.DOCUMENT_NODE
+                    || nodeArg.getNodeType() != Node.ELEMENT_NODE
+                    || nodeArg.getNodeType() != Node.ENTITY_NODE)
+                    && ((fFeatures & XMLDECL) != 0))  {
+                fDOMConfigProperties.setProperty(
+                        DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
+                        DOMConstants.DOM3_DEFAULT_FALSE);
+            }
+
+            fVisitedNode = nodeArg;
+        }
+
+        // Update the serializer properties
+        fXMLSerializer.setOutputFormat(fDOMConfigProperties);
+
+        //
+        try {
+            // If the specified encoding is not supported an
+            // "unsupported-encoding" fatal error is raised. ??
+            if (uri == null) {
+                String msg = Utils.messages.createMessage(
+                        MsgKey.ER_NO_OUTPUT_SPECIFIED, null);
+                if (fDOMErrorHandler != null) {
+                    fDOMErrorHandler.handleError(new DOMErrorImpl(
+                            DOMError.SEVERITY_FATAL_ERROR, msg,
+                            MsgKey.ER_NO_OUTPUT_SPECIFIED));
+                }
+                throw new LSException(LSException.SERIALIZE_ERR, msg);
+
+            } else {
+                // REVISIT: Can this be used to get an absolute expanded URI
+                String absoluteURI = SystemIDResolver.getAbsoluteURI(uri);
+
+                URL url = new URL(absoluteURI);
+                OutputStream urlOutStream = null;
+                String protocol = url.getProtocol();
+                String host = url.getHost();
+
+                // For file protocols, there is no need to use a URL to get its
+                // corresponding OutputStream
+
+                // Scheme names consist of a sequence of characters. The lower
+                // case letters "a"--"z", digits, and the characters plus ("+"),
+                // period ("."), and hyphen ("-") are allowed. For resiliency,
+                // programs interpreting URLs should treat upper case letters as
+                // equivalent to lower case in scheme names
+                // (e.g., allow "HTTP" as well as "http").
+                if (protocol.equalsIgnoreCase("file")
+                        && (host == null || host.length() == 0 || host
+                                .equals("localhost"))) {
+                    // do we also need to check for host.equals(hostname)
+                    urlOutStream = new FileOutputStream(new File(url.getPath()));
+
+                } else {
+                    // This should support URL's whose schemes are mentioned in
+                    // RFC1738 other than file
+
+                    URLConnection urlCon = url.openConnection();
+                    urlCon.setDoInput(false);
+                    urlCon.setDoOutput(true);
+                    urlCon.setUseCaches(false);
+                    urlCon.setAllowUserInteraction(false);
+
+                    // When writing to a HTTP URI, a HTTP PUT is performed.
+                    if (urlCon instanceof HttpURLConnection) {
+                        HttpURLConnection httpCon = (HttpURLConnection) urlCon;
+                        httpCon.setRequestMethod("PUT");
+                    }
+                    urlOutStream = urlCon.getOutputStream();
+                }
+                // set the OutputStream to that obtained from the systemId
+                serializer.setWriter(new OutputStreamWriter(urlOutStream, fEncoding));
+            }
+
+            // Get a reference to the serializer then lets you serilize a DOM
+            // Use this hack till Xalan support JAXP1.3
+            if (fDOMSerializer == null) {
+                fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
+            }
+
+            // Set the error handler on the DOM3Serializer interface implementation
+            if (fDOMErrorHandler != null) {
+                fDOMSerializer.setErrorHandler(fDOMErrorHandler);
+            }
+
+            // Set the filter on the DOM3Serializer interface implementation
+            if (fSerializerFilter != null) {
+                fDOMSerializer.setNodeFilter(fSerializerFilter);
+            }
+
+            // Set the NewLine character to be used
+            fDOMSerializer.setNewLine(fEndOfLine);
+
+            // Serializer your DOM, where node is an org.w3c.dom.Node
+            // Assuming that Xalan's serializer can serialize any type of DOM
+            // node
+            fDOMSerializer.serializeDOM3(nodeArg);
+
+        } catch (LSException lse) {
+            // Rethrow LSException.
+            throw lse;
+        } catch (RuntimeException e) {
+            e.printStackTrace();
+            throw new LSException(LSException.SERIALIZE_ERR, e.toString());
+        }  catch (Exception e) {
+            if (fDOMErrorHandler != null) {
+                fDOMErrorHandler.handleError(new DOMErrorImpl(
+                        DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
+                        null, e));
+            }
+            e.printStackTrace();
+            throw new LSException(LSException.SERIALIZE_ERR, e.toString());
+        }
+
+        return true;
+    }
+    // ************************************************************************
+
+
+    // ************************************************************************
+    // Implementaion methods
+    // ************************************************************************
+
+    /**
+     * Determines the XML Version of the Document Node to serialize.  If the Document Node
+     * is not a DOM Level 3 Node, then the default version returned is 1.0.
+     *
+     * @param  nodeArg The Node to serialize
+     * @return A String containing the version pseudo-attribute of the XMLDecl.
+     * @throws Throwable if the DOM implementation does not implement Document.getXmlVersion()
+     */
+    //protected String getXMLVersion(Node nodeArg) throws Throwable {
+    protected String getXMLVersion(Node nodeArg) {
+        Document doc = null;
+
+        // Determine the XML Version of the document
+        if (nodeArg != null) {
+            if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
+                // The Document node is the Node argument
+                doc = (Document)nodeArg;
+            } else {
+                // The Document node is the Node argument's ownerDocument
+                doc = nodeArg.getOwnerDocument();
+            }
+
+            // Determine the DOM Version.
+            if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
+                try {
+                    return doc.getXmlVersion();
+                } catch (AbstractMethodError e) {
+                    //ignore, impl does not support the method
+                }
+            }
+        }
+        // The version will be treated as "1.0" which may result in
+        // an ill-formed document being serialized.
+        // If nodeArg does not have an ownerDocument, treat this as XML 1.0
+        return "1.0";
+    }
+
+    /**
+     * Determines the XML Encoding of the Document Node to serialize.  If the Document Node
+     * is not a DOM Level 3 Node, then the default encoding "UTF-8" is returned.
+     *
+     * @param  nodeArg The Node to serialize
+     * @return A String containing the encoding pseudo-attribute of the XMLDecl.
+     * @throws Throwable if the DOM implementation does not implement Document.getXmlEncoding()
+     */
+    protected String getXMLEncoding(Node nodeArg) {
+        Document doc = null;
+
+        // Determine the XML Encoding of the document
+        if (nodeArg != null) {
+            if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
+                // The Document node is the Node argument
+                doc = (Document)nodeArg;
+            } else {
+                // The Document node is the Node argument's ownerDocument
+                doc = nodeArg.getOwnerDocument();
+            }
+
+            // Determine the XML Version.
+            if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
+                return doc.getXmlEncoding();
+            }
+        }
+        // The default encoding is UTF-8 except for the writeToString method
+        return "UTF-8";
+    }
+
+    /**
+     * Determines the Input Encoding of the Document Node to serialize.  If the Document Node
+     * is not a DOM Level 3 Node, then null is returned.
+     *
+     * @param  nodeArg The Node to serialize
+     * @return A String containing the input encoding.
+     */
+    protected String getInputEncoding(Node nodeArg)  {
+        Document doc = null;
+
+        // Determine the Input Encoding of the document
+        if (nodeArg != null) {
+            if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
+                // The Document node is the Node argument
+                doc = (Document)nodeArg;
+            } else {
+                // The Document node is the Node argument's ownerDocument
+                doc = nodeArg.getOwnerDocument();
+            }
+
+            // Determine the DOM Version.
+            if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
+                return doc.getInputEncoding();
+            }
+        }
+        // The default encoding returned is null
+        return null;
+    }
+
+    /**
+     * This method returns the LSSerializer's error handler.
+     *
+     * @return Returns the fDOMErrorHandler.
+     */
+    public DOMErrorHandler getErrorHandler() {
+        return fDOMErrorHandler;
+    }
+
+}