• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
LSSerializerImpl()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      */
initializeSerializerProps()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      */
canSetParameter(String name, Object value)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      */
getParameter(String name)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      */
getParameterNames()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      */
setParameter(String name, Object value)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      */
getDomConfig()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      */
getFilter()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      */
getNewLine()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      */
setFilter(LSSerializerFilter filter)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      */
setNewLine(String newLine)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      */
write(Node nodeArg, LSOutput destination)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      */
writeToString(Node nodeArg)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      */
writeToURI(Node nodeArg, String uri)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 {
getXMLVersion(Node nodeArg)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      */
getXMLEncoding(Node nodeArg)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      */
getInputEncoding(Node nodeArg)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      */
getErrorHandler()1457     public DOMErrorHandler getErrorHandler() {
1458         return fDOMErrorHandler;
1459     }
1460 
1461     /**
1462      * Replaces all escape sequences in the given path with their literal characters.
1463      */
getPathWithoutEscapes(String origPath)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      */
isHexDigit(char c)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      */
createLSException(short code, Throwable cause)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 
ThrowableMethods()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