Home | History | Annotate | Download | only in dom3
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one
      3  * or more contributor license agreements. See the NOTICE file
      4  * distributed with this work for additional information
      5  * regarding copyright ownership. The ASF licenses this file
      6  * to you under the Apache License, Version 2.0 (the  "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 /*
     19  * $Id:  $
     20  */
     21 
     22 package org.apache.xml.serializer.dom3;
     23 
     24 import java.io.FileOutputStream;
     25 import java.io.OutputStream;
     26 import java.io.StringWriter;
     27 import java.io.UnsupportedEncodingException;
     28 import java.io.Writer;
     29 import java.net.HttpURLConnection;
     30 import java.net.URL;
     31 import java.net.URLConnection;
     32 import java.security.AccessController;
     33 import java.security.PrivilegedAction;
     34 import java.util.Properties;
     35 import java.util.StringTokenizer;
     36 
     37 import org.apache.xml.serializer.DOM3Serializer;
     38 import org.apache.xml.serializer.Encodings;
     39 import org.apache.xml.serializer.OutputPropertiesFactory;
     40 import org.apache.xml.serializer.Serializer;
     41 import org.apache.xml.serializer.SerializerFactory;
     42 import org.apache.xml.serializer.utils.MsgKey;
     43 import org.apache.xml.serializer.utils.SystemIDResolver;
     44 import org.apache.xml.serializer.utils.Utils;
     45 import org.w3c.dom.DOMConfiguration;
     46 import org.w3c.dom.DOMError;
     47 import org.w3c.dom.DOMErrorHandler;
     48 import org.w3c.dom.DOMException;
     49 import org.w3c.dom.DOMStringList;
     50 import org.w3c.dom.Document;
     51 import org.w3c.dom.Node;
     52 import org.w3c.dom.ls.LSException;
     53 import org.w3c.dom.ls.LSOutput;
     54 import org.w3c.dom.ls.LSSerializer;
     55 import org.w3c.dom.ls.LSSerializerFilter;
     56 
     57 /**
     58  * Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer and
     59  * org.w3c.dom.ls.DOMConfiguration.  Serialization is achieved by delegating
     60  * serialization calls to <CODE>org.apache.xml.serializer.ToStream</CODE> or
     61  * one of its derived classes depending on the serialization method, while walking
     62  * the DOM in DOM3TreeWalker.
     63  * @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>
     64  * @see <a href="http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#DOMConfiguration">org.w3c.dom.DOMConfiguration</a>
     65  *
     66  * @version $Id:
     67  *
     68  * @xsl.usage internal
     69  */
     70 final public class LSSerializerImpl implements DOMConfiguration, LSSerializer {
     71 
     72     // The default end-of-line character sequence used in serialization.
     73     private static final String DEFAULT_END_OF_LINE;
     74     static {
     75         String lineSeparator = (String) AccessController.doPrivileged(new PrivilegedAction() {
     76             public Object run() {
     77                 try {
     78                     return System.getProperty("line.separator");
     79                 }
     80                 catch (SecurityException ex) {}
     81                 return null;
     82             }
     83         });
     84         // The DOM Level 3 Load and Save specification requires that implementations choose a default
     85         // sequence which matches one allowed by XML 1.0 (or XML 1.1). If the value of "line.separator"
     86         // isn't one of the XML 1.0 end-of-line sequences then we select "\n" as the default value.
     87         DEFAULT_END_OF_LINE = lineSeparator != null &&
     88             (lineSeparator.equals("\r\n") || lineSeparator.equals("\r")) ? lineSeparator : "\n";
     89     }
     90 
     91     /** private data members */
     92     private Serializer fXMLSerializer = null;
     93 
     94     // Tracks DOMConfiguration features.
     95     protected int fFeatures = 0;
     96 
     97     // Common DOM serializer
     98     private  DOM3Serializer fDOMSerializer = null;
     99 
    100     // A filter set on the LSSerializer
    101     private LSSerializerFilter fSerializerFilter = null;
    102 
    103     // Stores the nodeArg parameter to speed up multiple writes of the same node.
    104     private Node fVisitedNode = null;
    105 
    106     // The end-of-line character sequence used in serialization. "\n" is whats used on the web.
    107     private String fEndOfLine = DEFAULT_END_OF_LINE;
    108 
    109     // The DOMErrorhandler.
    110     private DOMErrorHandler fDOMErrorHandler = null;
    111 
    112     // The Configuration parameter to pass to the Underlying serilaizer.
    113     private Properties fDOMConfigProperties = null;
    114 
    115     // The encoding to use during serialization.
    116     private String fEncoding;
    117 
    118     // ************************************************************************
    119     // DOM Level 3 DOM Configuration parameter names
    120     // ************************************************************************
    121     // Parameter canonical-form, true [optional] - NOT SUPPORTED
    122     private final static int CANONICAL = 0x1 << 0;
    123 
    124     // Parameter cdata-sections, true [required] (default)
    125     private final static int CDATA = 0x1 << 1;
    126 
    127     // Parameter check-character-normalization, true [optional] - NOT SUPPORTED
    128     private final static int CHARNORMALIZE = 0x1 << 2;
    129 
    130     // Parameter comments, true [required] (default)
    131     private final static int COMMENTS = 0x1 << 3;
    132 
    133     // Parameter datatype-normalization, true [optional] - NOT SUPPORTED
    134     private final static int DTNORMALIZE = 0x1 << 4;
    135 
    136     // Parameter element-content-whitespace, true [required] (default) - value - false [optional] NOT SUPPORTED
    137     private final static int ELEM_CONTENT_WHITESPACE = 0x1 << 5;
    138 
    139     // Parameter entities, true [required] (default)
    140     private final static int ENTITIES = 0x1 << 6;
    141 
    142     // Parameter infoset, true [required] (default), false has no effect --> True has no effect for the serializer
    143     private final static int INFOSET = 0x1 << 7;
    144 
    145     // Parameter namespaces, true [required] (default)
    146     private final static int NAMESPACES = 0x1 << 8;
    147 
    148     // Parameter namespace-declarations, true [required] (default)
    149     private final static int NAMESPACEDECLS = 0x1 << 9;
    150 
    151     // Parameter normalize-characters, true [optional] - NOT SUPPORTED
    152     private final static int NORMALIZECHARS = 0x1 << 10;
    153 
    154     // Parameter split-cdata-sections, true [required] (default)
    155     private final static int SPLITCDATA = 0x1 << 11;
    156 
    157     // Parameter validate, true [optional] - NOT SUPPORTED
    158     private final static int VALIDATE = 0x1 << 12;
    159 
    160     // Parameter validate-if-schema, true [optional] - NOT SUPPORTED
    161     private final static int SCHEMAVALIDATE = 0x1 << 13;
    162 
    163     // Parameter split-cdata-sections, true [required] (default)
    164     private final static int WELLFORMED = 0x1 << 14;
    165 
    166     // Parameter discard-default-content, true [required] (default)
    167     // Not sure how this will be used in level 2 Documents
    168     private final static int DISCARDDEFAULT = 0x1 << 15;
    169 
    170     // Parameter format-pretty-print, true [optional]
    171     private final static int PRETTY_PRINT = 0x1 << 16;
    172 
    173     // Parameter ignore-unknown-character-denormalizations, true [required] (default)
    174     // We currently do not support XML 1.1 character normalization
    175     private final static int IGNORE_CHAR_DENORMALIZE = 0x1 << 17;
    176 
    177     // Parameter discard-default-content, true [required] (default)
    178     private final static int XMLDECL = 0x1 << 18;
    179     // ************************************************************************
    180 
    181     // Recognized parameters for which atleast one value can be set
    182     private String fRecognizedParameters [] = {
    183             DOMConstants.DOM_CANONICAL_FORM,
    184             DOMConstants.DOM_CDATA_SECTIONS,
    185             DOMConstants.DOM_CHECK_CHAR_NORMALIZATION,
    186             DOMConstants.DOM_COMMENTS,
    187             DOMConstants.DOM_DATATYPE_NORMALIZATION,
    188             DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
    189             DOMConstants.DOM_ENTITIES,
    190             DOMConstants.DOM_INFOSET,
    191             DOMConstants.DOM_NAMESPACES,
    192             DOMConstants.DOM_NAMESPACE_DECLARATIONS,
    193             //DOMConstants.DOM_NORMALIZE_CHARACTERS,
    194             DOMConstants.DOM_SPLIT_CDATA,
    195             DOMConstants.DOM_VALIDATE,
    196             DOMConstants.DOM_VALIDATE_IF_SCHEMA,
    197             DOMConstants.DOM_WELLFORMED,
    198             DOMConstants.DOM_DISCARD_DEFAULT_CONTENT,
    199             DOMConstants.DOM_FORMAT_PRETTY_PRINT,
    200             DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS,
    201             DOMConstants.DOM_XMLDECL,
    202             DOMConstants.DOM_ERROR_HANDLER
    203     };
    204 
    205 
    206     /**
    207      * Constructor:  Creates a LSSerializerImpl object.  The underlying
    208      * XML 1.0 or XML 1.1 org.apache.xml.serializer.Serializer object is
    209      * created and initialized the first time any of the write methods are
    210      * invoked to serialize the Node.  Subsequent write methods on the same
    211      * LSSerializerImpl object will use the previously created Serializer object.
    212      */
    213     public LSSerializerImpl () {
    214         // set default parameters
    215         fFeatures |= CDATA;
    216         fFeatures |= COMMENTS;
    217         fFeatures |= ELEM_CONTENT_WHITESPACE;
    218         fFeatures |= ENTITIES;
    219         fFeatures |= NAMESPACES;
    220         fFeatures |= NAMESPACEDECLS;
    221         fFeatures |= SPLITCDATA;
    222         fFeatures |= WELLFORMED;
    223         fFeatures |= DISCARDDEFAULT;
    224         fFeatures |= XMLDECL;
    225 
    226         // New OutputFormat properties
    227         fDOMConfigProperties = new Properties();
    228 
    229         // Initialize properties to be passed on the underlying serializer
    230         initializeSerializerProps();
    231 
    232         // Create the underlying serializer.
    233         Properties  configProps = OutputPropertiesFactory.getDefaultMethodProperties("xml");
    234 
    235         // change xml version from 1.0 to 1.1
    236         //configProps.setProperty("version", "1.1");
    237 
    238         // Get a serializer that seriailizes according the the properties,
    239         // which in this case is to xml
    240         fXMLSerializer = SerializerFactory.getSerializer(configProps);
    241 
    242         // Initialize Serializer
    243         fXMLSerializer.setOutputFormat(fDOMConfigProperties);
    244     }
    245 
    246     /**
    247      * Initializes the underlying serializer's configuration depending on the
    248      * default DOMConfiguration parameters. This method must be called before a
    249      * node is to be serialized.
    250      *
    251      * @xsl.usage internal
    252      */
    253     public void initializeSerializerProps () {
    254         // canonical-form
    255         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    256                 + DOMConstants.DOM_CANONICAL_FORM, DOMConstants.DOM3_DEFAULT_FALSE);
    257 
    258         // cdata-sections
    259         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    260                 + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_DEFAULT_TRUE);
    261 
    262         // "check-character-normalization"
    263         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    264                 + DOMConstants.DOM_CHECK_CHAR_NORMALIZATION,
    265                 DOMConstants.DOM3_DEFAULT_FALSE);
    266 
    267         // comments
    268         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    269                 + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_DEFAULT_TRUE);
    270 
    271         // datatype-normalization
    272         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    273                 + DOMConstants.DOM_DATATYPE_NORMALIZATION,
    274                 DOMConstants.DOM3_DEFAULT_FALSE);
    275 
    276         // element-content-whitespace
    277         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    278                 + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
    279                 DOMConstants.DOM3_DEFAULT_TRUE);
    280 
    281         // entities
    282         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    283                 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_TRUE);
    284         // preserve entities
    285         fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS
    286                 + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_TRUE);
    287 
    288         // error-handler
    289         // Should we set our default ErrorHandler
    290         /*
    291          * if (fDOMConfig.getParameter(Constants.DOM_ERROR_HANDLER) != null) {
    292          * fDOMErrorHandler =
    293          * (DOMErrorHandler)fDOMConfig.getParameter(Constants.DOM_ERROR_HANDLER); }
    294          */
    295 
    296         // infoset
    297         if ((fFeatures & INFOSET) != 0) {
    298             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    299                     + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_DEFAULT_TRUE);
    300             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    301                     + DOMConstants.DOM_NAMESPACE_DECLARATIONS,
    302                     DOMConstants.DOM3_DEFAULT_TRUE);
    303             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    304                     + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_DEFAULT_TRUE);
    305             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    306                     + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
    307                     DOMConstants.DOM3_DEFAULT_TRUE);
    308             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    309                     + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_DEFAULT_TRUE);
    310             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    311                     + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_FALSE);
    312             // preserve entities
    313             fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS
    314                     + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_DEFAULT_FALSE);
    315             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    316                     + DOMConstants.DOM_CDATA_SECTIONS,
    317                     DOMConstants.DOM3_DEFAULT_FALSE);
    318             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    319                     + DOMConstants.DOM_VALIDATE_IF_SCHEMA,
    320                     DOMConstants.DOM3_DEFAULT_FALSE);
    321             fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    322                     + DOMConstants.DOM_DATATYPE_NORMALIZATION,
    323                     DOMConstants.DOM3_DEFAULT_FALSE);
    324         }
    325 
    326         // namespaces
    327         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    328                 + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_DEFAULT_TRUE);
    329 
    330         // namespace-declarations
    331         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    332                 + DOMConstants.DOM_NAMESPACE_DECLARATIONS,
    333                 DOMConstants.DOM3_DEFAULT_TRUE);
    334 
    335         // normalize-characters
    336         /*
    337         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    338                 + DOMConstants.DOM_NORMALIZE_CHARACTERS,
    339                 DOMConstants.DOM3_DEFAULT_FALSE);
    340         */
    341 
    342         // split-cdata-sections
    343         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    344                 + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_DEFAULT_TRUE);
    345 
    346         // validate
    347         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    348                 + DOMConstants.DOM_VALIDATE, DOMConstants.DOM3_DEFAULT_FALSE);
    349 
    350         // validate-if-schema
    351         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    352                 + DOMConstants.DOM_VALIDATE_IF_SCHEMA,
    353                 DOMConstants.DOM3_DEFAULT_FALSE);
    354 
    355         // well-formed
    356         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    357                 + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_DEFAULT_TRUE);
    358 
    359         // pretty-print
    360         fDOMConfigProperties.setProperty(
    361                 DOMConstants.S_XSL_OUTPUT_INDENT,
    362                 DOMConstants.DOM3_DEFAULT_TRUE);
    363         fDOMConfigProperties.setProperty(
    364                 OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, Integer.toString(3));
    365 
    366         //
    367 
    368         // discard-default-content
    369         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    370                 + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT,
    371                 DOMConstants.DOM3_DEFAULT_TRUE);
    372 
    373         // xml-declaration
    374         fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "no");
    375 
    376     }
    377 
    378     // ************************************************************************
    379     // DOMConfiguraiton implementation
    380     // ************************************************************************
    381 
    382     /**
    383      * Checks if setting a parameter to a specific value is supported.
    384      *
    385      * @see org.w3c.dom.DOMConfiguration#canSetParameter(java.lang.String, java.lang.Object)
    386      * @since DOM Level 3
    387      * @param name A String containing the DOMConfiguration parameter name.
    388      * @param value An Object specifying the value of the corresponding parameter.
    389      */
    390     public boolean canSetParameter(String name, Object value) {
    391         if (value instanceof Boolean){
    392             if ( name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)
    393                     || name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)
    394                     || name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)
    395                     || name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)
    396                     || name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)
    397                     || name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)
    398                     || name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)
    399                     || name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)
    400                     || name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)
    401                     || name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)
    402                     || name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)
    403                     || name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)){
    404                 // both values supported
    405                 return true;
    406             }
    407             else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
    408                     || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
    409                     || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
    410                     || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)
    411                     || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
    412                     // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
    413                     ) {
    414                 // true is not supported
    415                 return !((Boolean)value).booleanValue();
    416             }
    417             else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
    418                 // false is not supported
    419                 return ((Boolean)value).booleanValue();
    420             }
    421         }
    422         else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER) &&
    423                 value == null || value instanceof DOMErrorHandler){
    424             return true;
    425         }
    426         return false;
    427     }
    428     /**
    429      * This method returns the value of a parameter if known.
    430      *
    431      * @see org.w3c.dom.DOMConfiguration#getParameter(java.lang.String)
    432      *
    433      * @param name A String containing the DOMConfiguration parameter name
    434      *             whose value is to be returned.
    435      * @return Object The value of the parameter if known.
    436      */
    437     public Object getParameter(String name) throws DOMException {
    438         if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)) {
    439             return ((fFeatures & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE;
    440         } else if (name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)) {
    441             return ((fFeatures & CDATA) != 0) ? Boolean.TRUE : Boolean.FALSE;
    442         } else if (name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)) {
    443             return ((fFeatures & ENTITIES) != 0) ? Boolean.TRUE : Boolean.FALSE;
    444         } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)) {
    445             return ((fFeatures & NAMESPACES) != 0) ? Boolean.TRUE : Boolean.FALSE;
    446         } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)) {
    447             return ((fFeatures & NAMESPACEDECLS) != 0) ? Boolean.TRUE : Boolean.FALSE;
    448         } else if (name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)) {
    449             return ((fFeatures & SPLITCDATA) != 0) ? Boolean.TRUE : Boolean.FALSE;
    450         } else if (name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)) {
    451             return ((fFeatures & WELLFORMED) != 0) ? Boolean.TRUE : Boolean.FALSE;
    452         }  else if (name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)) {
    453             return ((fFeatures & DISCARDDEFAULT) != 0) ? Boolean.TRUE : Boolean.FALSE;
    454         } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
    455             return ((fFeatures & PRETTY_PRINT) != 0) ? Boolean.TRUE : Boolean.FALSE;
    456         } else if (name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)) {
    457             return ((fFeatures & XMLDECL) != 0) ? Boolean.TRUE : Boolean.FALSE;
    458         } else if (name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
    459             return ((fFeatures & ELEM_CONTENT_WHITESPACE) != 0) ? Boolean.TRUE : Boolean.FALSE;
    460         } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
    461             return ((fFeatures & PRETTY_PRINT) != 0) ? Boolean.TRUE : Boolean.FALSE;
    462         } else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
    463             return Boolean.TRUE;
    464         } else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
    465                 || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
    466                 || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
    467                 // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
    468                 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
    469                 || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
    470             return Boolean.FALSE;
    471         } else if (name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)){
    472             if ((fFeatures & ENTITIES) == 0 &&
    473                     (fFeatures & CDATA) == 0 &&
    474                     (fFeatures & ELEM_CONTENT_WHITESPACE) != 0 &&
    475                     (fFeatures & NAMESPACES) != 0 &&
    476                     (fFeatures & NAMESPACEDECLS) != 0 &&
    477                     (fFeatures & WELLFORMED) != 0 &&
    478                     (fFeatures & COMMENTS) != 0) {
    479                 return Boolean.TRUE;
    480             }
    481             return Boolean.FALSE;
    482         } else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER)) {
    483             return fDOMErrorHandler;
    484         } else if (
    485                 name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION)
    486                 || name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)) {
    487             return null;
    488         } else {
    489             // Here we have to add the Xalan specific DOM Message Formatter
    490             String msg = Utils.messages.createMessage(
    491                     MsgKey.ER_FEATURE_NOT_FOUND,
    492                     new Object[] { name });
    493             throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
    494         }
    495     }
    496 
    497     /**
    498      * This method returns a of the parameters supported by this DOMConfiguration object
    499      * and for which at least one value can be set by the application
    500      *
    501      * @see org.w3c.dom.DOMConfiguration#getParameterNames()
    502      *
    503      * @return DOMStringList A list of DOMConfiguration parameters recognized
    504      *                       by the serializer
    505      */
    506     public DOMStringList getParameterNames() {
    507         return new DOMStringListImpl(fRecognizedParameters);
    508     }
    509 
    510     /**
    511      * This method sets the value of the named parameter.
    512      *
    513      * @see org.w3c.dom.DOMConfiguration#setParameter(java.lang.String, java.lang.Object)
    514      *
    515      * @param name A String containing the DOMConfiguration parameter name.
    516      * @param value An Object contaiing the parameters value to set.
    517      */
    518     public void setParameter(String name, Object value) throws DOMException {
    519         // If the value is a boolean
    520         if (value instanceof Boolean) {
    521             boolean state = ((Boolean) value).booleanValue();
    522 
    523             if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS)) {
    524                 fFeatures = state ? fFeatures | COMMENTS : fFeatures
    525                         & ~COMMENTS;
    526                 // comments
    527                 if (state) {
    528                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    529                             + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_TRUE);
    530                 } else {
    531                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    532                             + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_FALSE);
    533                 }
    534             } else if (name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS)) {
    535                 fFeatures =  state ? fFeatures | CDATA : fFeatures
    536                         & ~CDATA;
    537                 // cdata-sections
    538                 if (state) {
    539                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    540                             + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
    541                 } else {
    542                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    543                             + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
    544                 }
    545             } else if (name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES)) {
    546                 fFeatures = state ? fFeatures | ENTITIES : fFeatures
    547                         & ~ENTITIES;
    548                 // entities
    549                 if (state) {
    550                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    551                             + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_TRUE);
    552                     fDOMConfigProperties.setProperty(
    553                             DOMConstants.S_XERCES_PROPERTIES_NS
    554                             + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_TRUE);
    555                 } else {
    556                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    557                             + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
    558                     fDOMConfigProperties.setProperty(
    559                             DOMConstants.S_XERCES_PROPERTIES_NS
    560                             + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
    561                 }
    562             } else if (name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES)) {
    563                 fFeatures = state ? fFeatures | NAMESPACES : fFeatures
    564                         & ~NAMESPACES;
    565                 // namespaces
    566                 if (state) {
    567                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    568                             + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_TRUE);
    569                 } else {
    570                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    571                             + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_FALSE);
    572                 }
    573             } else if (name
    574                     .equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS)) {
    575                 fFeatures = state ? fFeatures | NAMESPACEDECLS
    576                         : fFeatures & ~NAMESPACEDECLS;
    577                 // namespace-declarations
    578                 if (state) {
    579                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    580                             + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
    581                 } else {
    582                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    583                             + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
    584                 }
    585             } else if (name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA)) {
    586                 fFeatures = state ? fFeatures | SPLITCDATA : fFeatures
    587                         & ~SPLITCDATA;
    588                 // split-cdata-sections
    589                 if (state) {
    590                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    591                             + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_EXPLICIT_TRUE);
    592                 } else {
    593                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    594                             + DOMConstants.DOM_SPLIT_CDATA, DOMConstants.DOM3_EXPLICIT_FALSE);
    595                 }
    596             } else if (name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED)) {
    597                 fFeatures = state ? fFeatures | WELLFORMED : fFeatures
    598                         & ~WELLFORMED;
    599                 // well-formed
    600                 if (state) {
    601                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    602                             + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_TRUE);
    603                 } else {
    604                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    605                             + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_FALSE);
    606                 }
    607             } else if (name
    608                     .equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT)) {
    609                 fFeatures = state ? fFeatures | DISCARDDEFAULT
    610                         : fFeatures & ~DISCARDDEFAULT;
    611                 // discard-default-content
    612                 if (state) {
    613                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    614                             + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT, DOMConstants.DOM3_EXPLICIT_TRUE);
    615                 } else {
    616                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    617                             + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT, DOMConstants.DOM3_EXPLICIT_FALSE);
    618                 }
    619             } else if (name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT)) {
    620                 fFeatures = state ? fFeatures | PRETTY_PRINT : fFeatures
    621                         & ~PRETTY_PRINT;
    622                 // format-pretty-print
    623                 if (state) {
    624                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    625                             + DOMConstants.DOM_FORMAT_PRETTY_PRINT, DOMConstants.DOM3_EXPLICIT_TRUE);
    626                 }
    627                 else {
    628                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    629                             + DOMConstants.DOM_FORMAT_PRETTY_PRINT, DOMConstants.DOM3_EXPLICIT_FALSE);
    630                 }
    631             } else if (name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL)) {
    632                 fFeatures = state ? fFeatures | XMLDECL : fFeatures
    633                         & ~XMLDECL;
    634                 if (state) {
    635                     fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "no");
    636                 } else {
    637                     fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "yes");
    638                 }
    639             } else if (name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE)) {
    640                 fFeatures = state ? fFeatures | ELEM_CONTENT_WHITESPACE : fFeatures
    641                         & ~ELEM_CONTENT_WHITESPACE;
    642                 // element-content-whitespace
    643                 if (state) {
    644                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    645                             + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_TRUE);
    646                 } else {
    647                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    648                             + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_FALSE);
    649                 }
    650             } else if (name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
    651                 // false is not supported
    652                 if (!state) {
    653                     // Here we have to add the Xalan specific DOM Message Formatter
    654                     String msg = Utils.messages.createMessage(
    655                             MsgKey.ER_FEATURE_NOT_SUPPORTED,
    656                             new Object[] { name });
    657                     throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
    658                 } else {
    659                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    660                             + DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
    661                 }
    662             } else if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)
    663                     || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)
    664                     || name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)
    665                     || name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION)
    666                     || name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)
    667                     // || name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)
    668                     ) {
    669                 // true is not supported
    670                 if (state) {
    671                     String msg = Utils.messages.createMessage(
    672                             MsgKey.ER_FEATURE_NOT_SUPPORTED,
    673                             new Object[] { name });
    674                     throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
    675                 } else {
    676                     if (name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM)) {
    677                         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    678                                 + DOMConstants.DOM_CANONICAL_FORM, DOMConstants.DOM3_EXPLICIT_FALSE);
    679                     } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
    680                         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    681                                 + DOMConstants.DOM_VALIDATE_IF_SCHEMA, DOMConstants.DOM3_EXPLICIT_FALSE);
    682                     } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE)) {
    683                         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    684                                 + DOMConstants.DOM_VALIDATE, DOMConstants.DOM3_EXPLICIT_FALSE);
    685                     } else if (name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA)) {
    686                         fDOMConfigProperties.setProperty(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION
    687                                 + DOMConstants.DOM_CHECK_CHAR_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
    688                     } else if (name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION)) {
    689                         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    690                                 + DOMConstants.DOM_DATATYPE_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
    691                     } /* else if (name.equalsIgnoreCase(DOMConstants.DOM_NORMALIZE_CHARACTERS)) {
    692                         fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    693                                 + DOMConstants.DOM_NORMALIZE_CHARACTERS, DOMConstants.DOM3_EXPLICIT_FALSE);
    694                     } */
    695                 }
    696             } else if (name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)) {
    697                 // infoset
    698                 if (state) {
    699                     fFeatures &= ~ENTITIES;
    700                     fFeatures &= ~CDATA;
    701                     fFeatures &= ~SCHEMAVALIDATE;
    702                     fFeatures &= ~DTNORMALIZE;
    703                     fFeatures |= NAMESPACES;
    704                     fFeatures |= NAMESPACEDECLS;
    705                     fFeatures |= WELLFORMED;
    706                     fFeatures |= ELEM_CONTENT_WHITESPACE;
    707                     fFeatures |= COMMENTS;
    708 
    709                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    710                             + DOMConstants.DOM_NAMESPACES, DOMConstants.DOM3_EXPLICIT_TRUE);
    711                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    712                             + DOMConstants.DOM_NAMESPACE_DECLARATIONS, DOMConstants.DOM3_EXPLICIT_TRUE);
    713                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    714                             + DOMConstants.DOM_COMMENTS, DOMConstants.DOM3_EXPLICIT_TRUE);
    715                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    716                             + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE, DOMConstants.DOM3_EXPLICIT_TRUE);
    717                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    718                             + DOMConstants.DOM_WELLFORMED, DOMConstants.DOM3_EXPLICIT_TRUE);
    719 
    720                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    721                             + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
    722                     fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS
    723                             + DOMConstants.DOM_ENTITIES, DOMConstants.DOM3_EXPLICIT_FALSE);
    724 
    725                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    726                             + DOMConstants.DOM_CDATA_SECTIONS, DOMConstants.DOM3_EXPLICIT_FALSE);
    727                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    728                             + DOMConstants.DOM_VALIDATE_IF_SCHEMA, DOMConstants.DOM3_EXPLICIT_FALSE);
    729                     fDOMConfigProperties.setProperty(DOMConstants.S_DOM3_PROPERTIES_NS
    730                             + DOMConstants.DOM_DATATYPE_NORMALIZATION, DOMConstants.DOM3_EXPLICIT_FALSE);
    731                 }
    732             } else {
    733                 // If this is a non-boolean parameter a type mismatch should be thrown.
    734                 if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER) ||
    735                     name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION) ||
    736                     name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)) {
    737                     String msg = Utils.messages.createMessage(
    738                             MsgKey.ER_TYPE_MISMATCH_ERR,
    739                             new Object[] { name });
    740                     throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
    741                 }
    742 
    743                 // Parameter is not recognized
    744                 String msg = Utils.messages.createMessage(
    745                         MsgKey.ER_FEATURE_NOT_FOUND,
    746                         new Object[] { name });
    747                 throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
    748             }
    749         } // If the parameter value is not a boolean
    750         else if (name.equalsIgnoreCase(DOMConstants.DOM_ERROR_HANDLER)) {
    751             if (value == null || value instanceof DOMErrorHandler) {
    752                 fDOMErrorHandler = (DOMErrorHandler)value;
    753             } else {
    754                 String msg = Utils.messages.createMessage(
    755                         MsgKey.ER_TYPE_MISMATCH_ERR,
    756                         new Object[] { name });
    757                 throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
    758             }
    759         } else if (
    760                 name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_LOCATION)
    761                 || name.equalsIgnoreCase(DOMConstants.DOM_SCHEMA_TYPE)) {
    762             if (value != null) {
    763                 if (!(value instanceof String)) {
    764                     String msg = Utils.messages.createMessage(
    765                             MsgKey.ER_TYPE_MISMATCH_ERR,
    766                             new Object[] { name });
    767                     throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
    768                 }
    769                 String msg = Utils.messages.createMessage(
    770                         MsgKey.ER_FEATURE_NOT_SUPPORTED,
    771                         new Object[] { name });
    772                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
    773             }
    774         } else {
    775             // If this is a boolean parameter a type mismatch should be thrown.
    776             if (name.equalsIgnoreCase(DOMConstants.DOM_COMMENTS) ||
    777                     name.equalsIgnoreCase(DOMConstants.DOM_CDATA_SECTIONS) ||
    778                     name.equalsIgnoreCase(DOMConstants.DOM_ENTITIES) ||
    779                     name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACES) ||
    780                     name.equalsIgnoreCase(DOMConstants.DOM_NAMESPACE_DECLARATIONS) ||
    781                     name.equalsIgnoreCase(DOMConstants.DOM_SPLIT_CDATA) ||
    782                     name.equalsIgnoreCase(DOMConstants.DOM_WELLFORMED) ||
    783                     name.equalsIgnoreCase(DOMConstants.DOM_DISCARD_DEFAULT_CONTENT) ||
    784                     name.equalsIgnoreCase(DOMConstants.DOM_FORMAT_PRETTY_PRINT) ||
    785                     name.equalsIgnoreCase(DOMConstants.DOM_XMLDECL) ||
    786                     name.equalsIgnoreCase(DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE) ||
    787                     name.equalsIgnoreCase(DOMConstants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS) ||
    788                     name.equalsIgnoreCase(DOMConstants.DOM_CANONICAL_FORM) ||
    789                     name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE_IF_SCHEMA) ||
    790                     name.equalsIgnoreCase(DOMConstants.DOM_VALIDATE) ||
    791                     name.equalsIgnoreCase(DOMConstants.DOM_CHECK_CHAR_NORMALIZATION) ||
    792                     name.equalsIgnoreCase(DOMConstants.DOM_DATATYPE_NORMALIZATION) ||
    793                     name.equalsIgnoreCase(DOMConstants.DOM_INFOSET)) {
    794                 String msg = Utils.messages.createMessage(
    795                         MsgKey.ER_TYPE_MISMATCH_ERR,
    796                         new Object[] { name });
    797                 throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
    798             }
    799 
    800             // Parameter is not recognized
    801             String msg = Utils.messages.createMessage(
    802                     MsgKey.ER_FEATURE_NOT_FOUND,
    803                     new Object[] { name });
    804             throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
    805         }
    806     }
    807     // ************************************************************************
    808 
    809 
    810     // ************************************************************************
    811     // DOMConfiguraiton implementation
    812     // ************************************************************************
    813 
    814     /**
    815      * Returns the DOMConfiguration of the LSSerializer.
    816      *
    817      * @see org.w3c.dom.ls.LSSerializer#getDomConfig()
    818      * @since DOM Level 3
    819      * @return A DOMConfiguration object.
    820      */
    821     public DOMConfiguration getDomConfig() {
    822         return (DOMConfiguration)this;
    823     }
    824 
    825     /**
    826      * Returns the DOMConfiguration of the LSSerializer.
    827      *
    828      * @see org.w3c.dom.ls.LSSerializer#getFilter()
    829      * @since DOM Level 3
    830      * @return A LSSerializerFilter object.
    831      */
    832     public LSSerializerFilter getFilter() {
    833         return fSerializerFilter;
    834     }
    835 
    836     /**
    837      * Returns the End-Of-Line sequence of characters to be used in the XML
    838      * being serialized.  If none is set a default "\n" is returned.
    839      *
    840      * @see org.w3c.dom.ls.LSSerializer#getNewLine()
    841      * @since DOM Level 3
    842      * @return A String containing the end-of-line character sequence  used in
    843      * serialization.
    844      */
    845     public String getNewLine() {
    846         return fEndOfLine;
    847     }
    848 
    849     /**
    850      * Set a LSSerilizerFilter on the LSSerializer.  When set, the filter is
    851      * called before each node is serialized which depending on its implemention
    852      * determines if the node is to be serialized or not.
    853      *
    854      * @see org.w3c.dom.ls.LSSerializer#setFilter
    855      * @since DOM Level 3
    856      * @param filter A LSSerializerFilter to be applied to the stream to serialize.
    857      */
    858     public void setFilter(LSSerializerFilter filter) {
    859         fSerializerFilter = filter;
    860     }
    861 
    862     /**
    863      * Sets the End-Of-Line sequence of characters to be used in the XML
    864      * being serialized.  Setting this attribute to null will reset its
    865      * value to the default value i.e. "\n".
    866      *
    867      * @see org.w3c.dom.ls.LSSerializer#setNewLine
    868      * @since DOM Level 3
    869      * @param newLine a String that is the end-of-line character sequence to be used in
    870      * serialization.
    871      */
    872     public void setNewLine(String newLine) {
    873         fEndOfLine = (newLine != null) ? newLine : DEFAULT_END_OF_LINE;
    874     }
    875 
    876     /**
    877      * Serializes the specified node to the specified LSOutput and returns true if the Node
    878      * was successfully serialized.
    879      *
    880      * @see org.w3c.dom.ls.LSSerializer#write(org.w3c.dom.Node, org.w3c.dom.ls.LSOutput)
    881      * @since DOM Level 3
    882      * @param nodeArg The Node to serialize.
    883      * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
    884      * LSSerializer was unable to serialize the node.
    885      *
    886      */
    887     public boolean write(Node nodeArg, LSOutput destination) throws LSException {
    888         // If the destination is null
    889         if (destination == null) {
    890             String msg = Utils.messages
    891             .createMessage(
    892                     MsgKey.ER_NO_OUTPUT_SPECIFIED,
    893                     null);
    894             if (fDOMErrorHandler != null) {
    895                 fDOMErrorHandler.handleError(new DOMErrorImpl(
    896                         DOMError.SEVERITY_FATAL_ERROR, msg,
    897                         MsgKey.ER_NO_OUTPUT_SPECIFIED));
    898             }
    899             throw new LSException(LSException.SERIALIZE_ERR, msg);
    900         }
    901 
    902         // If nodeArg is null, return false.  Should we throw and LSException instead?
    903         if (nodeArg == null ) {
    904             return false;
    905         }
    906 
    907         // Obtain a reference to the serializer to use
    908         // Serializer serializer = getXMLSerializer(xmlVersion);
    909         Serializer serializer = fXMLSerializer;
    910         serializer.reset();
    911 
    912         // If the node has not been seen
    913         if ( nodeArg != fVisitedNode) {
    914             // Determine the XML Document version of the Node
    915             String xmlVersion = getXMLVersion(nodeArg);
    916 
    917             // Determine the encoding: 1.LSOutput.encoding, 2.Document.inputEncoding, 3.Document.xmlEncoding.
    918             fEncoding = destination.getEncoding();
    919             if (fEncoding == null ) {
    920             	fEncoding = getInputEncoding(nodeArg);
    921             	fEncoding = fEncoding != null ? fEncoding : getXMLEncoding(nodeArg) == null? "UTF-8": getXMLEncoding(nodeArg);
    922             }
    923 
    924             // If the encoding is not recognized throw an exception.
    925             // Note: The serializer defaults to UTF-8 when created
    926             if (!Encodings.isRecognizedEncoding(fEncoding)) {
    927                 String msg = Utils.messages
    928                 .createMessage(
    929                         MsgKey.ER_UNSUPPORTED_ENCODING,
    930                         null);
    931                 if (fDOMErrorHandler != null) {
    932                     fDOMErrorHandler.handleError(new DOMErrorImpl(
    933                             DOMError.SEVERITY_FATAL_ERROR, msg,
    934                             MsgKey.ER_UNSUPPORTED_ENCODING));
    935                 }
    936                 throw new LSException(LSException.SERIALIZE_ERR, msg);
    937             }
    938 
    939             serializer.getOutputFormat().setProperty("version", xmlVersion);
    940 
    941             // Set the output encoding and xml version properties
    942             fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
    943             fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, fEncoding);
    944 
    945             // If the node to be serialized is not a Document, Element, or Entity
    946             // node
    947             // then the XML declaration, or text declaration, should be never be
    948             // serialized.
    949             if ( (nodeArg.getNodeType() != Node.DOCUMENT_NODE
    950                     || nodeArg.getNodeType() != Node.ELEMENT_NODE
    951                     || nodeArg.getNodeType() != Node.ENTITY_NODE)
    952                     && ((fFeatures & XMLDECL) != 0)) {
    953                 fDOMConfigProperties.setProperty(
    954                         DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
    955                         DOMConstants.DOM3_DEFAULT_FALSE);
    956             }
    957 
    958             fVisitedNode = nodeArg;
    959         }
    960 
    961         // Update the serializer properties
    962         fXMLSerializer.setOutputFormat(fDOMConfigProperties);
    963 
    964         //
    965         try {
    966 
    967             // The LSSerializer will use the LSOutput object to determine
    968             // where to serialize the output to in the following order the
    969             // first one that is not null and not an empty string will be
    970             // used: 1.LSOutput.characterStream, 2.LSOutput.byteStream,
    971             // 3. LSOutput.systemId
    972             // 1.LSOutput.characterStream
    973             Writer writer = destination.getCharacterStream();
    974             if (writer == null ) {
    975 
    976                 // 2.LSOutput.byteStream
    977                 OutputStream outputStream = destination.getByteStream();
    978                 if ( outputStream == null) {
    979 
    980                     // 3. LSOutput.systemId
    981                     String uri = destination.getSystemId();
    982                     if (uri == null) {
    983                         String msg = Utils.messages
    984                         .createMessage(
    985                                 MsgKey.ER_NO_OUTPUT_SPECIFIED,
    986                                 null);
    987                         if (fDOMErrorHandler != null) {
    988                             fDOMErrorHandler.handleError(new DOMErrorImpl(
    989                                     DOMError.SEVERITY_FATAL_ERROR, msg,
    990                                     MsgKey.ER_NO_OUTPUT_SPECIFIED));
    991                         }
    992                         throw new LSException(LSException.SERIALIZE_ERR, msg);
    993 
    994                     } else {
    995                         // Expand the System Id and obtain an absolute URI for it.
    996                         String absoluteURI = SystemIDResolver.getAbsoluteURI(uri);
    997 
    998                         URL url = new URL(absoluteURI);
    999                         OutputStream urlOutStream = null;
   1000                         String protocol = url.getProtocol();
   1001                         String host = url.getHost();
   1002 
   1003                         // For file protocols, there is no need to use a URL to get its
   1004                         // corresponding OutputStream
   1005 
   1006                         // Scheme names consist of a sequence of characters. The lower case
   1007                         // letters "a"--"z", digits, and the characters plus ("+"), period
   1008                         // ("."), and hyphen ("-") are allowed. For resiliency, programs
   1009                         // interpreting URLs should treat upper case letters as equivalent to
   1010                         // lower case in scheme names (e.g., allow "HTTP" as well as "http").
   1011                         if (protocol.equalsIgnoreCase("file")
   1012                                 && (host == null || host.length() == 0 || host.equals("localhost"))) {
   1013                             // do we also need to check for host.equals(hostname)
   1014                             urlOutStream = new FileOutputStream(getPathWithoutEscapes(url.getPath()));
   1015 
   1016                         } else {
   1017                             // This should support URL's whose schemes are mentioned in
   1018                             // RFC1738 other than file
   1019 
   1020                             URLConnection urlCon = url.openConnection();
   1021                             urlCon.setDoInput(false);
   1022                             urlCon.setDoOutput(true);
   1023                             urlCon.setUseCaches(false);
   1024                             urlCon.setAllowUserInteraction(false);
   1025 
   1026                             // When writing to a HTTP URI, a HTTP PUT is performed.
   1027                             if (urlCon instanceof HttpURLConnection) {
   1028                                 HttpURLConnection httpCon = (HttpURLConnection) urlCon;
   1029                                 httpCon.setRequestMethod("PUT");
   1030                             }
   1031                             urlOutStream = urlCon.getOutputStream();
   1032                         }
   1033                         // set the OutputStream to that obtained from the systemId
   1034                         serializer.setOutputStream(urlOutStream);
   1035                     }
   1036                 } else {
   1037                     // 2.LSOutput.byteStream
   1038                     serializer.setOutputStream(outputStream);
   1039                 }
   1040             } else {
   1041                 // 1.LSOutput.characterStream
   1042                 serializer.setWriter(writer);
   1043             }
   1044 
   1045             // The associated media type by default is set to text/xml on
   1046             // org.apache.xml.serializer.SerializerBase.
   1047 
   1048             // Get a reference to the serializer then lets you serilize a DOM
   1049             // Use this hack till Xalan support JAXP1.3
   1050             if (fDOMSerializer == null) {
   1051                fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
   1052             }
   1053 
   1054             // Set the error handler on the DOM3Serializer interface implementation
   1055             if (fDOMErrorHandler != null) {
   1056                 fDOMSerializer.setErrorHandler(fDOMErrorHandler);
   1057             }
   1058 
   1059             // Set the filter on the DOM3Serializer interface implementation
   1060             if (fSerializerFilter != null) {
   1061                 fDOMSerializer.setNodeFilter(fSerializerFilter);
   1062             }
   1063 
   1064             // Set the NewLine character to be used
   1065             fDOMSerializer.setNewLine(fEndOfLine.toCharArray());
   1066 
   1067             // Serializer your DOM, where node is an org.w3c.dom.Node
   1068             // Assuming that Xalan's serializer can serialize any type of DOM node
   1069             fDOMSerializer.serializeDOM3(nodeArg);
   1070 
   1071         } catch( UnsupportedEncodingException ue) {
   1072 
   1073             String msg = Utils.messages
   1074             .createMessage(
   1075                     MsgKey.ER_UNSUPPORTED_ENCODING,
   1076                     null);
   1077             if (fDOMErrorHandler != null) {
   1078                 fDOMErrorHandler.handleError(new DOMErrorImpl(
   1079                         DOMError.SEVERITY_FATAL_ERROR, msg,
   1080                         MsgKey.ER_UNSUPPORTED_ENCODING, ue));
   1081             }
   1082             throw (LSException) createLSException(LSException.SERIALIZE_ERR, ue).fillInStackTrace();
   1083         } catch (LSException lse) {
   1084             // Rethrow LSException.
   1085             throw lse;
   1086         } catch (RuntimeException e) {
   1087             throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
   1088         }  catch (Exception e) {
   1089             if (fDOMErrorHandler != null) {
   1090                 fDOMErrorHandler.handleError(new DOMErrorImpl(
   1091                         DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
   1092                         null, e));
   1093             }
   1094             throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
   1095         }
   1096         return true;
   1097     }
   1098 
   1099     /**
   1100      * Serializes the specified node and returns a String with the serialized
   1101      * data to the caller.
   1102      *
   1103      * @see org.w3c.dom.ls.LSSerializer#writeToString(org.w3c.dom.Node)
   1104      * @since DOM Level 3
   1105      * @param nodeArg The Node to serialize.
   1106      * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
   1107      * LSSerializer was unable to serialize the node.
   1108      *
   1109      */
   1110     public String writeToString(Node nodeArg) throws DOMException, LSException {
   1111         // return null is nodeArg is null.  Should an Exception be thrown instead?
   1112         if (nodeArg == null) {
   1113             return null;
   1114         }
   1115 
   1116         // Should we reset the serializer configuration before each write operation?
   1117         // Obtain a reference to the serializer to use
   1118         Serializer serializer = fXMLSerializer;
   1119         serializer.reset();
   1120 
   1121         if (nodeArg != fVisitedNode){
   1122             // Determine the XML Document version of the Node
   1123             String xmlVersion = getXMLVersion(nodeArg);
   1124 
   1125             serializer.getOutputFormat().setProperty("version", xmlVersion);
   1126 
   1127             // Set the output encoding and xml version properties
   1128             fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
   1129             fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, "UTF-16");
   1130 
   1131             // If the node to be serialized is not a Document, Element, or Entity
   1132             // node
   1133             // then the XML declaration, or text declaration, should be never be
   1134             // serialized.
   1135             if  ((nodeArg.getNodeType() != Node.DOCUMENT_NODE
   1136                     || nodeArg.getNodeType() != Node.ELEMENT_NODE
   1137                     || nodeArg.getNodeType() != Node.ENTITY_NODE)
   1138                     && ((fFeatures & XMLDECL) != 0)) {
   1139                 fDOMConfigProperties.setProperty(
   1140                         DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
   1141                         DOMConstants.DOM3_DEFAULT_FALSE);
   1142             }
   1143 
   1144             fVisitedNode = nodeArg;
   1145         }
   1146         // Update the serializer properties
   1147         fXMLSerializer.setOutputFormat(fDOMConfigProperties);
   1148 
   1149         // StringWriter to Output to
   1150         StringWriter output = new StringWriter();
   1151 
   1152         //
   1153         try {
   1154 
   1155             // Set the Serializer's Writer to a StringWriter
   1156             serializer.setWriter(output);
   1157 
   1158             // Get a reference to the serializer then lets you serilize a DOM
   1159             // Use this hack till Xalan support JAXP1.3
   1160             if (fDOMSerializer == null) {
   1161                 fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
   1162             }
   1163 
   1164             // Set the error handler on the DOM3Serializer interface implementation
   1165             if (fDOMErrorHandler != null) {
   1166                 fDOMSerializer.setErrorHandler(fDOMErrorHandler);
   1167             }
   1168 
   1169             // Set the filter on the DOM3Serializer interface implementation
   1170             if (fSerializerFilter != null) {
   1171                 fDOMSerializer.setNodeFilter(fSerializerFilter);
   1172             }
   1173 
   1174             // Set the NewLine character to be used
   1175             fDOMSerializer.setNewLine(fEndOfLine.toCharArray());
   1176 
   1177             // Serializer your DOM, where node is an org.w3c.dom.Node
   1178             fDOMSerializer.serializeDOM3(nodeArg);
   1179         } catch (LSException lse) {
   1180             // Rethrow LSException.
   1181             throw lse;
   1182         } catch (RuntimeException e) {
   1183             throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
   1184         }  catch (Exception e) {
   1185             if (fDOMErrorHandler != null) {
   1186                 fDOMErrorHandler.handleError(new DOMErrorImpl(
   1187                         DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
   1188                         null, e));
   1189             }
   1190             throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
   1191         }
   1192 
   1193         // return the serialized string
   1194         return output.toString();
   1195     }
   1196 
   1197     /**
   1198      * Serializes the specified node to the specified URI and returns true if the Node
   1199      * was successfully serialized.
   1200      *
   1201      * @see org.w3c.dom.ls.LSSerializer#writeToURI(org.w3c.dom.Node, String)
   1202      * @since DOM Level 3
   1203      * @param nodeArg The Node to serialize.
   1204      * @throws org.w3c.dom.ls.LSException SERIALIZE_ERR: Raised if the
   1205      * LSSerializer was unable to serialize the node.
   1206      *
   1207      */
   1208     public boolean writeToURI(Node nodeArg, String uri) throws LSException {
   1209         // If nodeArg is null, return false.  Should we throw and LSException instead?
   1210         if (nodeArg == null ) {
   1211             return false;
   1212         }
   1213 
   1214         // Obtain a reference to the serializer to use
   1215         Serializer serializer = fXMLSerializer;
   1216         serializer.reset();
   1217 
   1218         if (nodeArg != fVisitedNode) {
   1219             // Determine the XML Document version of the Node
   1220             String xmlVersion = getXMLVersion(nodeArg);
   1221 
   1222             // Determine the encoding: 1.LSOutput.encoding,
   1223             // 2.Document.inputEncoding, 3.Document.xmlEncoding.
   1224             fEncoding = getInputEncoding(nodeArg);
   1225             if (fEncoding == null ) {
   1226             	fEncoding = fEncoding != null ? fEncoding : getXMLEncoding(nodeArg) == null? "UTF-8": getXMLEncoding(nodeArg);
   1227             }
   1228 
   1229             serializer.getOutputFormat().setProperty("version", xmlVersion);
   1230 
   1231             // Set the output encoding and xml version properties
   1232             fDOMConfigProperties.setProperty(DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION, xmlVersion);
   1233             fDOMConfigProperties.setProperty(DOMConstants.S_XSL_OUTPUT_ENCODING, fEncoding);
   1234 
   1235             // If the node to be serialized is not a Document, Element, or Entity
   1236             // node
   1237             // then the XML declaration, or text declaration, should be never be
   1238             // serialized.
   1239             if ( (nodeArg.getNodeType() != Node.DOCUMENT_NODE
   1240                     || nodeArg.getNodeType() != Node.ELEMENT_NODE
   1241                     || nodeArg.getNodeType() != Node.ENTITY_NODE)
   1242                     && ((fFeatures & XMLDECL) != 0))  {
   1243                 fDOMConfigProperties.setProperty(
   1244                         DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL,
   1245                         DOMConstants.DOM3_DEFAULT_FALSE);
   1246             }
   1247 
   1248             fVisitedNode = nodeArg;
   1249         }
   1250 
   1251         // Update the serializer properties
   1252         fXMLSerializer.setOutputFormat(fDOMConfigProperties);
   1253 
   1254         //
   1255         try {
   1256             // If the specified encoding is not supported an
   1257             // "unsupported-encoding" fatal error is raised. ??
   1258             if (uri == null) {
   1259                 String msg = Utils.messages.createMessage(
   1260                         MsgKey.ER_NO_OUTPUT_SPECIFIED, null);
   1261                 if (fDOMErrorHandler != null) {
   1262                     fDOMErrorHandler.handleError(new DOMErrorImpl(
   1263                             DOMError.SEVERITY_FATAL_ERROR, msg,
   1264                             MsgKey.ER_NO_OUTPUT_SPECIFIED));
   1265                 }
   1266                 throw new LSException(LSException.SERIALIZE_ERR, msg);
   1267 
   1268             } else {
   1269                 // REVISIT: Can this be used to get an absolute expanded URI
   1270                 String absoluteURI = SystemIDResolver.getAbsoluteURI(uri);
   1271 
   1272                 URL url = new URL(absoluteURI);
   1273                 OutputStream urlOutStream = null;
   1274                 String protocol = url.getProtocol();
   1275                 String host = url.getHost();
   1276 
   1277                 // For file protocols, there is no need to use a URL to get its
   1278                 // corresponding OutputStream
   1279 
   1280                 // Scheme names consist of a sequence of characters. The lower
   1281                 // case letters "a"--"z", digits, and the characters plus ("+"),
   1282                 // period ("."), and hyphen ("-") are allowed. For resiliency,
   1283                 // programs interpreting URLs should treat upper case letters as
   1284                 // equivalent to lower case in scheme names
   1285                 // (e.g., allow "HTTP" as well as "http").
   1286                 if (protocol.equalsIgnoreCase("file")
   1287                         && (host == null || host.length() == 0 || host
   1288                                 .equals("localhost"))) {
   1289                     // do we also need to check for host.equals(hostname)
   1290                     urlOutStream = new FileOutputStream(getPathWithoutEscapes(url.getPath()));
   1291 
   1292                 } else {
   1293                     // This should support URL's whose schemes are mentioned in
   1294                     // RFC1738 other than file
   1295 
   1296                     URLConnection urlCon = url.openConnection();
   1297                     urlCon.setDoInput(false);
   1298                     urlCon.setDoOutput(true);
   1299                     urlCon.setUseCaches(false);
   1300                     urlCon.setAllowUserInteraction(false);
   1301 
   1302                     // When writing to a HTTP URI, a HTTP PUT is performed.
   1303                     if (urlCon instanceof HttpURLConnection) {
   1304                         HttpURLConnection httpCon = (HttpURLConnection) urlCon;
   1305                         httpCon.setRequestMethod("PUT");
   1306                     }
   1307                     urlOutStream = urlCon.getOutputStream();
   1308                 }
   1309                 // set the OutputStream to that obtained from the systemId
   1310                 serializer.setOutputStream(urlOutStream);
   1311             }
   1312 
   1313             // Get a reference to the serializer then lets you serilize a DOM
   1314             // Use this hack till Xalan support JAXP1.3
   1315             if (fDOMSerializer == null) {
   1316                 fDOMSerializer = (DOM3Serializer)serializer.asDOM3Serializer();
   1317             }
   1318 
   1319             // Set the error handler on the DOM3Serializer interface implementation
   1320             if (fDOMErrorHandler != null) {
   1321                 fDOMSerializer.setErrorHandler(fDOMErrorHandler);
   1322             }
   1323 
   1324             // Set the filter on the DOM3Serializer interface implementation
   1325             if (fSerializerFilter != null) {
   1326                 fDOMSerializer.setNodeFilter(fSerializerFilter);
   1327             }
   1328 
   1329             // Set the NewLine character to be used
   1330             fDOMSerializer.setNewLine(fEndOfLine.toCharArray());
   1331 
   1332             // Serializer your DOM, where node is an org.w3c.dom.Node
   1333             // Assuming that Xalan's serializer can serialize any type of DOM
   1334             // node
   1335             fDOMSerializer.serializeDOM3(nodeArg);
   1336 
   1337         } catch (LSException lse) {
   1338             // Rethrow LSException.
   1339             throw lse;
   1340         } catch (RuntimeException e) {
   1341             throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
   1342         }  catch (Exception e) {
   1343             if (fDOMErrorHandler != null) {
   1344                 fDOMErrorHandler.handleError(new DOMErrorImpl(
   1345                         DOMError.SEVERITY_FATAL_ERROR, e.getMessage(),
   1346                         null, e));
   1347             }
   1348             throw (LSException) createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
   1349         }
   1350 
   1351         return true;
   1352     }
   1353     // ************************************************************************
   1354 
   1355 
   1356     // ************************************************************************
   1357     // Implementaion methods
   1358     // ************************************************************************
   1359 
   1360     /**
   1361      * Determines the XML Version of the Document Node to serialize.  If the Document Node
   1362      * is not a DOM Level 3 Node, then the default version returned is 1.0.
   1363      *
   1364      * @param  nodeArg The Node to serialize
   1365      * @return A String containing the version pseudo-attribute of the XMLDecl.
   1366      * @throws Throwable if the DOM implementation does not implement Document.getXmlVersion()
   1367      */
   1368     //protected String getXMLVersion(Node nodeArg) throws Throwable {
   1369     protected String getXMLVersion(Node nodeArg) {
   1370         Document doc = null;
   1371 
   1372         // Determine the XML Version of the document
   1373         if (nodeArg != null) {
   1374             if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
   1375                 // The Document node is the Node argument
   1376                 doc = (Document)nodeArg;
   1377             } else {
   1378                 // The Document node is the Node argument's ownerDocument
   1379                 doc = nodeArg.getOwnerDocument();
   1380             }
   1381 
   1382             // Determine the DOM Version.
   1383             if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
   1384                 return doc.getXmlVersion();
   1385             }
   1386         }
   1387         // The version will be treated as "1.0" which may result in
   1388         // an ill-formed document being serialized.
   1389         // If nodeArg does not have an ownerDocument, treat this as XML 1.0
   1390         return "1.0";
   1391     }
   1392 
   1393     /**
   1394      * Determines the XML Encoding of the Document Node to serialize.  If the Document Node
   1395      * is not a DOM Level 3 Node, then the default encoding "UTF-8" is returned.
   1396      *
   1397      * @param  nodeArg The Node to serialize
   1398      * @return A String containing the encoding pseudo-attribute of the XMLDecl.
   1399      * @throws Throwable if the DOM implementation does not implement Document.getXmlEncoding()
   1400      */
   1401     protected String getXMLEncoding(Node nodeArg) {
   1402         Document doc = null;
   1403 
   1404         // Determine the XML Encoding of the document
   1405         if (nodeArg != null) {
   1406             if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
   1407                 // The Document node is the Node argument
   1408                 doc = (Document)nodeArg;
   1409             } else {
   1410                 // The Document node is the Node argument's ownerDocument
   1411                 doc = nodeArg.getOwnerDocument();
   1412             }
   1413 
   1414             // Determine the XML Version.
   1415             if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
   1416                 return doc.getXmlEncoding();
   1417             }
   1418         }
   1419         // The default encoding is UTF-8 except for the writeToString method
   1420         return "UTF-8";
   1421     }
   1422 
   1423     /**
   1424      * Determines the Input Encoding of the Document Node to serialize.  If the Document Node
   1425      * is not a DOM Level 3 Node, then null is returned.
   1426      *
   1427      * @param  nodeArg The Node to serialize
   1428      * @return A String containing the input encoding.
   1429      */
   1430     protected String getInputEncoding(Node nodeArg)  {
   1431         Document doc = null;
   1432 
   1433         // Determine the Input Encoding of the document
   1434         if (nodeArg != null) {
   1435             if (nodeArg.getNodeType() == Node.DOCUMENT_NODE) {
   1436                 // The Document node is the Node argument
   1437                 doc = (Document)nodeArg;
   1438             } else {
   1439                 // The Document node is the Node argument's ownerDocument
   1440                 doc = nodeArg.getOwnerDocument();
   1441             }
   1442 
   1443             // Determine the DOM Version.
   1444             if (doc != null && doc.getImplementation().hasFeature("Core","3.0")) {
   1445                 return doc.getInputEncoding();
   1446             }
   1447         }
   1448         // The default encoding returned is null
   1449         return null;
   1450     }
   1451 
   1452     /**
   1453      * This method returns the LSSerializer's error handler.
   1454      *
   1455      * @return Returns the fDOMErrorHandler.
   1456      */
   1457     public DOMErrorHandler getErrorHandler() {
   1458         return fDOMErrorHandler;
   1459     }
   1460 
   1461     /**
   1462      * Replaces all escape sequences in the given path with their literal characters.
   1463      */
   1464     private static String getPathWithoutEscapes(String origPath) {
   1465         if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) {
   1466             // Locate the escape characters
   1467             StringTokenizer tokenizer = new StringTokenizer(origPath, "%");
   1468             StringBuffer result = new StringBuffer(origPath.length());
   1469             int size = tokenizer.countTokens();
   1470             result.append(tokenizer.nextToken());
   1471             for(int i = 1; i < size; ++i) {
   1472                 String token = tokenizer.nextToken();
   1473                 if (token.length() >= 2 && isHexDigit(token.charAt(0)) &&
   1474                         isHexDigit(token.charAt(1))) {
   1475                     // Decode the 2 digit hexadecimal number following % in '%nn'
   1476                     result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue());
   1477                     token = token.substring(2);
   1478                 }
   1479                 result.append(token);
   1480             }
   1481             return result.toString();
   1482         }
   1483         return origPath;
   1484     }
   1485 
   1486     /**
   1487      * Returns true if the given character is a valid hex character.
   1488      */
   1489     private static boolean isHexDigit(char c) {
   1490         return (c >= '0' && c <= '9' ||
   1491                 c >= 'a' && c <= 'f' ||
   1492                 c >= 'A' && c <= 'F');
   1493     }
   1494 
   1495     /**
   1496      * Creates an LSException. On J2SE 1.4 and above the cause for the exception will be set.
   1497      */
   1498     private static LSException createLSException(short code, Throwable cause) {
   1499         LSException lse = new LSException(code, cause != null ? cause.getMessage() : null);
   1500         if (cause != null && ThrowableMethods.fgThrowableMethodsAvailable) {
   1501             try {
   1502                 ThrowableMethods.fgThrowableInitCauseMethod.invoke(lse, new Object [] {cause});
   1503             }
   1504             // Something went wrong. There's not much we can do about it.
   1505             catch (Exception e) {}
   1506         }
   1507         return lse;
   1508     }
   1509 
   1510     /**
   1511      * Holder of methods from java.lang.Throwable.
   1512      */
   1513     static class ThrowableMethods {
   1514 
   1515         // Method: java.lang.Throwable.initCause(java.lang.Throwable)
   1516         private static java.lang.reflect.Method fgThrowableInitCauseMethod = null;
   1517 
   1518         // Flag indicating whether or not Throwable methods available.
   1519         private static boolean fgThrowableMethodsAvailable = false;
   1520 
   1521         private ThrowableMethods() {}
   1522 
   1523         // Attempt to get methods for java.lang.Throwable on class initialization.
   1524         static {
   1525             try {
   1526                 fgThrowableInitCauseMethod = Throwable.class.getMethod("initCause", new Class [] {Throwable.class});
   1527                 fgThrowableMethodsAvailable = true;
   1528             }
   1529             // ClassNotFoundException, NoSuchMethodException or SecurityException
   1530             // Whatever the case, we cannot use java.lang.Throwable.initCause(java.lang.Throwable).
   1531             catch (Exception exc) {
   1532                 fgThrowableInitCauseMethod = null;
   1533                 fgThrowableMethodsAvailable = false;
   1534             }
   1535         }
   1536     }
   1537 }
   1538