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