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