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