1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xml.internal.serialize;
  22 
  23 import java.io.FileOutputStream;
  24 import java.io.IOException;
  25 import java.io.OutputStream;
  26 import java.io.StringWriter;
  27 import java.io.UnsupportedEncodingException;
  28 import java.io.Writer;
  29 import java.lang.reflect.Method;
  30 import java.net.HttpURLConnection;
  31 import java.net.URL;
  32 import java.net.URLConnection;
  33 import java.util.StringTokenizer;
  34 import java.util.Vector;
  35 
  36 import com.sun.org.apache.xerces.internal.dom.AbortException;
  37 import com.sun.org.apache.xerces.internal.dom.CoreDocumentImpl;
  38 import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl;
  39 import com.sun.org.apache.xerces.internal.dom.DOMLocatorImpl;
  40 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  41 import com.sun.org.apache.xerces.internal.dom.DOMNormalizer;
  42 import com.sun.org.apache.xerces.internal.dom.DOMStringListImpl;
  43 import org.w3c.dom.DOMConfiguration;
  44 import org.w3c.dom.DOMError;
  45 import org.w3c.dom.DOMErrorHandler;
  46 import org.w3c.dom.DOMStringList;
  47 import com.sun.org.apache.xerces.internal.impl.Constants;
  48 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  49 import com.sun.org.apache.xerces.internal.util.DOMUtil;
  50 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  51 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  52 import com.sun.org.apache.xerces.internal.util.XML11Char;
  53 import com.sun.org.apache.xerces.internal.util.XMLChar;
  54 import org.w3c.dom.Attr;
  55 import org.w3c.dom.Comment;
  56 import org.w3c.dom.DOMException;
  57 import org.w3c.dom.Document;
  58 import org.w3c.dom.DocumentFragment;
  59 import org.w3c.dom.Element;
  60 import org.w3c.dom.NamedNodeMap;
  61 import org.w3c.dom.Node;
  62 import org.w3c.dom.ProcessingInstruction;
  63 import org.w3c.dom.ls.LSException;
  64 import org.w3c.dom.ls.LSOutput;
  65 import org.w3c.dom.ls.LSSerializer;
  66 import org.w3c.dom.ls.LSSerializerFilter;
  67 
  68 
  69 /**
  70  * EXPERIMENTAL: Implemenatation of DOM Level 3 org.w3c.ls.LSSerializer  by delegating serialization
  71  * calls to <CODE>XMLSerializer</CODE>.
  72  * LSSerializer provides an API for serializing (writing) a DOM document out in an
  73  * XML document. The XML data is written to an output stream.
  74  * During serialization of XML data, namespace fixup is done when possible as
  75  * defined in DOM Level 3 Core, Appendix B.
  76  *
  77  * @author Elena Litani, IBM
  78  * @author Gopal Sharma, Sun Microsystems
  79  * @author Arun Yadav, Sun Microsystems
  80  * @author Sunitha Reddy, Sun Microsystems
  81  * @version $Id: DOMSerializerImpl.java,v 1.11 2010-11-01 04:40:36 joehw Exp $
  82  */
  83 public class DOMSerializerImpl implements LSSerializer, DOMConfiguration {
  84 
  85     // TODO: When DOM Level 3 goes to REC replace method calls using
  86     // reflection for: getXmlEncoding, getInputEncoding and getXmlEncoding
  87     // with regular static calls on the Document object.
  88 
  89     // data
  90     // serializer
  91     private XMLSerializer serializer;
  92 
  93     // XML 1.1 serializer
  94     private XML11Serializer xml11Serializer;
  95 
  96     //Recognized parameters
  97     private DOMStringList fRecognizedParameters;
  98 
  99     /** REVISIT: Currently we handle 3 different configurations, would be nice just have one configuration
 100      * that has different recognized parameters depending if it is used in Core/LS.
 101      */
 102     protected short features = 0;
 103 
 104     protected final static short NAMESPACES          = 0x1<<0;
 105     protected final static short WELLFORMED          = 0x1<<1;
 106     protected final static short ENTITIES            = 0x1<<2;
 107     protected final static short CDATA               = 0x1<<3;
 108     protected final static short SPLITCDATA          = 0x1<<4;
 109     protected final static short COMMENTS            = 0x1<<5;
 110     protected final static short DISCARDDEFAULT      = 0x1<<6;
 111     protected final static short INFOSET             = 0x1<<7;
 112     protected final static short XMLDECL             = 0x1<<8;
 113     protected final static short NSDECL              = 0x1<<9;
 114     protected final static short DOM_ELEMENT_CONTENT_WHITESPACE = 0x1<<10;
 115     protected final static short FORMAT_PRETTY_PRINT = 0x1<<11;
 116 
 117     // well-formness checking
 118     private DOMErrorHandler fErrorHandler = null;
 119     private final DOMErrorImpl fError = new DOMErrorImpl();
 120     private final DOMLocatorImpl fLocator = new DOMLocatorImpl();
 121 
 122     /**
 123      * Constructs a new LSSerializer.
 124      * The constructor turns on the namespace support in <code>XMLSerializer</code> and
 125      * initializes the following fields: fNSBinder, fLocalNSBinder, fSymbolTable,
 126      * fEmptySymbol, fXmlSymbol, fXmlnsSymbol, fNamespaceCounter, fFeatures.
 127      */
 128     public DOMSerializerImpl() {
 129         // set default features
 130         features |= NAMESPACES;
 131         features |= ENTITIES;
 132         features |= COMMENTS;
 133         features |= CDATA;
 134         features |= SPLITCDATA;
 135         features |= WELLFORMED;
 136         features |= NSDECL;
 137         features |= DOM_ELEMENT_CONTENT_WHITESPACE;
 138         features |= DISCARDDEFAULT;
 139         features |= XMLDECL;
 140 
 141         serializer = new XMLSerializer();
 142         initSerializer(serializer);
 143     }
 144 
 145 
 146 
 147     //
 148     // LSSerializer methods
 149     //
 150 
 151     public DOMConfiguration getDomConfig(){
 152         return this;
 153     }
 154 
 155     /** DOM L3-EXPERIMENTAL:
 156      * Setter for boolean and object parameters
 157      */
 158     public void setParameter(String name, Object value) throws DOMException {
 159         if (value instanceof Boolean) {
 160             boolean state = ((Boolean) value).booleanValue();
 161             if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){
 162                 if (state){
 163                     features &= ~ENTITIES;
 164                     features &= ~CDATA;
 165                     features |= NAMESPACES;
 166                     features |= NSDECL;
 167                     features |= WELLFORMED;
 168                     features |= COMMENTS;
 169                 }
 170                 // false does not have any effect
 171             } else if (name.equalsIgnoreCase(Constants.DOM_XMLDECL)) {
 172                 features =
 173                     (short) (state ? features | XMLDECL : features & ~XMLDECL);
 174             } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) {
 175                 features =
 176                     (short) (state
 177                         ? features | NAMESPACES
 178                         : features & ~NAMESPACES);
 179                 serializer.fNamespaces = state;
 180             } else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) {
 181                 features =
 182                     (short) (state
 183                         ? features | SPLITCDATA
 184                         : features & ~SPLITCDATA);
 185             } else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)) {
 186                 features =
 187                     (short) (state
 188                         ? features | DISCARDDEFAULT
 189                         : features & ~DISCARDDEFAULT);
 190             } else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) {
 191                 features =
 192                     (short) (state
 193                         ? features | WELLFORMED
 194                         : features & ~WELLFORMED);
 195             } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)){
 196                 features =
 197                     (short) (state
 198                         ? features | ENTITIES
 199                         : features & ~ENTITIES);
 200             }
 201             else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)){
 202                 features =
 203                     (short) (state
 204                         ? features | CDATA
 205                         : features & ~CDATA);
 206                         }
 207             else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)){
 208                 features =
 209                      (short) (state
 210                          ? features | COMMENTS
 211                          : features & ~COMMENTS);
 212             }
 213             else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)){
 214                 features =
 215                      (short) (state
 216                          ? features | FORMAT_PRETTY_PRINT
 217                          : features & ~FORMAT_PRETTY_PRINT);
 218             }
 219                 else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM)
 220                     || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA)
 221                     || name.equalsIgnoreCase(Constants.DOM_VALIDATE)
 222                     || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION)
 223                     || name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION)) {
 224                 //  || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) {
 225                 // true is not supported
 226                 if (state) {
 227                     String msg =
 228                         DOMMessageFormatter.formatMessage(
 229                             DOMMessageFormatter.DOM_DOMAIN,
 230                             "FEATURE_NOT_SUPPORTED",
 231                             new Object[] { name });
 232                     throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
 233                 }
 234             }else if (
 235                         name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) {
 236                                 //namespace-declaration has effect only if namespaces is true
 237                                 features =
 238                                         (short) (state
 239                                                 ? features | NSDECL
 240                                                 : features & ~NSDECL);
 241                                 serializer.fNamespacePrefixes = state;
 242             } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE)
 243                     || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
 244                 // false is not supported
 245                 if (!state) {
 246                     String msg =
 247                         DOMMessageFormatter.formatMessage(
 248                             DOMMessageFormatter.DOM_DOMAIN,
 249                             "FEATURE_NOT_SUPPORTED",
 250                             new Object[] { name });
 251                     throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
 252                 }
 253             } else {
 254                 String msg =
 255                     DOMMessageFormatter.formatMessage(
 256                         DOMMessageFormatter.DOM_DOMAIN,
 257                         "FEATURE_NOT_FOUND",
 258                         new Object[] { name });
 259                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
 260             }
 261         } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) {
 262             if (value == null || value instanceof DOMErrorHandler) {
 263                 fErrorHandler = (DOMErrorHandler)value;
 264             } else {
 265                 String msg =
 266                     DOMMessageFormatter.formatMessage(
 267                         DOMMessageFormatter.DOM_DOMAIN,
 268                         "TYPE_MISMATCH_ERR",
 269                         new Object[] { name });
 270                 throw new DOMException(DOMException.TYPE_MISMATCH_ERR, msg);
 271             }
 272         } else if (
 273             name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER)
 274                 || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION)
 275                 || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)
 276                 || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)
 277                 && value != null) {
 278             String msg =
 279                 DOMMessageFormatter.formatMessage(
 280                     DOMMessageFormatter.DOM_DOMAIN,
 281                     "FEATURE_NOT_SUPPORTED",
 282                     new Object[] { name });
 283             throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
 284         } else {
 285             String msg =
 286                 DOMMessageFormatter.formatMessage(
 287                     DOMMessageFormatter.DOM_DOMAIN,
 288                     "FEATURE_NOT_FOUND",
 289                     new Object[] { name });
 290             throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
 291         }
 292     }
 293 
 294     /** DOM L3-EXPERIMENTAL:
 295      * Check if parameter can be set
 296      */
 297     public boolean canSetParameter(String name, Object state) {
 298 
 299         if (state == null) {
 300             return true;
 301         }
 302 
 303         if (state instanceof Boolean) {
 304             boolean value = ((Boolean) state).booleanValue();
 305 
 306             if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)
 307                 || name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)
 308                 || name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)
 309                 || name.equalsIgnoreCase(Constants.DOM_XMLDECL)
 310                 || name.equalsIgnoreCase(Constants.DOM_WELLFORMED)
 311                 || name.equalsIgnoreCase(Constants.DOM_INFOSET)
 312                 || name.equalsIgnoreCase(Constants.DOM_ENTITIES)
 313                 || name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)
 314                 || name.equalsIgnoreCase(Constants.DOM_COMMENTS)
 315                 || name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)
 316                 || name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) {
 317                 // both values supported
 318                 return true;
 319             } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM)
 320                 || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA)
 321                 || name.equalsIgnoreCase(Constants.DOM_VALIDATE)
 322                 || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION)
 323                 || name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION)) {
 324                 // || name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)) {
 325                 // true is not supported
 326                 return !value;
 327             } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE)
 328                 || name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
 329                 // false is not supported
 330                 return value;
 331             }
 332         } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER) &&
 333             state == null || state instanceof DOMErrorHandler) {
 334             return true;
 335         }
 336 
 337         return false;
 338     }
 339 
 340     /**
 341      *  DOM Level 3 Core CR - Experimental.
 342      *
 343      *  The list of the parameters supported by this
 344      * <code>DOMConfiguration</code> object and for which at least one value
 345      * can be set by the application. Note that this list can also contain
 346      * parameter names defined outside this specification.
 347      */
 348     public DOMStringList getParameterNames() {
 349 
 350         if (fRecognizedParameters == null){
 351                         Vector parameters = new Vector();
 352 
 353                         //Add DOM recognized parameters
 354                         //REVISIT: Would have been nice to have a list of
 355                         //recognized parameters.
 356                         parameters.add(Constants.DOM_NAMESPACES);
 357                         parameters.add(Constants.DOM_SPLIT_CDATA);
 358                         parameters.add(Constants.DOM_DISCARD_DEFAULT_CONTENT);
 359                         parameters.add(Constants.DOM_XMLDECL);
 360                         parameters.add(Constants.DOM_CANONICAL_FORM);
 361                         parameters.add(Constants.DOM_VALIDATE_IF_SCHEMA);
 362                         parameters.add(Constants.DOM_VALIDATE);
 363                         parameters.add(Constants.DOM_CHECK_CHAR_NORMALIZATION);
 364                         parameters.add(Constants.DOM_DATATYPE_NORMALIZATION);
 365                         parameters.add(Constants.DOM_FORMAT_PRETTY_PRINT);
 366                         //parameters.add(Constants.DOM_NORMALIZE_CHARACTERS);
 367                         parameters.add(Constants.DOM_WELLFORMED);
 368                         parameters.add(Constants.DOM_INFOSET);
 369                         parameters.add(Constants.DOM_NAMESPACE_DECLARATIONS);
 370                         parameters.add(Constants.DOM_ELEMENT_CONTENT_WHITESPACE);
 371                         parameters.add(Constants.DOM_ENTITIES);
 372                         parameters.add(Constants.DOM_CDATA_SECTIONS);
 373                         parameters.add(Constants.DOM_COMMENTS);
 374                         parameters.add(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS);
 375                         parameters.add(Constants.DOM_ERROR_HANDLER);
 376                         //parameters.add(Constants.DOM_SCHEMA_LOCATION);
 377                         //parameters.add(Constants.DOM_SCHEMA_TYPE);
 378 
 379                         //Add recognized xerces features and properties
 380 
 381                         fRecognizedParameters = new DOMStringListImpl(parameters);
 382 
 383         }
 384 
 385         return fRecognizedParameters;
 386     }
 387 
 388     /** DOM L3-EXPERIMENTAL:
 389      * Getter for boolean and object parameters
 390      */
 391     public Object getParameter(String name) throws DOMException {
 392 
 393         if(name.equalsIgnoreCase(Constants.DOM_NORMALIZE_CHARACTERS)){
 394                       return null;
 395         } else if (name.equalsIgnoreCase(Constants.DOM_COMMENTS)) {
 396             return ((features & COMMENTS) != 0) ? Boolean.TRUE : Boolean.FALSE;
 397         } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACES)) {
 398             return (features & NAMESPACES) != 0 ? Boolean.TRUE : Boolean.FALSE;
 399         } else if (name.equalsIgnoreCase(Constants.DOM_XMLDECL)) {
 400             return (features & XMLDECL) != 0 ? Boolean.TRUE : Boolean.FALSE;
 401         } else if (name.equalsIgnoreCase(Constants.DOM_CDATA_SECTIONS)) {
 402             return (features & CDATA) != 0 ? Boolean.TRUE : Boolean.FALSE;
 403         } else if (name.equalsIgnoreCase(Constants.DOM_ENTITIES)) {
 404             return (features & ENTITIES) != 0 ? Boolean.TRUE : Boolean.FALSE;
 405         } else if (name.equalsIgnoreCase(Constants.DOM_SPLIT_CDATA)) {
 406             return (features & SPLITCDATA) != 0 ? Boolean.TRUE : Boolean.FALSE;
 407         } else if (name.equalsIgnoreCase(Constants.DOM_WELLFORMED)) {
 408             return (features & WELLFORMED) != 0 ? Boolean.TRUE : Boolean.FALSE;
 409         } else if (name.equalsIgnoreCase(Constants.DOM_NAMESPACE_DECLARATIONS)) {
 410             return (features & NSDECL) != 0 ? Boolean.TRUE : Boolean.FALSE;
 411         } else if (name.equalsIgnoreCase(Constants.DOM_FORMAT_PRETTY_PRINT)) {
 412             return (features & FORMAT_PRETTY_PRINT) != 0 ? Boolean.TRUE : Boolean.FALSE;
 413         } else if (name.equalsIgnoreCase(Constants.DOM_ELEMENT_CONTENT_WHITESPACE) ||
 414                    name.equalsIgnoreCase(Constants.DOM_IGNORE_UNKNOWN_CHARACTER_DENORMALIZATIONS)) {
 415             return Boolean.TRUE;
 416         }else if (name.equalsIgnoreCase(Constants.DOM_DISCARD_DEFAULT_CONTENT)){
 417             return ((features & DISCARDDEFAULT)!=0)?Boolean.TRUE:Boolean.FALSE;
 418         }else if (name.equalsIgnoreCase(Constants.DOM_INFOSET)){
 419             if ((features & ENTITIES) == 0 &&
 420                  (features & CDATA) == 0 &&
 421                  (features & NAMESPACES) != 0 &&
 422                  (features & NSDECL) != 0 &&
 423                  (features & WELLFORMED) != 0 &&
 424                  (features & COMMENTS) != 0) {
 425                      return Boolean.TRUE;
 426                  }
 427                  return Boolean.FALSE;
 428         } else if (name.equalsIgnoreCase(Constants.DOM_CANONICAL_FORM)
 429                 || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA)
 430                 || name.equalsIgnoreCase(Constants.DOM_CHECK_CHAR_NORMALIZATION)
 431                 || name.equalsIgnoreCase(Constants.DOM_VALIDATE)
 432                 || name.equalsIgnoreCase(Constants.DOM_VALIDATE_IF_SCHEMA)
 433                 || name.equalsIgnoreCase(Constants.DOM_DATATYPE_NORMALIZATION)) {
 434             return Boolean.FALSE;
 435         } else if (name.equalsIgnoreCase(Constants.DOM_ERROR_HANDLER)) {
 436             return fErrorHandler;
 437         } else if (
 438             name.equalsIgnoreCase(Constants.DOM_RESOURCE_RESOLVER)
 439                 || name.equalsIgnoreCase(Constants.DOM_SCHEMA_LOCATION)
 440                 || name.equalsIgnoreCase(Constants.DOM_SCHEMA_TYPE)) {
 441             String msg =
 442                 DOMMessageFormatter.formatMessage(
 443                     DOMMessageFormatter.DOM_DOMAIN,
 444                     "FEATURE_NOT_SUPPORTED",
 445                     new Object[] { name });
 446             throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
 447         } else {
 448             String msg =
 449                 DOMMessageFormatter.formatMessage(
 450                     DOMMessageFormatter.DOM_DOMAIN,
 451                     "FEATURE_NOT_FOUND",
 452                     new Object[] { name });
 453             throw new DOMException(DOMException.NOT_FOUND_ERR, msg);
 454         }
 455     }
 456 
 457 
 458     /**
 459      * DOM L3 EXPERIMENTAL:
 460      *  Serialize the specified node as described above in the description of
 461      * <code>LSSerializer</code>. The result of serializing the node is
 462      * returned as a string. Writing a Document or Entity node produces a
 463      * serialized form that is well formed XML. Writing other node types
 464      * produces a fragment of text in a form that is not fully defined by
 465      * this document, but that should be useful to a human for debugging or
 466      * diagnostic purposes.
 467      * @param wnode  The node to be written.
 468      * @return  Returns the serialized data
 469      * @exception DOMException
 470      *    DOMSTRING_SIZE_ERR: The resulting string is too long to fit in a
 471      *   <code>DOMString</code>.
 472      * @exception LSException
 473      *    SERIALIZE_ERR: Unable to serialize the node.  DOM applications should
 474      *    attach a <code>DOMErrorHandler</code> using the parameter
 475      *    &quot;<i>error-handler</i>&quot; to get details on error.
 476      */
 477     public String writeToString(Node wnode) throws DOMException, LSException {
 478         // determine which serializer to use:
 479         Document doc = (wnode.getNodeType() == Node.DOCUMENT_NODE)?(Document)wnode:wnode.getOwnerDocument();
 480         Method getVersion = null;
 481         XMLSerializer ser = null;
 482         String ver = null;
 483         // this should run under JDK 1.1.8...
 484         try {
 485             getVersion = doc.getClass().getMethod("getXmlVersion", new Class[]{});
 486             if(getVersion != null ) {
 487                 ver = (String)getVersion.invoke(doc, (Object[]) null);
 488             }
 489         } catch (Exception e) {
 490             // no way to test the version...
 491             // ignore the exception
 492         }
 493         if(ver != null && ver.equals("1.1")) {
 494             if(xml11Serializer == null) {
 495                 xml11Serializer = new XML11Serializer();
 496                 initSerializer(xml11Serializer);
 497             }
 498             // copy setting from "main" serializer to XML 1.1 serializer
 499             copySettings(serializer, xml11Serializer);
 500             ser = xml11Serializer;
 501         } else {
 502             ser = serializer;
 503         }
 504 
 505         StringWriter destination = new StringWriter();
 506         try {
 507             prepareForSerialization(ser, wnode);
 508             ser._format.setEncoding("UTF-16");
 509             ser.setOutputCharStream(destination);
 510             if (wnode.getNodeType() == Node.DOCUMENT_NODE) {
 511                 ser.serialize((Document)wnode);
 512             }
 513             else if (wnode.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE) {
 514                 ser.serialize((DocumentFragment)wnode);
 515             }
 516             else if (wnode.getNodeType() == Node.ELEMENT_NODE) {
 517                 ser.serialize((Element)wnode);
 518             }
 519             else if (wnode.getNodeType() == Node.TEXT_NODE ||
 520                     wnode.getNodeType() == Node.COMMENT_NODE ||
 521                     wnode.getNodeType() == Node.ENTITY_REFERENCE_NODE ||
 522                     wnode.getNodeType() == Node.CDATA_SECTION_NODE ||
 523                     wnode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) {
 524                 ser.serialize(wnode);
 525             }
 526             else {
 527                 String msg = DOMMessageFormatter.formatMessage(
 528                     DOMMessageFormatter.SERIALIZER_DOMAIN,
 529                     "unable-to-serialize-node", null);
 530                 if (ser.fDOMErrorHandler != null) {
 531                     DOMErrorImpl error = new DOMErrorImpl();
 532                     error.fType = "unable-to-serialize-node";
 533                     error.fMessage = msg;
 534                     error.fSeverity = DOMError.SEVERITY_FATAL_ERROR;
 535                     ser.fDOMErrorHandler.handleError(error);
 536                 }
 537                 throw new LSException(LSException.SERIALIZE_ERR, msg);
 538             }
 539         } catch (LSException lse) {
 540             // Rethrow LSException.
 541             throw lse;
 542         } catch (AbortException e) {
 543             return null;
 544         } catch (RuntimeException e) {
 545             throw (LSException) new LSException(LSException.SERIALIZE_ERR, e.toString()).initCause(e);
 546         } catch (IOException ioe) {
 547             // REVISIT: A generic IOException doesn't provide enough information
 548             // to determine that the serialized document is too large to fit
 549             // into a string. This could have thrown for some other reason. -- mrglavas
 550             String msg = DOMMessageFormatter.formatMessage(
 551                 DOMMessageFormatter.DOM_DOMAIN,
 552                 "STRING_TOO_LONG",
 553                 new Object[] { ioe.getMessage()});
 554             throw (DOMException) new DOMException(DOMException.DOMSTRING_SIZE_ERR, msg).initCause(ioe);
 555         }
 556 
 557         return destination.toString();
 558     }
 559 
 560     /**
 561      * DOM L3 EXPERIMENTAL:
 562      * The end-of-line sequence of characters to be used in the XML being
 563      * written out. The only permitted values are these:
 564      * <dl>
 565      * <dt><code>null</code></dt>
 566      * <dd>
 567      * Use a default end-of-line sequence. DOM implementations should choose
 568      * the default to match the usual convention for text files in the
 569      * environment being used. Implementations must choose a default
 570      * sequence that matches one of those allowed by  2.11 "End-of-Line
 571      * Handling". </dd>
 572      * <dt>CR</dt>
 573      * <dd>The carriage-return character (#xD).</dd>
 574      * <dt>CR-LF</dt>
 575      * <dd> The
 576      * carriage-return and line-feed characters (#xD #xA). </dd>
 577      * <dt>LF</dt>
 578      * <dd> The line-feed
 579      * character (#xA). </dd>
 580      * </dl>
 581      * <br>The default value for this attribute is <code>null</code>.
 582      */
 583     public void setNewLine(String newLine) {
 584         serializer._format.setLineSeparator(newLine);
 585     }
 586 
 587 
 588     /**
 589      * DOM L3 EXPERIMENTAL:
 590      * The end-of-line sequence of characters to be used in the XML being
 591      * written out. The only permitted values are these:
 592      * <dl>
 593      * <dt><code>null</code></dt>
 594      * <dd>
 595      * Use a default end-of-line sequence. DOM implementations should choose
 596      * the default to match the usual convention for text files in the
 597      * environment being used. Implementations must choose a default
 598      * sequence that matches one of those allowed by  2.11 "End-of-Line
 599      * Handling". </dd>
 600      * <dt>CR</dt>
 601      * <dd>The carriage-return character (#xD).</dd>
 602      * <dt>CR-LF</dt>
 603      * <dd> The
 604      * carriage-return and line-feed characters (#xD #xA). </dd>
 605      * <dt>LF</dt>
 606      * <dd> The line-feed
 607      * character (#xA). </dd>
 608      * </dl>
 609      * <br>The default value for this attribute is <code>null</code>.
 610      */
 611     public String getNewLine() {
 612         return serializer._format.getLineSeparator();
 613     }
 614 
 615 
 616     /**
 617      *  When the application provides a filter, the serializer will call out
 618      * to the filter before serializing each Node. Attribute nodes are never
 619      * passed to the filter. The filter implementation can choose to remove
 620      * the node from the stream or to terminate the serialization early.
 621      */
 622     public LSSerializerFilter getFilter(){
 623         return serializer.fDOMFilter;
 624     }
 625     /**
 626      *  When the application provides a filter, the serializer will call out
 627      * to the filter before serializing each Node. Attribute nodes are never
 628      * passed to the filter. The filter implementation can choose to remove
 629      * the node from the stream or to terminate the serialization early.
 630      */
 631     public void setFilter(LSSerializerFilter filter){
 632         serializer.fDOMFilter = filter;
 633     }
 634 
 635     // this initializes a newly-created serializer
 636     private void initSerializer(XMLSerializer ser) {
 637         ser.fNSBinder = new NamespaceSupport();
 638         ser.fLocalNSBinder = new NamespaceSupport();
 639         ser.fSymbolTable = new SymbolTable();
 640     }
 641 
 642     // copies all settings that could have been modified
 643     // by calls to LSSerializer methods from one serializer to another.
 644     // IMPORTANT:  if new methods are implemented or more settings of
 645     // the serializer are made alterable, this must be
 646     // reflected in this method!
 647     private void copySettings(XMLSerializer src, XMLSerializer dest) {
 648         dest.fDOMErrorHandler = fErrorHandler;
 649         dest._format.setEncoding(src._format.getEncoding());
 650         dest._format.setLineSeparator(src._format.getLineSeparator());
 651         dest.fDOMFilter = src.fDOMFilter;
 652     }//copysettings
 653 
 654     /**
 655       *  Serialize the specified node as described above in the general
 656       * description of the <code>LSSerializer</code> interface. The output
 657       * is written to the supplied <code>LSOutput</code>.
 658       * <br> When writing to a <code>LSOutput</code>, the encoding is found by
 659       * looking at the encoding information that is reachable through the
 660       * <code>LSOutput</code> and the item to be written (or its owner
 661       * document) in this order:
 662       * <ol>
 663       * <li> <code>LSOutput.encoding</code>,
 664       * </li>
 665       * <li>
 666       * <code>Document.actualEncoding</code>,
 667       * </li>
 668       * <li>
 669       * <code>Document.xmlEncoding</code>.
 670       * </li>
 671       * </ol>
 672       * <br> If no encoding is reachable through the above properties, a
 673       * default encoding of "UTF-8" will be used.
 674       * <br> If the specified encoding is not supported an
 675       * "unsupported-encoding" error is raised.
 676       * <br> If no output is specified in the <code>LSOutput</code>, a
 677       * "no-output-specified" error is raised.
 678       * @param node  The node to serialize.
 679       * @param destination The destination for the serialized DOM.
 680       * @return  Returns <code>true</code> if <code>node</code> was
 681       *   successfully serialized and <code>false</code> in case the node
 682       *   couldn't be serialized.
 683       */
 684     public boolean write(Node node, LSOutput destination) throws LSException{
 685 
 686         if (node == null)
 687             return false;
 688 
 689         Method getVersion = null;
 690         XMLSerializer ser = null;
 691         String ver = null;
 692         Document fDocument =(node.getNodeType() == Node.DOCUMENT_NODE)
 693                 ? (Document) node
 694                 : node.getOwnerDocument();
 695         // this should run under JDK 1.1.8...
 696         try {
 697             getVersion = fDocument.getClass().getMethod("getXmlVersion", new Class[] {});
 698             if (getVersion != null) {
 699                 ver = (String) getVersion.invoke(fDocument, (Object[]) null);
 700             }
 701         } catch (Exception e) {
 702             //no way to test the version...
 703             //ignore the exception
 704         }
 705         //determine which serializer to use:
 706         if (ver != null && ver.equals("1.1")) {
 707             if (xml11Serializer == null) {
 708                 xml11Serializer = new XML11Serializer();
 709                 initSerializer(xml11Serializer);
 710             }
 711             //copy setting from "main" serializer to XML 1.1 serializer
 712             copySettings(serializer, xml11Serializer);
 713             ser = xml11Serializer;
 714         } else {
 715             ser = serializer;
 716         }
 717 
 718         String encoding = null;
 719         if ((encoding = destination.getEncoding()) == null) {
 720             try {
 721                 Method getEncoding =
 722                     fDocument.getClass().getMethod("getInputEncoding", new Class[] {});
 723                 if (getEncoding != null) {
 724                     encoding = (String) getEncoding.invoke(fDocument, (Object[]) null);
 725                 }
 726             } catch (Exception e) {
 727                 // ignore the exception
 728             }
 729             if (encoding == null) {
 730                 try {
 731                     Method getEncoding =
 732                         fDocument.getClass().getMethod("getXmlEncoding", new Class[] {});
 733                     if (getEncoding != null) {
 734                         encoding = (String) getEncoding.invoke(fDocument, (Object[]) null);
 735                     }
 736                 } catch (Exception e) {
 737                     // ignore the exception
 738                 }
 739                 if (encoding == null) {
 740                     encoding = "UTF-8";
 741                 }
 742             }
 743         }
 744         try {
 745             prepareForSerialization(ser, node);
 746             ser._format.setEncoding(encoding);
 747             OutputStream outputStream = destination.getByteStream();
 748             Writer writer = destination.getCharacterStream();
 749             String uri =  destination.getSystemId();
 750             if (writer == null) {
 751                 if (outputStream == null) {
 752                     if (uri == null) {
 753                         String msg = DOMMessageFormatter.formatMessage(
 754                             DOMMessageFormatter.SERIALIZER_DOMAIN,
 755                             "no-output-specified", null);
 756                         if (ser.fDOMErrorHandler != null) {
 757                             DOMErrorImpl error = new DOMErrorImpl();
 758                             error.fType = "no-output-specified";
 759                             error.fMessage = msg;
 760                             error.fSeverity = DOMError.SEVERITY_FATAL_ERROR;
 761                             ser.fDOMErrorHandler.handleError(error);
 762                         }
 763                         throw new LSException(LSException.SERIALIZE_ERR, msg);
 764                     }
 765                     else {
 766                         // URI was specified. Handle relative URIs.
 767                         String expanded = XMLEntityManager.expandSystemId(uri, null, true);
 768                         URL url = new URL(expanded != null ? expanded : uri);
 769                         OutputStream out = null;
 770                         String protocol = url.getProtocol();
 771                         String host = url.getHost();
 772                         // Use FileOutputStream if this URI is for a local file.
 773                         if (protocol.equals("file")
 774                             && (host == null || host.length() == 0 || host.equals("localhost"))) {
 775                             out = new FileOutputStream(getPathWithoutEscapes(url.getFile()));
 776                         }
 777                         // Try to write to some other kind of URI. Some protocols
 778                         // won't support this, though HTTP should work.
 779                         else {
 780                             URLConnection urlCon = url.openConnection();
 781                             urlCon.setDoInput(false);
 782                             urlCon.setDoOutput(true);
 783                             urlCon.setUseCaches(false); // Enable tunneling.
 784                             if (urlCon instanceof HttpURLConnection) {
 785                                 // The DOM L3 LS CR says if we are writing to an HTTP URI
 786                                 // it is to be done with an HTTP PUT.
 787                                 HttpURLConnection httpCon = (HttpURLConnection) urlCon;
 788                                 httpCon.setRequestMethod("PUT");
 789                             }
 790                             out = urlCon.getOutputStream();
 791                         }
 792                         ser.setOutputByteStream(out);
 793                     }
 794                 }
 795                 else {
 796                     // byte stream was specified
 797                     ser.setOutputByteStream(outputStream);
 798                 }
 799             }
 800             else {
 801                 // character stream is specified
 802                 ser.setOutputCharStream(writer);
 803             }
 804 
 805             if (node.getNodeType() == Node.DOCUMENT_NODE)
 806                 ser.serialize((Document) node);
 807             else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE)
 808                 ser.serialize((DocumentFragment) node);
 809             else if (node.getNodeType() == Node.ELEMENT_NODE)
 810                 ser.serialize((Element) node);
 811             else if (node.getNodeType() == Node.TEXT_NODE ||
 812                     node.getNodeType() == Node.COMMENT_NODE ||
 813                     node.getNodeType() == Node.ENTITY_REFERENCE_NODE ||
 814                     node.getNodeType() == Node.CDATA_SECTION_NODE ||
 815                     node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) {
 816                 ser.serialize(node);
 817             }
 818             else
 819                 return false;
 820         } catch( UnsupportedEncodingException ue) {
 821             if (ser.fDOMErrorHandler != null) {
 822                 DOMErrorImpl error = new DOMErrorImpl();
 823                 error.fException = ue;
 824                                 error.fType = "unsupported-encoding";
 825                 error.fMessage = ue.getMessage();
 826                                 error.fSeverity = DOMError.SEVERITY_FATAL_ERROR;
 827                 ser.fDOMErrorHandler.handleError(error);
 828                         }
 829             throw new LSException(LSException.SERIALIZE_ERR,
 830                 DOMMessageFormatter.formatMessage(
 831                     DOMMessageFormatter.SERIALIZER_DOMAIN,
 832                     "unsupported-encoding", null));
 833                         //return false;
 834         } catch (LSException lse) {
 835             // Rethrow LSException.
 836             throw lse;
 837         } catch (AbortException e) {
 838             return false;
 839         } catch (RuntimeException e) {
 840             throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
 841         } catch (Exception e) {
 842             if (ser.fDOMErrorHandler != null) {
 843                 DOMErrorImpl error = new DOMErrorImpl();
 844                 error.fException = e;
 845                 error.fMessage = e.getMessage();
 846                 error.fSeverity = DOMError.SEVERITY_ERROR;
 847                 ser.fDOMErrorHandler.handleError(error);
 848 
 849             }
 850             throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
 851         }
 852         return true;
 853 
 854     } //write
 855 
 856     /**
 857       *  Serialize the specified node as described above in the general
 858       * description of the <code>LSSerializer</code> interface. The output
 859       * is written to the supplied URI.
 860       * <br> When writing to a URI, the encoding is found by looking at the
 861       * encoding information that is reachable through the item to be written
 862       * (or its owner document) in this order:
 863       * <ol>
 864       * <li>
 865       * <code>Document.inputEncoding</code>,
 866       * </li>
 867       * <li>
 868       * <code>Document.xmlEncoding</code>.
 869       * </li>
 870       * </ol>
 871       * <br> If no encoding is reachable through the above properties, a
 872       * default encoding of "UTF-8" will be used.
 873       * <br> If the specified encoding is not supported an
 874       * "unsupported-encoding" error is raised.
 875       * @param node  The node to serialize.
 876       * @param URI The URI to write to.
 877       * @return  Returns <code>true</code> if <code>node</code> was
 878       *   successfully serialized and <code>false</code> in case the node
 879       *   couldn't be serialized.
 880       */
 881     public boolean writeToURI(Node node, String URI) throws LSException{
 882         if (node == null){
 883             return false;
 884         }
 885 
 886         Method getXmlVersion = null;
 887         XMLSerializer ser = null;
 888         String ver = null;
 889         String encoding = null;
 890 
 891         Document fDocument =(node.getNodeType() == Node.DOCUMENT_NODE)
 892                 ? (Document) node
 893                 : node.getOwnerDocument();
 894         // this should run under JDK 1.1.8...
 895         try {
 896             getXmlVersion =
 897                 fDocument.getClass().getMethod("getXmlVersion", new Class[] {});
 898             if (getXmlVersion != null) {
 899                 ver = (String) getXmlVersion.invoke(fDocument, (Object[]) null);
 900             }
 901         } catch (Exception e) {
 902             // no way to test the version...
 903             // ignore the exception
 904         }
 905         if (ver != null && ver.equals("1.1")) {
 906             if (xml11Serializer == null) {
 907                 xml11Serializer = new XML11Serializer();
 908                 initSerializer(xml11Serializer);
 909             }
 910             // copy setting from "main" serializer to XML 1.1 serializer
 911             copySettings(serializer, xml11Serializer);
 912             ser = xml11Serializer;
 913         } else {
 914             ser = serializer;
 915         }
 916 
 917         try {
 918             Method getEncoding =
 919                 fDocument.getClass().getMethod("getInputEncoding", new Class[] {});
 920             if (getEncoding != null) {
 921                 encoding = (String) getEncoding.invoke(fDocument, (Object[]) null);
 922             }
 923         } catch (Exception e) {
 924             // ignore the exception
 925         }
 926         if (encoding == null) {
 927             try {
 928                 Method getEncoding =
 929                     fDocument.getClass().getMethod("getXmlEncoding", new Class[] {});
 930                 if (getEncoding != null) {
 931                     encoding = (String) getEncoding.invoke(fDocument, (Object[]) null);
 932                 }
 933             } catch (Exception e) {
 934                 // ignore the exception
 935             }
 936             if (encoding == null) {
 937                 encoding = "UTF-8";
 938             }
 939         }
 940 
 941         try {
 942             prepareForSerialization(ser, node);
 943             ser._format.setEncoding(encoding);
 944 
 945             // URI was specified. Handle relative URIs.
 946             String expanded = XMLEntityManager.expandSystemId(URI, null, true);
 947             URL url = new URL(expanded != null ? expanded : URI);
 948             OutputStream out = null;
 949             String protocol = url.getProtocol();
 950             String host = url.getHost();
 951             // Use FileOutputStream if this URI is for a local file.
 952             if (protocol.equals("file")
 953                 && (host == null || host.length() == 0 || host.equals("localhost"))) {
 954                 out = new FileOutputStream(getPathWithoutEscapes(url.getFile()));
 955             }
 956             // Try to write to some other kind of URI. Some protocols
 957             // won't support this, though HTTP should work.
 958             else {
 959                 URLConnection urlCon = url.openConnection();
 960                 urlCon.setDoInput(false);
 961                 urlCon.setDoOutput(true);
 962                 urlCon.setUseCaches(false); // Enable tunneling.
 963                 if (urlCon instanceof HttpURLConnection) {
 964                     // The DOM L3 LS CR says if we are writing to an HTTP URI
 965                     // it is to be done with an HTTP PUT.
 966                     HttpURLConnection httpCon = (HttpURLConnection) urlCon;
 967                     httpCon.setRequestMethod("PUT");
 968                 }
 969                 out = urlCon.getOutputStream();
 970             }
 971             ser.setOutputByteStream(out);
 972 
 973             if (node.getNodeType() == Node.DOCUMENT_NODE)
 974                 ser.serialize((Document) node);
 975             else if (node.getNodeType() == Node.DOCUMENT_FRAGMENT_NODE)
 976                 ser.serialize((DocumentFragment) node);
 977             else if (node.getNodeType() == Node.ELEMENT_NODE)
 978                 ser.serialize((Element) node);
 979             else if (node.getNodeType() == Node.TEXT_NODE ||
 980                     node.getNodeType() == Node.COMMENT_NODE ||
 981                     node.getNodeType() == Node.ENTITY_REFERENCE_NODE ||
 982                     node.getNodeType() == Node.CDATA_SECTION_NODE ||
 983                     node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE ) {
 984                 ser.serialize(node);
 985             }
 986             else
 987                 return false;
 988         } catch (LSException lse) {
 989             // Rethrow LSException.
 990             throw lse;
 991         } catch (AbortException e) {
 992             return false;
 993         } catch (RuntimeException e) {
 994             throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
 995         } catch (Exception e) {
 996             if (ser.fDOMErrorHandler != null) {
 997                 DOMErrorImpl error = new DOMErrorImpl();
 998                 error.fException = e;
 999                 error.fMessage = e.getMessage();
1000                 error.fSeverity = DOMError.SEVERITY_ERROR;
1001                 ser.fDOMErrorHandler.handleError(error);
1002             }
1003             throw (LSException) DOMUtil.createLSException(LSException.SERIALIZE_ERR, e).fillInStackTrace();
1004         }
1005         return true;
1006     } //writeURI
1007 
1008 
1009     //
1010     //  Private methods
1011     //
1012 
1013     private void prepareForSerialization(XMLSerializer ser, Node node) {
1014         ser.reset();
1015         ser.features = features;
1016         ser.fDOMErrorHandler = fErrorHandler;
1017         ser.fNamespaces = (features & NAMESPACES) != 0;
1018         ser.fNamespacePrefixes = (features & NSDECL) != 0;
1019         ser._format.setOmitComments((features & COMMENTS)==0);
1020         ser._format.setOmitXMLDeclaration((features & XMLDECL) == 0);
1021         ser._format.setIndenting((features & FORMAT_PRETTY_PRINT) != 0);
1022 
1023         if ((features & WELLFORMED) != 0) {
1024             // REVISIT: this is inefficient implementation of well-formness. Instead, we should check
1025             // well-formness as we serialize the tree
1026             Node next, root;
1027             root = node;
1028             Method versionChanged;
1029             boolean verifyNames = true;
1030             Document document =(node.getNodeType() == Node.DOCUMENT_NODE)
1031                     ? (Document) node
1032                     : node.getOwnerDocument();
1033             try {
1034                 versionChanged = document.getClass().getMethod("isXMLVersionChanged()", new Class[] {});
1035                 if (versionChanged != null) {
1036                     verifyNames = ((Boolean)versionChanged.invoke(document, (Object[]) null)).booleanValue();
1037                 }
1038             } catch (Exception e) {
1039                 //no way to test the version...
1040                 //ignore the exception
1041             }
1042             if (node.getFirstChild() != null) {
1043                 while (node != null) {
1044                     verify(node, verifyNames, false);
1045                     // Move down to first child
1046                     next = node.getFirstChild();
1047                     // No child nodes, so walk tree
1048                     while (next == null) {
1049                       // Move to sibling if possible.
1050                       next = node.getNextSibling();
1051                       if (next == null) {
1052                           node = node.getParentNode();
1053                           if (root == node){
1054                               next = null;
1055                               break;
1056                           }
1057                           next = node.getNextSibling();
1058                       }
1059                     }
1060                     node = next;
1061                 }
1062             }
1063             else {
1064                 verify(node, verifyNames, false);
1065             }
1066         }
1067     }
1068 
1069 
1070     private void verify (Node node, boolean verifyNames, boolean xml11Version){
1071 
1072         int type = node.getNodeType();
1073         fLocator.fRelatedNode = node;
1074         boolean wellformed;
1075         switch (type) {
1076             case Node.DOCUMENT_NODE:{
1077                 break;
1078             }
1079             case Node.DOCUMENT_TYPE_NODE:{
1080                 break;
1081             }
1082             case Node.ELEMENT_NODE:{
1083                 if (verifyNames){
1084                     if((features & NAMESPACES) != 0){
1085                         wellformed = CoreDocumentImpl.isValidQName(node.getPrefix() , node.getLocalName(), xml11Version) ;
1086                     }
1087                     else{
1088                         wellformed = CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version);
1089                     }
1090                     if (!wellformed){
1091                             if (!wellformed){
1092                                 if (fErrorHandler != null) {
1093                                     String msg = DOMMessageFormatter.formatMessage(
1094                                         DOMMessageFormatter.DOM_DOMAIN,
1095                                         "wf-invalid-character-in-node-name",
1096                                         new Object[]{"Element", node.getNodeName()});
1097                                         DOMNormalizer.reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR,
1098                                         "wf-invalid-character-in-node-name");
1099                                 }
1100 
1101                             }
1102                     }
1103                 }
1104 
1105                 NamedNodeMap attributes = (node.hasAttributes()) ? node.getAttributes() : null;
1106                 if (attributes != null) {
1107                     for (int i = 0; i < attributes.getLength(); ++i) {
1108                         Attr attr = (Attr) attributes.item(i);
1109                         fLocator.fRelatedNode = attr;
1110                         DOMNormalizer.isAttrValueWF( fErrorHandler, fError, fLocator,
1111                                       attributes, attr, attr.getValue(), xml11Version);
1112                         if (verifyNames) {
1113                             wellformed = CoreDocumentImpl.isXMLName( attr.getNodeName(), xml11Version);
1114                             if (!wellformed) {
1115                                     String msg =
1116                                         DOMMessageFormatter.formatMessage(
1117                                             DOMMessageFormatter.DOM_DOMAIN,
1118                                             "wf-invalid-character-in-node-name",
1119                                             new Object[] { "Attr", node.getNodeName()});
1120                                     DOMNormalizer.reportDOMError( fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR,
1121                                         "wf-invalid-character-in-node-name");
1122                             }
1123                         }
1124                     }
1125 
1126                 }
1127 
1128                 break;
1129             }
1130 
1131         case Node.COMMENT_NODE: {
1132             // only verify well-formness if comments included in the tree
1133             if ((features & COMMENTS) != 0)
1134                 DOMNormalizer.isCommentWF(fErrorHandler, fError, fLocator, ((Comment)node).getData(), xml11Version);
1135             break;
1136         }
1137         case Node.ENTITY_REFERENCE_NODE: {
1138             // only if entity is preserved in the tree
1139             if (verifyNames && (features & ENTITIES) != 0){
1140                 CoreDocumentImpl.isXMLName(node.getNodeName() , xml11Version);
1141             }
1142             break;
1143 
1144         }
1145         case Node.CDATA_SECTION_NODE: {
1146             // verify content
1147             DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version);
1148             // the ]]> string will be checked during serialization
1149             break;
1150         }
1151         case Node.TEXT_NODE:{
1152             DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), xml11Version);
1153             break;
1154         }
1155         case Node.PROCESSING_INSTRUCTION_NODE:{
1156             ProcessingInstruction pinode = (ProcessingInstruction)node ;
1157             String target = pinode.getTarget();
1158             if (verifyNames) {
1159                 if (xml11Version) {
1160                     wellformed = XML11Char.isXML11ValidName(target);
1161                 } else {
1162                     wellformed = XMLChar.isValidName(target);
1163                 }
1164 
1165                 if (!wellformed) {
1166                     String msg =
1167                         DOMMessageFormatter.formatMessage(
1168                             DOMMessageFormatter.DOM_DOMAIN,
1169                             "wf-invalid-character-in-node-name",
1170                             new Object[] { "Element", node.getNodeName()});
1171                     DOMNormalizer.reportDOMError(
1172                         fErrorHandler,
1173                         fError,
1174                         fLocator,
1175                         msg,
1176                         DOMError.SEVERITY_FATAL_ERROR,
1177                         "wf-invalid-character-in-node-name");
1178                 }
1179             }
1180             DOMNormalizer.isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), xml11Version);
1181             break;
1182         }
1183         }
1184 
1185     }
1186 
1187     private String getPathWithoutEscapes(String origPath) {
1188         if (origPath != null && origPath.length() != 0 && origPath.indexOf('%') != -1) {
1189             // Locate the escape characters
1190             StringTokenizer tokenizer = new StringTokenizer(origPath, "%");
1191             StringBuffer result = new StringBuffer(origPath.length());
1192             int size = tokenizer.countTokens();
1193             result.append(tokenizer.nextToken());
1194             for(int i = 1; i < size; ++i) {
1195                 String token = tokenizer.nextToken();
1196                 // Decode the 2 digit hexadecimal number following % in '%nn'
1197                 result.append((char)Integer.valueOf(token.substring(0, 2), 16).intValue());
1198                 result.append(token.substring(2));
1199             }
1200             return result.toString();
1201         }
1202         return origPath;
1203     }
1204 
1205 }//DOMSerializerImpl