diff -r 054a597b18f8 -r aba3efbf4ec5 jaxp/src/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java --- /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 org.apache.xml.serializer.ToStream or + * one of its derived classes depending on the serialization method, while walking + * the DOM in DOM3TreeWalker. + * @see org.w3c.dom.ls.LSSerializer + * @see org.w3c.dom.DOMConfiguration + * + * @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; + } + +}