1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Nov 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.dom;
  23 
  24 
  25 
  26 import com.sun.org.apache.xerces.internal.dom.AbortException;
  27 import com.sun.org.apache.xerces.internal.impl.Constants;
  28 import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
  29 import com.sun.org.apache.xerces.internal.impl.dtd.DTDGrammar;
  30 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDDescription;
  31 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator;
  32 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  33 import com.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator;
  34 import com.sun.org.apache.xerces.internal.parsers.XMLGrammarPreparser;
  35 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
  36 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  37 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  38 import com.sun.org.apache.xerces.internal.util.XML11Char;
  39 import com.sun.org.apache.xerces.internal.util.XMLChar;
  40 import com.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl;
  41 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  42 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  43 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  44 import com.sun.org.apache.xerces.internal.xni.QName;
  45 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  46 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  47 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  48 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  49 import com.sun.org.apache.xerces.internal.xni.XMLString;
  50 import com.sun.org.apache.xerces.internal.xni.XNIException;
  51 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  52 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  53 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  54 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  55 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  56 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  57 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  58 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  59 import java.io.IOException;
  60 import java.io.StringReader;
  61 import java.util.ArrayList;
  62 import java.util.List;
  63 import java.util.Vector;
  64 import org.w3c.dom.Attr;
  65 import org.w3c.dom.Comment;
  66 import org.w3c.dom.DOMError;
  67 import org.w3c.dom.DOMErrorHandler;
  68 import org.w3c.dom.Document;
  69 import org.w3c.dom.DocumentType;
  70 import org.w3c.dom.Element;
  71 import org.w3c.dom.Entity;
  72 import org.w3c.dom.NamedNodeMap;
  73 import org.w3c.dom.Node;
  74 import org.w3c.dom.NodeList;
  75 import org.w3c.dom.ProcessingInstruction;
  76 import org.w3c.dom.Text;
  77 /**
  78  * This class adds implementation for normalizeDocument method.
  79  * It acts as if the document was going through a save and load cycle, putting
  80  * the document in a "normal" form. The actual result depends on the features being set
  81  * and governing what operations actually take place. See setNormalizationFeature for details.
  82  * Noticeably this method normalizes Text nodes, makes the document "namespace wellformed",
  83  * according to the algorithm described below in pseudo code, by adding missing namespace
  84  * declaration attributes and adding or changing namespace prefixes, updates the replacement
  85  * tree of EntityReference nodes, normalizes attribute values, etc.
  86  * Mutation events, when supported, are generated to reflect the changes occuring on the
  87  * document.
  88  * See Namespace normalization for details on how namespace declaration attributes and prefixes
  89  * are normalized.
  90  *
  91  * NOTE: There is an initial support for DOM revalidation with XML Schema as a grammar.
  92  * The tree might not be validated correctly if entityReferences, CDATA sections are
  93  * present in the tree. The PSVI information is not exposed, normalized data (including element
  94  * default content is not available).
  95  *
  96  * @xerces.experimental
  97  *
  98  * @author Elena Litani, IBM
  99  * @author Neeraj Bajaj, Sun Microsystems, inc.
 100  */
 101 public class DOMNormalizer implements XMLDocumentHandler {
 102 
 103     //
 104     // constants
 105     //
 106     /** Debug normalize document*/
 107     protected final static boolean DEBUG_ND = false;
 108     /** Debug namespace fix up algorithm*/
 109     protected final static boolean DEBUG = false;
 110     /** Debug document handler events */
 111     protected final static boolean DEBUG_EVENTS = false;
 112 
 113     /** prefix added by namespace fixup algorithm should follow a pattern "NS" + index*/
 114     protected final static String PREFIX = "NS";
 115 
 116     //
 117     // Data
 118     //
 119     protected DOMConfigurationImpl fConfiguration = null;
 120     protected CoreDocumentImpl fDocument = null;
 121     protected final XMLAttributesProxy fAttrProxy = new XMLAttributesProxy();
 122     protected final QName fQName = new QName();
 123 
 124     /** Validation handler represents validator instance. */
 125     protected RevalidationHandler fValidationHandler;
 126 
 127     /** symbol table */
 128     protected SymbolTable fSymbolTable;
 129     /** error handler. may be null. */
 130     protected DOMErrorHandler fErrorHandler;
 131 
 132     /**
 133      * Cached {@link DOMError} impl.
 134      * The same object is re-used to report multiple errors.
 135      */
 136     private final DOMErrorImpl fError = new DOMErrorImpl();
 137 
 138     // Validation against namespace aware grammar
 139     protected boolean fNamespaceValidation = false;
 140 
 141     // Update PSVI information in the tree
 142     protected boolean fPSVI = false;
 143 
 144     /** The namespace context of this document: stores namespaces in scope */
 145     protected final NamespaceContext fNamespaceContext = new NamespaceSupport();
 146 
 147     /** Stores all namespace bindings on the current element */
 148     protected final NamespaceContext fLocalNSBinder = new NamespaceSupport();
 149 
 150     /** list of attributes */
 151     protected final List<Node> fAttributeList = new ArrayList<>(5);
 152 
 153     /** DOM Locator -  for namespace fixup algorithm */
 154     protected final DOMLocatorImpl fLocator = new DOMLocatorImpl();
 155 
 156     /** for setting the PSVI */
 157     protected Node fCurrentNode = null;
 158     private QName fAttrQName = new QName();
 159 
 160     // attribute value normalization
 161     final XMLString fNormalizedValue = new XMLString(new char[16], 0, 0);
 162 
 163     //DTD validator
 164     private XMLDTDValidator fDTDValidator;
 165 
 166     //Check if element content is all "ignorable whitespace"
 167     private boolean allWhitespace = false;
 168 
 169     // Constructor
 170     //
 171 
 172     public DOMNormalizer(){}
 173 
 174 
 175 
 176     /**
 177      * Normalizes document.
 178      * Note: reset() must be called before this method.
 179      */
 180         protected void normalizeDocument(CoreDocumentImpl document, DOMConfigurationImpl config) {
 181 
 182                 fDocument = document;
 183                 fConfiguration = config;
 184 
 185                 // intialize and reset DOMNormalizer component
 186                 //
 187                 fSymbolTable = (SymbolTable) fConfiguration.getProperty(DOMConfigurationImpl.SYMBOL_TABLE);
 188                 // reset namespace context
 189                 fNamespaceContext.reset();
 190                 fNamespaceContext.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING);
 191 
 192                 if ((fConfiguration.features & DOMConfigurationImpl.VALIDATE) != 0) {
 193             String schemaLang = (String)fConfiguration.getProperty(DOMConfigurationImpl.JAXP_SCHEMA_LANGUAGE);
 194 
 195             if(schemaLang != null && schemaLang.equals(Constants.NS_XMLSCHEMA)) {
 196                         fValidationHandler =
 197                                 CoreDOMImplementationImpl.singleton.getValidator(XMLGrammarDescription.XML_SCHEMA);
 198                 fConfiguration.setFeature(DOMConfigurationImpl.SCHEMA, true);
 199                 fConfiguration.setFeature(DOMConfigurationImpl.SCHEMA_FULL_CHECKING, true);
 200                 // report fatal error on DOM Level 1 nodes
 201                 fNamespaceValidation = true;
 202 
 203                 // check if we need to fill in PSVI
 204                 fPSVI = ((fConfiguration.features & DOMConfigurationImpl.PSVI) !=0)?true:false;
 205             }
 206 
 207                         fConfiguration.setFeature(DOMConfigurationImpl.XERCES_VALIDATION, true);
 208 
 209             // reset ID table
 210             fDocument.clearIdentifiers();
 211 
 212             if(fValidationHandler != null)
 213             // reset schema validator
 214                 ((XMLComponent) fValidationHandler).reset(fConfiguration);
 215 
 216                 }
 217 
 218                 fErrorHandler = (DOMErrorHandler) fConfiguration.getParameter(Constants.DOM_ERROR_HANDLER);
 219                 if (fValidationHandler != null) {
 220                         fValidationHandler.setDocumentHandler(this);
 221                         fValidationHandler.startDocument(
 222                     new SimpleLocator(fDocument.fDocumentURI, fDocument.fDocumentURI,
 223                                                 -1, -1 ), fDocument.encoding, fNamespaceContext, null);
 224 
 225                 }
 226                 try {
 227                         Node kid, next;
 228                         for (kid = fDocument.getFirstChild(); kid != null; kid = next) {
 229                                 next = kid.getNextSibling();
 230                                 kid = normalizeNode(kid);
 231                                 if (kid != null) { // don't advance
 232                                         next = kid;
 233                                 }
 234                         }
 235 
 236                         // release resources
 237                         if (fValidationHandler != null) {
 238                                 fValidationHandler.endDocument(null);
 239                                 CoreDOMImplementationImpl.singleton.releaseValidator(
 240                                         XMLGrammarDescription.XML_SCHEMA, fValidationHandler);
 241                                 fValidationHandler = null;
 242                         }
 243                 } catch (AbortException e) {
 244                     return;
 245                 }
 246 
 247         }
 248 
 249 
 250     /**
 251      *
 252      * This method acts as if the document was going through a save
 253      * and load cycle, putting the document in a "normal" form. The actual result
 254      * depends on the features being set and governing what operations actually
 255      * take place. See setNormalizationFeature for details. Noticeably this method
 256      * normalizes Text nodes, makes the document "namespace wellformed",
 257      * according to the algorithm described below in pseudo code, by adding missing
 258      * namespace declaration attributes and adding or changing namespace prefixes, updates
 259      * the replacement tree of EntityReference nodes,normalizes attribute values, etc.
 260      *
 261      * @param node   Modified node or null. If node is returned, we need
 262      *               to normalize again starting on the node returned.
 263      * @return  the normalized Node
 264      */
 265     protected Node normalizeNode (Node node){
 266 
 267         int type = node.getNodeType();
 268         boolean wellformed;
 269         fLocator.fRelatedNode=node;
 270 
 271         switch (type) {
 272         case Node.DOCUMENT_TYPE_NODE: {
 273                 if (DEBUG_ND) {
 274                     System.out.println("==>normalizeNode:{doctype}");
 275                 }
 276                 DocumentTypeImpl docType = (DocumentTypeImpl)node;
 277                 fDTDValidator = (XMLDTDValidator)CoreDOMImplementationImpl.singleton.getValidator(XMLGrammarDescription.XML_DTD);
 278                 fDTDValidator.setDocumentHandler(this);
 279                 fConfiguration.setProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY, createGrammarPool(docType));
 280                 fDTDValidator.reset(fConfiguration);
 281                 fDTDValidator.startDocument(
 282                         new SimpleLocator(fDocument.fDocumentURI, fDocument.fDocumentURI,
 283                             -1, -1 ), fDocument.encoding, fNamespaceContext, null);
 284                 fDTDValidator.doctypeDecl(docType.getName(), docType.getPublicId(), docType.getSystemId(), null);
 285                 //REVISIT: well-formness encoding info
 286                 break;
 287             }
 288 
 289         case Node.ELEMENT_NODE: {
 290                 if (DEBUG_ND) {
 291                     System.out.println("==>normalizeNode:{element} "+node.getNodeName());
 292                 }
 293 
 294                 //do the name check only when version of the document was changed &
 295                 //application has set the value of well-formed features to true
 296                 if (fDocument.errorChecking) {
 297                     if ( ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0) &&
 298                             fDocument.isXMLVersionChanged()){
 299                         if (fNamespaceValidation){
 300                             wellformed = CoreDocumentImpl.isValidQName(node.getPrefix() , node.getLocalName(), fDocument.isXML11Version()) ;
 301                         }
 302                         else {
 303                             wellformed = CoreDocumentImpl.isXMLName(node.getNodeName() , fDocument.isXML11Version());
 304                         }
 305                         if (!wellformed){
 306                             String msg = DOMMessageFormatter.formatMessage(
 307                                     DOMMessageFormatter.DOM_DOMAIN,
 308                                     "wf-invalid-character-in-node-name",
 309                                     new Object[]{"Element", node.getNodeName()});
 310                             reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR,
 311                             "wf-invalid-character-in-node-name");
 312                         }
 313                     }
 314                 }
 315                 // push namespace context
 316                 fNamespaceContext.pushContext();
 317                 fLocalNSBinder.reset();
 318 
 319                 ElementImpl elem = (ElementImpl)node;
 320                 if (elem.needsSyncChildren()) {
 321                     elem.synchronizeChildren();
 322                 }
 323                 AttributeMap attributes = (elem.hasAttributes()) ? (AttributeMap) elem.getAttributes() : null;
 324 
 325                 // fix namespaces and remove default attributes
 326                 if ((fConfiguration.features & DOMConfigurationImpl.NAMESPACES) !=0) {
 327                     // fix namespaces
 328                     // normalize attribute values
 329                     // remove default attributes
 330                     namespaceFixUp(elem, attributes);
 331 
 332                     if ((fConfiguration.features & DOMConfigurationImpl.NSDECL) == 0 && attributes != null ) {
 333                         for (int i = 0; i < attributes.getLength(); ++i) {
 334                             Attr att = (Attr)attributes.getItem(i);
 335                             if (XMLSymbols.PREFIX_XMLNS.equals(att.getPrefix()) ||
 336                                 XMLSymbols.PREFIX_XMLNS.equals(att.getName())) {
 337                                 elem.removeAttributeNode(att);
 338                                 --i;
 339                             }
 340                         }
 341                     }
 342 
 343                 } else {
 344                     if ( attributes!=null ) {
 345                         for ( int i=0; i<attributes.getLength(); ++i ) {
 346                             Attr attr = (Attr)attributes.item(i);
 347                             //removeDefault(attr, attributes);
 348                             attr.normalize();
 349                             if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0)){
 350                                     isAttrValueWF(fErrorHandler, fError, fLocator, attributes, (AttrImpl)attr, attr.getValue(), fDocument.isXML11Version());
 351                                 if (fDocument.isXMLVersionChanged()){
 352                                     wellformed=CoreDocumentImpl.isXMLName(node.getNodeName() , fDocument.isXML11Version());
 353                                     if (!wellformed){
 354                                                             String msg = DOMMessageFormatter.formatMessage(
 355                                                               DOMMessageFormatter.DOM_DOMAIN,
 356                                                               "wf-invalid-character-in-node-name",
 357                                                                new Object[]{"Attr",node.getNodeName()});
 358                                                             reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR,
 359                                                                 "wf-invalid-character-in-node-name");
 360                                     }
 361                                 }
 362                             }
 363                         }
 364                     }
 365                 }
 366 
 367 
 368                 if (fValidationHandler != null) {
 369                     // REVISIT: possible solutions to discard default content are:
 370                     //         either we pass some flag to XML Schema validator
 371                     //         or rely on the PSVI information.
 372                     fAttrProxy.setAttributes(attributes, fDocument, elem);
 373                     updateQName(elem, fQName); // updates global qname
 374                     // set error node in the dom error wrapper
 375                     // so if error occurs we can report an error node
 376                     fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 377                     fCurrentNode = node;
 378                     // call re-validation handler
 379                     fValidationHandler.startElement(fQName, fAttrProxy, null);
 380                 }
 381 
 382                 if (fDTDValidator != null) {
 383                     // REVISIT: possible solutions to discard default content are:
 384                     //         either we pass some flag to XML Schema validator
 385                     //         or rely on the PSVI information.
 386                     fAttrProxy.setAttributes(attributes, fDocument, elem);
 387                     updateQName(elem, fQName); // updates global qname
 388                     // set error node in the dom error wrapper
 389                     // so if error occurs we can report an error node
 390                     fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 391                     fCurrentNode = node;
 392                     // call re-validation handler
 393                     fDTDValidator.startElement(fQName, fAttrProxy, null);
 394                 }
 395 
 396                 // normalize children
 397                 Node kid, next;
 398                 for (kid = elem.getFirstChild(); kid != null; kid = next) {
 399                     next = kid.getNextSibling();
 400                     kid = normalizeNode(kid);
 401                     if (kid !=null) {
 402                         next = kid;  // don't advance
 403                     }
 404                 }
 405                 if (DEBUG_ND) {
 406                     // normalized subtree
 407                     System.out.println("***The children of {"+node.getNodeName()+"} are normalized");
 408                     for (kid = elem.getFirstChild(); kid != null; kid = next) {
 409                         next = kid.getNextSibling();
 410                         System.out.println(kid.getNodeName() +"["+kid.getNodeValue()+"]");
 411                     }
 412 
 413                 }
 414 
 415 
 416                 if (fValidationHandler != null) {
 417                     updateQName(elem, fQName); // updates global qname
 418                     //
 419                     // set error node in the dom error wrapper
 420                     // so if error occurs we can report an error node
 421                     fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 422                     fCurrentNode = node;
 423                     fValidationHandler.endElement(fQName, null);
 424                 }
 425 
 426                 if (fDTDValidator != null) {
 427                     updateQName(elem, fQName); // updates global qname
 428                     //
 429                     // set error node in the dom error wrapper
 430                     // so if error occurs we can report an error node
 431                     fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 432                     fCurrentNode = node;
 433                     fDTDValidator.endElement(fQName, null);
 434                 }
 435 
 436                 // pop namespace context
 437                 fNamespaceContext.popContext();
 438 
 439                 break;
 440             }
 441 
 442         case Node.COMMENT_NODE: {
 443                 if (DEBUG_ND) {
 444                     System.out.println("==>normalizeNode:{comments}");
 445                 }
 446 
 447                 if ((fConfiguration.features & DOMConfigurationImpl.COMMENTS) == 0) {
 448                     Node prevSibling = node.getPreviousSibling();
 449                     Node parent = node.getParentNode();
 450                     // remove the comment node
 451                     parent.removeChild(node);
 452                     if (prevSibling != null && prevSibling.getNodeType() == Node.TEXT_NODE) {
 453                         Node nextSibling = prevSibling.getNextSibling();
 454                         if (nextSibling != null && nextSibling.getNodeType() == Node.TEXT_NODE) {
 455                             ((TextImpl)nextSibling).insertData(0, prevSibling.getNodeValue());
 456                             parent.removeChild(prevSibling);
 457                             return nextSibling;
 458                         }
 459                     }
 460                 }//if comment node need not be removed
 461                 else {
 462                     if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0)){
 463                         String commentdata = ((Comment)node).getData();
 464                         // check comments for invalid xml chracter as per the version
 465                         // of the document
 466                         isCommentWF(fErrorHandler, fError, fLocator, commentdata, fDocument.isXML11Version());
 467                     }
 468                 }//end-else if comment node is not to be removed.
 469                                 break;
 470             }
 471         case Node.ENTITY_REFERENCE_NODE: {
 472                 if (DEBUG_ND) {
 473                     System.out.println("==>normalizeNode:{entityRef} "+node.getNodeName());
 474                 }
 475 
 476                 if ((fConfiguration.features & DOMConfigurationImpl.ENTITIES) == 0) {
 477                     Node prevSibling = node.getPreviousSibling();
 478                     Node parent = node.getParentNode();
 479                     ((EntityReferenceImpl)node).setReadOnly(false, true);
 480                     expandEntityRef (parent, node);
 481                     parent.removeChild(node);
 482                     Node next = (prevSibling != null)?prevSibling.getNextSibling():parent.getFirstChild();
 483                     // The list of children #text -> &ent;
 484                     // and entity has a first child as a text
 485                     // we should not advance
 486                     if (prevSibling != null && next != null && prevSibling.getNodeType() == Node.TEXT_NODE &&
 487                         next.getNodeType() == Node.TEXT_NODE) {
 488                         return prevSibling;  // Don't advance
 489                     }
 490                     return next;
 491                 } else {
 492                     if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0) &&
 493                         fDocument.isXMLVersionChanged()){
 494                             CoreDocumentImpl.isXMLName(node.getNodeName() , fDocument.isXML11Version());
 495                     }
 496                     // REVISIT: traverse entity reference and send appropriate calls to the validator
 497                     // (no normalization should be performed for the children).
 498                 }
 499                 break;
 500             }
 501 
 502         case Node.CDATA_SECTION_NODE: {
 503                 if (DEBUG_ND) {
 504                     System.out.println("==>normalizeNode:{cdata}");
 505                 }
 506 
 507                 if ((fConfiguration.features & DOMConfigurationImpl.CDATA) == 0) {
 508                     // convert CDATA to TEXT nodes
 509                     Node prevSibling = node.getPreviousSibling();
 510                     if (prevSibling != null && prevSibling.getNodeType() == Node.TEXT_NODE){
 511                         ((Text)prevSibling).appendData(node.getNodeValue());
 512                         node.getParentNode().removeChild(node);
 513                         return prevSibling; //don't advance
 514                     }
 515                     else {
 516                         Text text = fDocument.createTextNode(node.getNodeValue());
 517                         Node parent = node.getParentNode();
 518                         node = parent.replaceChild(text, node);
 519                         return text;  //don't advance
 520 
 521                     }
 522                 }
 523 
 524                 // send characters call for CDATA
 525                 if (fValidationHandler != null) {
 526                     // set error node in the dom error wrapper
 527                     // so if error occurs we can report an error node
 528                     fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 529                     fCurrentNode = node;
 530                     fValidationHandler.startCDATA(null);
 531                     fValidationHandler.characterData(node.getNodeValue(), null);
 532                     fValidationHandler.endCDATA(null);
 533                 }
 534 
 535                 if (fDTDValidator != null) {
 536                     // set error node in the dom error wrapper
 537                     // so if error occurs we can report an error node
 538                     fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 539                     fCurrentNode = node;
 540                     fDTDValidator.startCDATA(null);
 541                     fDTDValidator.characterData(node.getNodeValue(), null);
 542                     fDTDValidator.endCDATA(null);
 543                 }
 544                 String value = node.getNodeValue();
 545 
 546                 if ((fConfiguration.features & DOMConfigurationImpl.SPLITCDATA) != 0) {
 547                     int index;
 548                     Node parent = node.getParentNode();
 549                     if (fDocument.errorChecking) {
 550                         isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), fDocument.isXML11Version());
 551                     }
 552                     while ( (index=value.indexOf("]]>")) >= 0 ) {
 553                         node.setNodeValue(value.substring(0, index+2));
 554                         value = value.substring(index +2);
 555 
 556                         Node firstSplitNode = node;
 557                         Node newChild = fDocument.createCDATASection(value);
 558                         parent.insertBefore(newChild, node.getNextSibling());
 559                         node = newChild;
 560                         // issue warning
 561                         fLocator.fRelatedNode = firstSplitNode;
 562                         String msg = DOMMessageFormatter.formatMessage(
 563                             DOMMessageFormatter.DOM_DOMAIN,
 564                             "cdata-sections-splitted",
 565                              null);
 566                         reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_WARNING,
 567                             "cdata-sections-splitted");
 568                     }
 569 
 570                 }
 571                 else if (fDocument.errorChecking) {
 572                     // check well-formedness
 573                     isCDataWF(fErrorHandler, fError, fLocator, value, fDocument.isXML11Version());
 574                 }
 575                 break;
 576             }
 577 
 578         case Node.TEXT_NODE: {
 579                 if (DEBUG_ND) {
 580                     System.out.println("==>normalizeNode(text):{"+node.getNodeValue()+"}");
 581                 }
 582                 // If node is a text node, we need to check for one of two
 583                 // conditions:
 584                 //   1) There is an adjacent text node
 585                 //   2) There is no adjacent text node, but node is
 586                 //      an empty text node.
 587                 Node next = node.getNextSibling();
 588                 // If an adjacent text node, merge it with this node
 589                 if ( next!=null && next.getNodeType() == Node.TEXT_NODE ) {
 590                     ((Text)node).appendData(next.getNodeValue());
 591                     node.getParentNode().removeChild( next );
 592                     // We don't need to check well-formness here since we are not yet
 593                     // done with this node.
 594 
 595                     return node; // Don't advance;
 596                 } else if (node.getNodeValue().length()==0) {
 597                     // If kid is empty, remove it
 598                     node.getParentNode().removeChild( node );
 599                 } else {
 600                     // validator.characters() call and well-formness
 601                     // Don't send characters or check well-formness in the following cases:
 602                     // 1. entities is false, next child is entity reference: expand tree first
 603                     // 2. comments is false, and next child is comment
 604                     // 3. cdata is false, and next child is cdata
 605 
 606                     short nextType = (next != null)?next.getNodeType():-1;
 607                     if (nextType == -1 || !(((fConfiguration.features & DOMConfigurationImpl.ENTITIES) == 0 &&
 608                            nextType == Node.ENTITY_NODE) ||
 609                           ((fConfiguration.features & DOMConfigurationImpl.COMMENTS) == 0 &&
 610                            nextType == Node.COMMENT_NODE) ||
 611                           ((fConfiguration.features & DOMConfigurationImpl.CDATA) == 0) &&
 612                           nextType == Node.CDATA_SECTION_NODE)) {
 613                               if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0) ){
 614                                   isXMLCharWF(fErrorHandler, fError, fLocator, node.getNodeValue(), fDocument.isXML11Version());
 615                               }
 616                               if (fValidationHandler != null) {
 617                                      fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 618                                      fCurrentNode = node;
 619                                      fValidationHandler.characterData(node.getNodeValue(), null);
 620                                      if (DEBUG_ND) {
 621                                          System.out.println("=====>characterData(),"+nextType);
 622 
 623                                      }
 624                               }
 625                               if (fDTDValidator != null) {
 626                                   fConfiguration.fErrorHandlerWrapper.fCurrentNode = node;
 627                                   fCurrentNode = node;
 628                                   fDTDValidator.characterData(node.getNodeValue(), null);
 629                                   if (DEBUG_ND) {
 630                                       System.out.println("=====>characterData(),"+nextType);
 631 
 632                                   }
 633                                   if(allWhitespace) {
 634                                       allWhitespace = false;
 635                                       ((TextImpl)node).setIgnorableWhitespace(true);
 636                                   }
 637                               }
 638                     }
 639                     else {
 640                             if (DEBUG_ND) {
 641                                 System.out.println("=====>don't send characters(),"+nextType);
 642 
 643                             }
 644                     }
 645                 }
 646                 break;
 647             }
 648         case Node.PROCESSING_INSTRUCTION_NODE: {
 649 
 650             //do the well-formed valid PI target name , data check when application has set the value of well-formed feature to true
 651             if (fDocument.errorChecking && (fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0 ) {
 652                 ProcessingInstruction pinode = (ProcessingInstruction)node ;
 653 
 654                 String target = pinode.getTarget();
 655                 //1.check PI target name
 656                 if(fDocument.isXML11Version()){
 657                     wellformed = XML11Char.isXML11ValidName(target);
 658                 }
 659                 else{
 660                     wellformed = XMLChar.isValidName(target);
 661                 }
 662 
 663                                 if (!wellformed) {
 664                                     String msg = DOMMessageFormatter.formatMessage(
 665                                         DOMMessageFormatter.DOM_DOMAIN,
 666                                         "wf-invalid-character-in-node-name",
 667                                         new Object[]{"Element", node.getNodeName()});
 668                     reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR,
 669                         "wf-invalid-character-in-node-name");
 670                 }
 671 
 672                 //2. check PI data
 673                 //processing isntruction data may have certain characters
 674                 //which may not be valid XML character
 675                 isXMLCharWF(fErrorHandler, fError, fLocator, pinode.getData(), fDocument.isXML11Version());
 676             }
 677         }//end case Node.PROCESSING_INSTRUCTION_NODE
 678 
 679         }//end of switch
 680         return null;
 681     }//normalizeNode
 682 
 683     private XMLGrammarPool createGrammarPool(DocumentTypeImpl docType) {
 684 
 685         XMLGrammarPoolImpl pool = new XMLGrammarPoolImpl();
 686 
 687         XMLGrammarPreparser preParser = new XMLGrammarPreparser(fSymbolTable);
 688         preParser.registerPreparser(XMLGrammarDescription.XML_DTD, null);
 689         preParser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE, true);
 690         preParser.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATION_FEATURE, true);
 691         preParser.setProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY, pool);
 692 
 693         String internalSubset = docType.getInternalSubset();
 694         XMLInputSource is = new XMLInputSource(docType.getPublicId(), docType.getSystemId(), null, false);
 695 
 696         if(internalSubset != null)
 697             is.setCharacterStream(new StringReader(internalSubset));
 698         try {
 699             DTDGrammar g = (DTDGrammar)preParser.preparseGrammar(XMLGrammarDescription.XML_DTD, is);
 700             ((XMLDTDDescription)g.getGrammarDescription()).setRootName(docType.getName());
 701             is.setCharacterStream(null);
 702             g = (DTDGrammar)preParser.preparseGrammar(XMLGrammarDescription.XML_DTD, is);
 703             ((XMLDTDDescription)g.getGrammarDescription()).setRootName(docType.getName());
 704 
 705         } catch (XNIException e) {
 706         } catch (IOException e) {
 707         }
 708 
 709         return pool;
 710     }
 711 
 712 
 713 
 714     protected final void expandEntityRef (Node parent, Node reference){
 715         Node kid, next;
 716         for (kid = reference.getFirstChild(); kid != null; kid = next) {
 717             next = kid.getNextSibling();
 718             parent.insertBefore(kid, reference);
 719         }
 720     }
 721 
 722     // fix namespaces
 723     // normalize attribute values
 724     // remove default attributes
 725     // check attribute names if the version of the document changed.
 726 
 727     protected final void namespaceFixUp (ElementImpl element, AttributeMap attributes){
 728         if (DEBUG) {
 729             System.out.println("[ns-fixup] element:" +element.getNodeName()+
 730                                " uri: "+element.getNamespaceURI());
 731         }
 732 
 733         // ------------------------------------
 734         // pick up local namespace declarations
 735         // <xsl:stylesheet xmlns:xsl="http://xslt">
 736         //   <!-- add the following via DOM
 737         //          body is bound to http://xslt
 738         //    -->
 739         //   <xsl:body xmlns:xsl="http://bound"/>
 740         //
 741         // ------------------------------------
 742 
 743         String value, name, uri, prefix;
 744         if (attributes != null) {
 745 
 746             // Record all valid local declarations
 747             for (int k = 0; k < attributes.getLength(); ++k) {
 748                 Attr attr = (Attr)attributes.getItem(k);
 749 
 750                 //do the name check only when version of the document was changed &
 751                 //application has set the value of well-formed features to true
 752                 if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0) &&
 753                     fDocument.isXMLVersionChanged()) {
 754                     //checkQName does checking based on the version of the document
 755                     fDocument.checkQName(attr.getPrefix() , attr.getLocalName()) ;
 756                 }
 757 
 758                 uri = attr.getNamespaceURI();
 759                 if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) {
 760                     // namespace attribute
 761 
 762                     // "namespace-declarations" == false; Discard all namespace declaration attributes
 763                     if ((fConfiguration.features & DOMConfigurationImpl.NSDECL) == 0) {
 764                         continue;
 765                     }
 766 
 767                     value = attr.getNodeValue();
 768                     if (value == null) {
 769                         value=XMLSymbols.EMPTY_STRING;
 770                     }
 771 
 772                     // Check for invalid namespace declaration:
 773                     if (fDocument.errorChecking && value.equals(NamespaceContext.XMLNS_URI)) {
 774                         //A null value for locale is passed to formatMessage,
 775                         //which means that the default locale will be used
 776                         fLocator.fRelatedNode = attr;
 777                         String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN,"CantBindXMLNS",null );
 778                         reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR, "CantBindXMLNS");
 779                     } else {
 780                         // XML 1.0 Attribute value normalization
 781                         // value = normalizeAttributeValue(value, attr);
 782                         prefix = attr.getPrefix();
 783                         prefix = (prefix == null ||
 784                                   prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix);
 785                         String localpart = fSymbolTable.addSymbol( attr.getLocalName());
 786                         if (prefix == XMLSymbols.PREFIX_XMLNS) { //xmlns:prefix
 787 
 788                             value = fSymbolTable.addSymbol(value);
 789                             if (value.length() != 0) {
 790                                 fNamespaceContext.declarePrefix(localpart, value);
 791                             } else {
 792                                 // REVISIT: issue error on invalid declarations
 793                                 //          xmlns:foo = ""
 794 
 795                             }
 796                             //removeDefault (attr, attributes);
 797                             continue;
 798                         } else { // (localpart == fXmlnsSymbol && prefix == fEmptySymbol)  -- xmlns
 799                             // empty prefix is always bound ("" or some string)
 800                             value = fSymbolTable.addSymbol(value);
 801                             fNamespaceContext.declarePrefix(XMLSymbols.EMPTY_STRING, value);
 802                             //removeDefault (attr, attributes);
 803                             continue;
 804                         }
 805                     }  // end-else: valid declaration
 806                 } // end-if: namespace attribute
 807             }
 808         }
 809 
 810 
 811 
 812         // ---------------------------------------------------------
 813         // Fix up namespaces for element: per DOM L3
 814         // Need to consider the following cases:
 815         //
 816         // case 1: <xsl:stylesheet xmlns:xsl="http://xsl">
 817         // We create another element body bound to the "http://xsl" namespace
 818         // as well as namespace attribute rebounding xsl to another namespace.
 819         // <xsl:body xmlns:xsl="http://another">
 820         // Need to make sure that the new namespace decl value is changed to
 821         // "http://xsl"
 822         //
 823         // ---------------------------------------------------------
 824         // check if prefix/namespace is correct for current element
 825         // ---------------------------------------------------------
 826 
 827         uri = element.getNamespaceURI();
 828         prefix = element.getPrefix();
 829 
 830         // "namespace-declarations" == false? Discard all namespace declaration attributes
 831         if ((fConfiguration.features & DOMConfigurationImpl.NSDECL) == 0) {
 832             // no namespace declaration == no namespace URI, semantics are to keep prefix
 833             uri = null;
 834         } else if (uri != null) {  // Element has a namespace
 835             uri = fSymbolTable.addSymbol(uri);
 836             prefix = (prefix == null ||
 837                       prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix);
 838             if (fNamespaceContext.getURI(prefix) == uri) {
 839                 // The xmlns:prefix=namespace or xmlns="default" was declared at parent.
 840                 // The binder always stores mapping of empty prefix to "".
 841             } else {
 842                 // the prefix is either undeclared
 843                 // or
 844                 // conflict: the prefix is bound to another URI
 845                 addNamespaceDecl(prefix, uri, element);
 846                 fLocalNSBinder.declarePrefix(prefix, uri);
 847                 fNamespaceContext.declarePrefix(prefix, uri);
 848             }
 849         } else { // Element has no namespace
 850             if (element.getLocalName() == null) {
 851 
 852                 //  Error: DOM Level 1 node!
 853                 if (fNamespaceValidation) {
 854                     String msg = DOMMessageFormatter.formatMessage(
 855                             DOMMessageFormatter.DOM_DOMAIN, "NullLocalElementName",
 856                             new Object[]{element.getNodeName()});
 857                     reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR,
 858                     "NullLocalElementName");
 859                 } else {
 860                     String msg = DOMMessageFormatter.formatMessage(
 861                             DOMMessageFormatter.DOM_DOMAIN, "NullLocalElementName",
 862                             new Object[]{element.getNodeName()});
 863                     reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR,
 864                     "NullLocalElementName");
 865                 }
 866 
 867             } else { // uri=null and no colon (DOM L2 node)
 868                 uri = fNamespaceContext.getURI(XMLSymbols.EMPTY_STRING);
 869                 if (uri !=null && uri.length() > 0) {
 870                     // undeclare default namespace declaration (before that element
 871                     // bound to non-zero length uir), but adding xmlns="" decl
 872                     addNamespaceDecl (XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING, element);
 873                     fLocalNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING);
 874                     fNamespaceContext.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING);
 875                 }
 876             }
 877         }
 878 
 879         // -----------------------------------------
 880         // Fix up namespaces for attributes: per DOM L3
 881         // check if prefix/namespace is correct the attributes
 882         // -----------------------------------------
 883         if (attributes != null) {
 884 
 885             // clone content of the attributes
 886             attributes.cloneMap(fAttributeList);
 887             for (int i = 0; i < fAttributeList.size(); i++) {
 888                 Attr attr = (Attr) fAttributeList.get(i);
 889                 fLocator.fRelatedNode = attr;
 890 
 891                 if (DEBUG) {
 892                     System.out.println("==>[ns-fixup] process attribute: "+attr.getNodeName());
 893                 }
 894                 // normalize attribute value
 895                 attr.normalize();
 896                 value = attr.getValue();
 897                 name = attr.getNodeName();
 898                 uri = attr.getNamespaceURI();
 899 
 900                 // make sure that value is never null.
 901                 if (value == null) {
 902                     value=XMLSymbols.EMPTY_STRING;
 903                 }
 904 
 905                 if (uri != null) {  // attribute has namespace !=null
 906                     prefix = attr.getPrefix();
 907                     prefix = (prefix == null ||
 908                               prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix);
 909                     /*String localpart =*/ fSymbolTable.addSymbol( attr.getLocalName());
 910 
 911                     // ---------------------------------------
 912                     // skip namespace declarations
 913                     // ---------------------------------------
 914                     // REVISIT: can we assume that "uri" is from some symbol
 915                     // table, and compare by reference? -SG
 916                     if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) {
 917                         continue;
 918                     }
 919                     //---------------------------------------
 920                     // check if value of the attribute is namespace well-formed
 921                     //---------------------------------------
 922                     if (fDocument.errorChecking && ((fConfiguration.features & DOMConfigurationImpl.WELLFORMED) != 0)) {
 923                             isAttrValueWF(fErrorHandler, fError, fLocator, attributes, (AttrImpl)attr, attr.getValue(), fDocument.isXML11Version());
 924                             if (fDocument.isXMLVersionChanged()){
 925                                 boolean wellformed=CoreDocumentImpl.isXMLName(attr.getNodeName() , fDocument.isXML11Version());
 926                                 if (!wellformed){
 927                                                         String msg = DOMMessageFormatter.formatMessage(
 928                                                             DOMMessageFormatter.DOM_DOMAIN,
 929                                                             "wf-invalid-character-in-node-name",
 930                                                             new Object[]{"Attribute", attr.getNodeName()});
 931                                         reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR,
 932                                             "wf-invalid-character-in-node-name");
 933                                 }
 934                         }
 935                     }
 936 
 937                     // ---------------------------------------
 938                     // remove default attributes
 939                     // ---------------------------------------
 940                     /*
 941                     if (removeDefault(attr, attributes)) {
 942                         continue;
 943                     }
 944                     */
 945                     // XML 1.0 Attribute value normalization
 946                     //value = normalizeAttributeValue(value, attr);
 947 
 948                     // reset id-attributes
 949                     ((AttrImpl)attr).setIdAttribute(false);
 950 
 951 
 952                     uri = fSymbolTable.addSymbol(uri);
 953 
 954                     // find if for this prefix a URI was already declared
 955                     String declaredURI =  fNamespaceContext.getURI(prefix);
 956 
 957                     if (prefix == XMLSymbols.EMPTY_STRING || declaredURI != uri) {
 958                         // attribute has no prefix (default namespace decl does not apply to attributes)
 959                         // OR
 960                         // attribute prefix is not declared
 961                         // OR
 962                         // conflict: attribute has a prefix that conficlicts with a binding
 963                         //           already active in scope
 964 
 965                         name  = attr.getNodeName();
 966                         // Find if any prefix for attributes namespace URI is available
 967                         // in the scope
 968                         String declaredPrefix = fNamespaceContext.getPrefix(uri);
 969                         if (declaredPrefix !=null && declaredPrefix !=XMLSymbols.EMPTY_STRING) {
 970 
 971                             // use the prefix that was found (declared previously for this URI
 972                             prefix = declaredPrefix;
 973                         } else {
 974                             if (prefix != XMLSymbols.EMPTY_STRING && fLocalNSBinder.getURI(prefix) == null) {
 975                                 // the current prefix is not null and it has no in scope declaration
 976 
 977                                 // use this prefix
 978                             } else {
 979 
 980                                 // find a prefix following the pattern "NS" +index (starting at 1)
 981                                 // make sure this prefix is not declared in the current scope.
 982                                 int counter = 1;
 983                                 prefix = fSymbolTable.addSymbol(PREFIX +counter++);
 984                                 while (fLocalNSBinder.getURI(prefix)!=null) {
 985                                     prefix = fSymbolTable.addSymbol(PREFIX +counter++);
 986                                 }
 987 
 988                             }
 989                             // add declaration for the new prefix
 990                             addNamespaceDecl(prefix, uri, element);
 991                             value = fSymbolTable.addSymbol(value);
 992                             fLocalNSBinder.declarePrefix(prefix, value);
 993                             fNamespaceContext.declarePrefix(prefix, uri);
 994                         }
 995 
 996                         // change prefix for this attribute
 997                         attr.setPrefix(prefix);
 998                     }
 999                 } else { // attribute uri == null
1000 
1001                     // XML 1.0 Attribute value normalization
1002                     //value = normalizeAttributeValue(value, attr);
1003 
1004                     // reset id-attributes
1005                     ((AttrImpl)attr).setIdAttribute(false);
1006 
1007                     if (attr.getLocalName() == null) {
1008                         // It is an error if document has DOM L1 nodes.
1009                         if (fNamespaceValidation) {
1010                             String msg = DOMMessageFormatter.formatMessage(
1011                                 DOMMessageFormatter.DOM_DOMAIN,
1012                                 "NullLocalAttrName", new Object[]{attr.getNodeName()});
1013                             reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_FATAL_ERROR,
1014                                 "NullLocalAttrName");
1015                         } else {
1016                             String msg = DOMMessageFormatter.formatMessage(
1017                                 DOMMessageFormatter.DOM_DOMAIN,
1018                                 "NullLocalAttrName", new Object[]{attr.getNodeName()});
1019                             reportDOMError(fErrorHandler, fError, fLocator, msg, DOMError.SEVERITY_ERROR,
1020                                 "NullLocalAttrName");
1021                         }
1022                     } else {
1023                         // uri=null and no colon
1024                         // no fix up is needed: default namespace decl does not
1025 
1026                         // ---------------------------------------
1027                         // remove default attributes
1028                         // ---------------------------------------
1029                         // removeDefault(attr, attributes);
1030                     }
1031                 }
1032             }
1033         } // end loop for attributes
1034     }
1035 
1036     /**
1037      * Adds a namespace attribute or replaces the value of existing namespace
1038      * attribute with the given prefix and value for URI.
1039      * In case prefix is empty will add/update default namespace declaration.
1040      *
1041      * @param prefix
1042      * @param uri
1043      * @exception IOException
1044      */
1045 
1046     protected final void addNamespaceDecl(String prefix, String uri, ElementImpl element){
1047         if (DEBUG) {
1048             System.out.println("[ns-fixup] addNamespaceDecl ["+prefix+"]");
1049         }
1050         if (prefix == XMLSymbols.EMPTY_STRING) {
1051             if (DEBUG) {
1052                 System.out.println("=>add xmlns=\""+uri+"\" declaration");
1053             }
1054             element.setAttributeNS(NamespaceContext.XMLNS_URI, XMLSymbols.PREFIX_XMLNS, uri);
1055         } else {
1056             if (DEBUG) {
1057                 System.out.println("=>add xmlns:"+prefix+"=\""+uri+"\" declaration");
1058             }
1059             element.setAttributeNS(NamespaceContext.XMLNS_URI, "xmlns:"+prefix, uri);
1060         }
1061     }
1062 
1063 
1064     //
1065     // Methods for well-formness checking
1066     //
1067 
1068 
1069     /**
1070      * Check if CDATA section is well-formed
1071      * @param datavalue
1072      * @param isXML11Version = true if XML 1.1
1073      */
1074     public static final void isCDataWF(DOMErrorHandler errorHandler, DOMErrorImpl error, DOMLocatorImpl locator,
1075         String datavalue, boolean isXML11Version)
1076     {
1077         if (datavalue == null || (datavalue.length() == 0) ) {
1078             return;
1079         }
1080 
1081         char [] dataarray = datavalue.toCharArray();
1082         int datalength = dataarray.length;
1083 
1084         // version of the document is XML 1.1
1085         if (isXML11Version) {
1086             // we need to check all chracters as per production rules of XML11
1087             int i = 0;
1088             while(i < datalength){
1089                 char c = dataarray[i++];
1090                 if ( XML11Char.isXML11Invalid(c) ) {
1091                     // check if this is a supplemental character
1092                     if (XMLChar.isHighSurrogate(c) && i < datalength) {
1093                         char c2 = dataarray[i++];
1094                         if (XMLChar.isLowSurrogate(c2) &&
1095                             XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) {
1096                             continue;
1097                         }
1098                     }
1099                     String msg = DOMMessageFormatter.formatMessage(
1100                         DOMMessageFormatter.XML_DOMAIN,
1101                         "InvalidCharInCDSect",
1102                         new Object[] { Integer.toString(c, 16)});
1103                     reportDOMError(
1104                         errorHandler,
1105                         error,
1106                         locator,
1107                         msg,
1108                         DOMError.SEVERITY_ERROR,
1109                         "wf-invalid-character");
1110                 }
1111                 else if (c == ']') {
1112                     int count = i;
1113                     if (count < datalength && dataarray[count] == ']') {
1114                         while (++count < datalength && dataarray[count] == ']') {
1115                             // do nothing
1116                         }
1117                         if (count < datalength && dataarray[count] == '>') {
1118                             // CDEndInContent
1119                             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN, "CDEndInContent", null);
1120                             reportDOMError(errorHandler, error, locator,msg, DOMError.SEVERITY_ERROR, "wf-invalid-character");
1121                         }
1122                     }
1123 
1124                 }
1125             }
1126         } // version of the document is XML 1.0
1127         else {
1128             // we need to check all chracters as per production rules of XML 1.0
1129             int i = 0;
1130             while (i < datalength) {
1131                 char c = dataarray[i++];
1132                 if( XMLChar.isInvalid(c) ) {
1133                     // check if this is a supplemental character
1134                     if (XMLChar.isHighSurrogate(c) && i < datalength) {
1135                         char c2 = dataarray[i++];
1136                         if (XMLChar.isLowSurrogate(c2) &&
1137                             XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) {
1138                             continue;
1139                         }
1140                     }
1141                     // Note:  The key InvalidCharInCDSect from XMLMessages.properties
1142                     // is being used to obtain the message and DOM error type
1143                     // "wf-invalid-character" is used.  Also per DOM it is error but
1144                     // as per XML spec. it is fatal error
1145                     String msg = DOMMessageFormatter.formatMessage(
1146                         DOMMessageFormatter.XML_DOMAIN,
1147                         "InvalidCharInCDSect",
1148                         new Object[]{Integer.toString(c, 16)});
1149                     reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character");
1150                 }
1151                 else if (c==']') {
1152                     int count = i;
1153                     if ( count< datalength && dataarray[count]==']' ) {
1154                         while (++count < datalength && dataarray[count]==']' ) {
1155                             // do nothing
1156                         }
1157                         if ( count < datalength && dataarray[count]=='>' ) {
1158                             String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN, "CDEndInContent", null);
1159                             reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character");
1160                         }
1161                     }
1162 
1163                 }
1164             }
1165         } // end-else fDocument.isXMLVersion()
1166 
1167     } // isCDataWF
1168 
1169     /**
1170      * NON-DOM: check for valid XML characters as per the XML version
1171      * @param datavalue
1172      * @param isXML11Version = true if XML 1.1
1173      */
1174     public static final void isXMLCharWF(DOMErrorHandler errorHandler, DOMErrorImpl error, DOMLocatorImpl locator,
1175         String datavalue, boolean isXML11Version)
1176     {
1177         if ( datavalue == null || (datavalue.length() == 0) ) {
1178             return;
1179         }
1180 
1181         char [] dataarray = datavalue.toCharArray();
1182         int datalength = dataarray.length;
1183 
1184         // version of the document is XML 1.1
1185         if(isXML11Version){
1186             //we need to check all characters as per production rules of XML11
1187             int i = 0 ;
1188             while (i < datalength) {
1189                 if(XML11Char.isXML11Invalid(dataarray[i++])){
1190                     // check if this is a supplemental character
1191                     char ch = dataarray[i-1];
1192                     if (XMLChar.isHighSurrogate(ch) && i < datalength) {
1193                         char ch2 = dataarray[i++];
1194                         if (XMLChar.isLowSurrogate(ch2) &&
1195                             XMLChar.isSupplemental(XMLChar.supplemental(ch, ch2))) {
1196                             continue;
1197                         }
1198                     }
1199                     String msg = DOMMessageFormatter.formatMessage(
1200                         DOMMessageFormatter.DOM_DOMAIN, "InvalidXMLCharInDOM",
1201                         new Object[]{Integer.toString(dataarray[i-1], 16)});
1202                     reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR,
1203                     "wf-invalid-character");
1204                 }
1205             }
1206         } // version of the document is XML 1.0
1207         else{
1208             // we need to check all characters as per production rules of XML 1.0
1209             int i = 0 ;
1210             while (i < datalength) {
1211                 if( XMLChar.isInvalid(dataarray[i++]) ) {
1212                     // check if this is a supplemental character
1213                     char ch = dataarray[i-1];
1214                     if (XMLChar.isHighSurrogate(ch) && i < datalength) {
1215                         char ch2 = dataarray[i++];
1216                         if (XMLChar.isLowSurrogate(ch2) &&
1217                             XMLChar.isSupplemental(XMLChar.supplemental(ch, ch2))) {
1218                             continue;
1219                         }
1220                     }
1221                     String msg = DOMMessageFormatter.formatMessage(
1222                         DOMMessageFormatter.DOM_DOMAIN, "InvalidXMLCharInDOM",
1223                         new Object[]{Integer.toString(dataarray[i-1], 16)});
1224                     reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR,
1225                     "wf-invalid-character");
1226                 }
1227             }
1228         } // end-else fDocument.isXMLVersion()
1229 
1230     } // isXMLCharWF
1231 
1232     /**
1233      * NON-DOM: check if value of the comment is well-formed
1234      * @param datavalue
1235      * @param isXML11Version = true if XML 1.1
1236      */
1237     public static final void isCommentWF(DOMErrorHandler errorHandler, DOMErrorImpl error, DOMLocatorImpl locator,
1238         String datavalue, boolean isXML11Version)
1239     {
1240         if ( datavalue == null || (datavalue.length() == 0) ) {
1241             return;
1242         }
1243 
1244         char [] dataarray = datavalue.toCharArray();
1245         int datalength = dataarray.length ;
1246 
1247         // version of the document is XML 1.1
1248         if (isXML11Version) {
1249             // we need to check all chracters as per production rules of XML11
1250             int i = 0 ;
1251             while (i < datalength){
1252                 char c = dataarray[i++];
1253                 if ( XML11Char.isXML11Invalid(c) ) {
1254                     // check if this is a supplemental character
1255                     if (XMLChar.isHighSurrogate(c) && i < datalength) {
1256                         char c2 = dataarray[i++];
1257                         if (XMLChar.isLowSurrogate(c2) &&
1258                             XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) {
1259                             continue;
1260                         }
1261                     }
1262                     String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN,
1263                         "InvalidCharInComment",
1264                         new Object [] {Integer.toString(dataarray[i-1], 16)});
1265                     reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character");
1266                 }
1267                 else if (c == '-' && i < datalength && dataarray[i] == '-') {
1268                     String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN,
1269                         "DashDashInComment", null);
1270                     // invalid: '--' in comment
1271                     reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character");
1272                 }
1273             }
1274         } // version of the document is XML 1.0
1275         else {
1276             // we need to check all chracters as per production rules of XML 1.0
1277             int i = 0;
1278             while (i < datalength){
1279                 char c = dataarray[i++];
1280                 if( XMLChar.isInvalid(c) ){
1281                     // check if this is a supplemental character
1282                     if (XMLChar.isHighSurrogate(c) && i < datalength) {
1283                         char c2 = dataarray[i++];
1284                         if (XMLChar.isLowSurrogate(c2) &&
1285                             XMLChar.isSupplemental(XMLChar.supplemental(c, c2))) {
1286                             continue;
1287                         }
1288                     }
1289                     String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN,
1290                         "InvalidCharInComment", new Object [] {Integer.toString(dataarray[i-1], 16)});
1291                     reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character");
1292                 }
1293                 else if (c == '-' && i<datalength && dataarray[i]=='-'){
1294                     String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.XML_DOMAIN,
1295                         "DashDashInComment", null);
1296                     // invalid: '--' in comment
1297                     reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR, "wf-invalid-character");
1298                 }
1299             }
1300 
1301         } // end-else fDocument.isXMLVersion()
1302 
1303     } // isCommentWF
1304 
1305     /** NON-DOM: check if attribute value is well-formed
1306      * @param attributes
1307      * @param a
1308      * @param value
1309      */
1310     public static final void isAttrValueWF(DOMErrorHandler errorHandler, DOMErrorImpl error,
1311             DOMLocatorImpl locator, NamedNodeMap attributes, Attr a, String value, boolean xml11Version) {
1312         if (a instanceof AttrImpl && ((AttrImpl)a).hasStringValue()) {
1313             isXMLCharWF(errorHandler, error, locator, value, xml11Version);
1314         } else {
1315                 NodeList children = a.getChildNodes();
1316             //check each child node of the attribute's value
1317             for (int j = 0; j < children.getLength(); j++) {
1318                 Node child = children.item(j);
1319                 //If the attribute's child is an entity refernce
1320                 if (child.getNodeType() == Node.ENTITY_REFERENCE_NODE) {
1321                     Document owner = a.getOwnerDocument();
1322                     Entity ent = null;
1323                     //search for the entity in the docType
1324                     //of the attribute's ownerDocument
1325                     if (owner != null) {
1326                         DocumentType docType = owner.getDoctype();
1327                         if (docType != null) {
1328                             NamedNodeMap entities = docType.getEntities();
1329                             ent = (Entity) entities.getNamedItemNS(
1330                                     "*",
1331                                     child.getNodeName());
1332                         }
1333                     }
1334                     //If the entity was not found issue a fatal error
1335                     if (ent == null) {
1336                         String msg = DOMMessageFormatter.formatMessage(
1337                             DOMMessageFormatter.DOM_DOMAIN, "UndeclaredEntRefInAttrValue",
1338                             new Object[]{a.getNodeName()});
1339                         reportDOMError(errorHandler, error, locator, msg, DOMError.SEVERITY_ERROR,
1340                             "UndeclaredEntRefInAttrValue");
1341                     }
1342                 }
1343                 else {
1344                     // Text node
1345                     isXMLCharWF(errorHandler, error, locator, child.getNodeValue(), xml11Version);
1346                 }
1347             }
1348         }
1349     }
1350 
1351 
1352 
1353     /**
1354      * Reports a DOM error to the user handler.
1355      *
1356      * If the error is fatal, the processing will be always aborted.
1357      */
1358     public static final void reportDOMError(DOMErrorHandler errorHandler, DOMErrorImpl error, DOMLocatorImpl locator,
1359                         String message, short severity, String type ) {
1360         if( errorHandler!=null ) {
1361             error.reset();
1362             error.fMessage = message;
1363             error.fSeverity = severity;
1364             error.fLocator = locator;
1365             error.fType = type;
1366             error.fRelatedData = locator.fRelatedNode;
1367 
1368             if(!errorHandler.handleError(error))
1369                 throw new AbortException();
1370         }
1371         if( severity==DOMError.SEVERITY_FATAL_ERROR )
1372             throw new AbortException();
1373     }
1374 
1375     protected final void updateQName (Node node, QName qname){
1376 
1377         String prefix    = node.getPrefix();
1378         String namespace = node.getNamespaceURI();
1379         String localName = node.getLocalName();
1380         // REVISIT: the symbols are added too often: start/endElement
1381         //          and in the namespaceFixup. Should reduce number of calls to symbol table.
1382         qname.prefix = (prefix!=null && prefix.length()!=0)?fSymbolTable.addSymbol(prefix):null;
1383         qname.localpart = (localName != null)?fSymbolTable.addSymbol(localName):null;
1384         qname.rawname = fSymbolTable.addSymbol(node.getNodeName());
1385         qname.uri =  (namespace != null)?fSymbolTable.addSymbol(namespace):null;
1386     }
1387 
1388 
1389 
1390         /* REVISIT: remove this method if DOM does not change spec.
1391          * Performs partial XML 1.0 attribute value normalization and replaces
1392      * attribute value if the value is changed after the normalization.
1393      * DOM defines that normalizeDocument acts as if the document was going
1394      * through a save and load cycle, given that serializer will not escape
1395      * any '\n' or '\r' characters on load those will be normalized.
1396      * Thus during normalize document we need to do the following:
1397      * - perform "2.11 End-of-Line Handling"
1398      * - replace #xD, #xA, #x9 with #x20 (white space).
1399      * Note: This alg. won't attempt to resolve entity references or character entity
1400      * references, since '&' will be escaped during serialization and during loading
1401      * this won't be recognized as entity reference, i.e. attribute value "&foo;" will
1402      * be serialized as "&amp;foo;" and thus after loading will be "&foo;" again.
1403          * @param value current attribute value
1404          * @param attr current attribute
1405          * @return String the value (could be original if normalization did not change
1406      * the string)
1407          */
1408     final String normalizeAttributeValue(String value, Attr attr) {
1409         if (!attr.getSpecified()){
1410             // specified attributes should already have a normalized form
1411             // since those were added by validator
1412             return value;
1413         }
1414         int end = value.length();
1415         // ensure capacity
1416         if (fNormalizedValue.ch.length < end) {
1417             fNormalizedValue.ch = new char[end];
1418         }
1419         fNormalizedValue.length = 0;
1420         boolean normalized = false;
1421         for (int i = 0; i < end; i++) {
1422             char c = value.charAt(i);
1423             if (c==0x0009 || c==0x000A) {
1424                fNormalizedValue.ch[fNormalizedValue.length++] = ' ';
1425                normalized = true;
1426             }
1427             else if(c==0x000D){
1428                normalized = true;
1429                fNormalizedValue.ch[fNormalizedValue.length++] = ' ';
1430                int next = i+1;
1431                if (next < end && value.charAt(next)==0x000A) i=next; // skip following xA
1432             }
1433             else {
1434                 fNormalizedValue.ch[fNormalizedValue.length++] = c;
1435             }
1436         }
1437         if (normalized){
1438            value = fNormalizedValue.toString();
1439            attr.setValue(value);
1440         }
1441         return value;
1442     }
1443 
1444     protected final class XMLAttributesProxy
1445     implements XMLAttributes {
1446         protected AttributeMap fAttributes;
1447         protected CoreDocumentImpl fDocument;
1448         protected ElementImpl fElement;
1449 
1450         protected final Vector<Augmentations> fAugmentations = new Vector<>(5);
1451 
1452 
1453         public void setAttributes(AttributeMap attributes, CoreDocumentImpl doc, ElementImpl elem) {
1454             fDocument = doc;
1455             fAttributes = attributes;
1456             fElement = elem;
1457             if (attributes != null) {
1458                 int length = attributes.getLength();
1459 
1460                 fAugmentations.setSize(length);
1461                 // REVISIT: this implementation does not store any value in augmentations
1462                 //          and basically not keeping augs in parallel to attributes map
1463                 //          untill all attributes are added (default attributes)
1464                 for (int i = 0; i < length; i++) {
1465                     fAugmentations.setElementAt(new AugmentationsImpl(), i);
1466                 }
1467             } else {
1468                 fAugmentations.setSize(0);
1469             }
1470         }
1471 
1472 
1473                 /**
1474          * This method adds default declarations
1475                  * @see com.sun.org.apache.xerces.internal.xni.XMLAttributes#addAttribute(QName, String, String)
1476                  */
1477                 public int addAttribute(QName qname, String attrType, String attrValue) {
1478                         int index = fElement.getXercesAttribute(qname.uri, qname.localpart);
1479                         // add defaults to the tree
1480                         if (index < 0) {
1481                 // the default attribute was removed by a user and needed to
1482                 // be added back
1483                                 AttrImpl attr = (AttrImpl)
1484                                         ((CoreDocumentImpl) fElement.getOwnerDocument()).createAttributeNS(
1485                                                 qname.uri,
1486                                                 qname.rawname,
1487                                                 qname.localpart);
1488                 // REVISIT: the following should also update ID table
1489                 attr.setNodeValue(attrValue);
1490                 index = fElement.setXercesAttributeNode(attr);
1491                 fAugmentations.insertElementAt(new AugmentationsImpl(), index);
1492                 attr.setSpecified(false);
1493                         }
1494                         else {
1495                 // default attribute is in the tree
1496                 // we don't need to do anything since prefix was already fixed
1497                 // at the namespace fixup time and value must be same value, otherwise
1498                 // attribute will be treated as specified and we will never reach
1499                 // this method.
1500 
1501             }
1502             return index;
1503                 }
1504 
1505 
1506         public void removeAllAttributes(){
1507             // REVISIT: implement
1508         }
1509 
1510 
1511         public void removeAttributeAt(int attrIndex){
1512             // REVISIT: implement
1513         }
1514 
1515 
1516         public int getLength(){
1517             return(fAttributes != null)?fAttributes.getLength():0;
1518         }
1519 
1520 
1521         public int getIndex(String qName){
1522             // REVISIT: implement
1523             return -1;
1524         }
1525 
1526         public int getIndex(String uri, String localPart){
1527             // REVISIT: implement
1528             return -1;
1529         }
1530 
1531         public void setName(int attrIndex, QName attrName){
1532             // REVISIT: implement
1533         }
1534 
1535         public void getName(int attrIndex, QName attrName){
1536             if (fAttributes !=null) {
1537                 updateQName((Node)fAttributes.getItem(attrIndex), attrName);
1538             }
1539         }
1540 
1541         public String getPrefix(int index){
1542             // REVISIT: implement
1543             return null;
1544         }
1545 
1546 
1547         public String getURI(int index){
1548             // REVISIT: implement
1549             return null;
1550         }
1551 
1552 
1553         public String getLocalName(int index){
1554             // REVISIT: implement
1555             return null;
1556         }
1557 
1558 
1559         public String getQName(int index){
1560             // REVISIT: implement
1561             return null;
1562         }
1563 
1564          public QName getQualifiedName(int index){
1565             //return fAttributes.item(index).ge);
1566             return null;
1567         }
1568 
1569         public void setType(int attrIndex, String attrType){
1570             // REVISIT: implement
1571         }
1572 
1573 
1574         public String getType(int index){
1575             return "CDATA";
1576         }
1577 
1578 
1579         public String getType(String qName){
1580             return "CDATA";
1581         }
1582 
1583 
1584         public String getType(String uri, String localName){
1585             return "CDATA";
1586         }
1587 
1588 
1589         public void setValue(int attrIndex, String attrValue){
1590             // REVISIT: is this desired behaviour?
1591             // The values are updated in the case datatype-normalization is turned on
1592             // in this case we need to make sure that specified attributes stay specified
1593 
1594             if (fAttributes != null){
1595                 AttrImpl attr = (AttrImpl)fAttributes.getItem(attrIndex);
1596                 boolean specified = attr.getSpecified();
1597                 attr.setValue(attrValue);
1598                 attr.setSpecified(specified);
1599 
1600             }
1601         }
1602 
1603         public  void setValue(int attrIndex, String attrValue, XMLString value){
1604             setValue(attrIndex, value.toString());
1605         }
1606 
1607         public String getValue(int index){
1608             return (fAttributes !=null)?fAttributes.item(index).getNodeValue():"";
1609 
1610         }
1611 
1612 
1613         public String getValue(String qName){
1614             // REVISIT: implement
1615             return null;
1616         }
1617 
1618 
1619         public String getValue(String uri, String localName){
1620             if (fAttributes != null) {
1621                 Node node =  fAttributes.getNamedItemNS(uri, localName);
1622                 return(node != null)? node.getNodeValue():null;
1623             }
1624             return null;
1625         }
1626 
1627 
1628         public void setNonNormalizedValue(int attrIndex, String attrValue){
1629             // REVISIT: implement
1630 
1631         }
1632 
1633 
1634         public String getNonNormalizedValue(int attrIndex){
1635             // REVISIT: implement
1636             return null;
1637         }
1638 
1639 
1640         public void setSpecified(int attrIndex, boolean specified){
1641             AttrImpl attr = (AttrImpl)fAttributes.getItem(attrIndex);
1642             attr.setSpecified(specified);
1643         }
1644 
1645         public boolean isSpecified(int attrIndex){
1646             return((Attr)fAttributes.getItem(attrIndex)).getSpecified();
1647         }
1648 
1649         public Augmentations getAugmentations (int attributeIndex){
1650             return fAugmentations.elementAt(attributeIndex);
1651         }
1652 
1653         public Augmentations getAugmentations (String uri, String localPart){
1654             // REVISIT: implement
1655             return null;
1656         }
1657 
1658         public Augmentations getAugmentations(String qName){
1659             // REVISIT: implement
1660             return null;
1661         }
1662 
1663         /**
1664          * Sets the augmentations of the attribute at the specified index.
1665          *
1666          * @param attrIndex The attribute index.
1667          * @param augs      The augmentations.
1668          */
1669         public void setAugmentations(int attrIndex, Augmentations augs) {
1670             fAugmentations.setElementAt(augs, attrIndex);
1671         }
1672     }
1673 
1674     //
1675     // XMLDocumentHandler methods
1676     //
1677 
1678     /**
1679      * The start of the document.
1680      *
1681      * @param locator  The document locator, or null if the document
1682      *                 location cannot be reported during the parsing
1683      *                 of this document. However, it is <em>strongly</em>
1684      *                 recommended that a locator be supplied that can
1685      *                 at least report the system identifier of the
1686      *                 document.
1687      * @param encoding The auto-detected IANA encoding name of the entity
1688      *                 stream. This value will be null in those situations
1689      *                 where the entity encoding is not auto-detected (e.g.
1690      *                 internal entities or a document entity that is
1691      *                 parsed from a java.io.Reader).
1692      * @param namespaceContext
1693      *                 The namespace context in effect at the
1694      *                 start of this document.
1695      *                 This object represents the current context.
1696      *                 Implementors of this class are responsible
1697      *                 for copying the namespace bindings from the
1698      *                 the current context (and its parent contexts)
1699      *                 if that information is important.
1700      *
1701      * @param augs     Additional information that may include infoset augmentations
1702      * @exception XNIException
1703      *                   Thrown by handler to signal an error.
1704      */
1705     public void startDocument(XMLLocator locator, String encoding,
1706                               NamespaceContext namespaceContext,
1707                               Augmentations augs)
1708         throws XNIException{
1709     }
1710 
1711     /**
1712      * Notifies of the presence of an XMLDecl line in the document. If
1713      * present, this method will be called immediately following the
1714      * startDocument call.
1715      *
1716      * @param version    The XML version.
1717      * @param encoding   The IANA encoding name of the document, or null if
1718      *                   not specified.
1719      * @param standalone The standalone value, or null if not specified.
1720      * @param augs       Additional information that may include infoset augmentations
1721      *
1722      * @exception XNIException
1723      *                   Thrown by handler to signal an error.
1724      */
1725     public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
1726         throws XNIException{
1727     }
1728 
1729     /**
1730      * Notifies of the presence of the DOCTYPE line in the document.
1731      *
1732      * @param rootElement
1733      *                 The name of the root element.
1734      * @param publicId The public identifier if an external DTD or null
1735      *                 if the external DTD is specified using SYSTEM.
1736      * @param systemId The system identifier if an external DTD, null
1737      *                 otherwise.
1738      * @param augs     Additional information that may include infoset augmentations
1739      *
1740      * @exception XNIException
1741      *                   Thrown by handler to signal an error.
1742      */
1743     public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs)
1744         throws XNIException{
1745     }
1746 
1747     /**
1748      * A comment.
1749      *
1750      * @param text   The text in the comment.
1751      * @param augs   Additional information that may include infoset augmentations
1752      *
1753      * @exception XNIException
1754      *                   Thrown by application to signal an error.
1755      */
1756     public void comment(XMLString text, Augmentations augs) throws XNIException{
1757     }
1758 
1759     /**
1760      * A processing instruction. Processing instructions consist of a
1761      * target name and, optionally, text data. The data is only meaningful
1762      * to the application.
1763      * <p>
1764      * Typically, a processing instruction's data will contain a series
1765      * of pseudo-attributes. These pseudo-attributes follow the form of
1766      * element attributes but are <strong>not</strong> parsed or presented
1767      * to the application as anything other than text. The application is
1768      * responsible for parsing the data.
1769      *
1770      * @param target The target.
1771      * @param data   The data or null if none specified.
1772      * @param augs   Additional information that may include infoset augmentations
1773      *
1774      * @exception XNIException
1775      *                   Thrown by handler to signal an error.
1776      */
1777     public void processingInstruction(String target, XMLString data, Augmentations augs)
1778         throws XNIException{
1779     }
1780 
1781     /**
1782      * The start of an element.
1783      *
1784      * @param element    The name of the element.
1785      * @param attributes The element attributes.
1786      * @param augs       Additional information that may include infoset augmentations
1787      *
1788      * @exception XNIException
1789      *                   Thrown by handler to signal an error.
1790      */
1791         public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
1792                 throws XNIException {
1793                 Element currentElement = (Element) fCurrentNode;
1794                 int attrCount = attributes.getLength();
1795         if (DEBUG_EVENTS) {
1796             System.out.println("==>startElement: " +element+
1797             " attrs.length="+attrCount);
1798         }
1799 
1800                 for (int i = 0; i < attrCount; i++) {
1801                         attributes.getName(i, fAttrQName);
1802                         Attr attr = null;
1803 
1804                         attr = currentElement.getAttributeNodeNS(fAttrQName.uri, fAttrQName.localpart);
1805             AttributePSVI attrPSVI =
1806                                 (AttributePSVI) attributes.getAugmentations(i).getItem(Constants.ATTRIBUTE_PSVI);
1807 
1808                         if (attrPSVI != null) {
1809                 //REVISIT: instead we should be using augmentations:
1810                 // to set/retrieve Id attributes
1811                 XSTypeDefinition decl = attrPSVI.getMemberTypeDefinition();
1812                 boolean id = false;
1813                 if (decl != null){
1814                     id = ((XSSimpleType)decl).isIDType();
1815                 } else{
1816                     decl = attrPSVI.getTypeDefinition();
1817                     if (decl !=null){
1818                        id = ((XSSimpleType)decl).isIDType();
1819                     }
1820                 }
1821                 if (id){
1822                     ((ElementImpl)currentElement).setIdAttributeNode(attr, true);
1823                 }
1824 
1825                                 if (fPSVI) {
1826                                         ((PSVIAttrNSImpl) attr).setPSVI(attrPSVI);
1827                                 }
1828                                 if ((fConfiguration.features & DOMConfigurationImpl.DTNORMALIZATION) != 0) {
1829                                         // datatype-normalization
1830                                         // NOTE: The specified value MUST be set after we set
1831                                         //       the node value because that turns the "specified"
1832                                         //       flag to "true" which may overwrite a "false"
1833                                         //       value from the attribute list.
1834                                         boolean specified = attr.getSpecified();
1835                                         attr.setValue(attrPSVI.getSchemaValue().getNormalizedValue());
1836                                         if (!specified) {
1837                                                 ((AttrImpl) attr).setSpecified(specified);
1838                                         }
1839                                 }
1840                         }
1841                 }
1842         }
1843 
1844 
1845     /**
1846      * An empty element.
1847      *
1848      * @param element    The name of the element.
1849      * @param attributes The element attributes.
1850      * @param augs       Additional information that may include infoset augmentations
1851      *
1852      * @exception XNIException
1853      *                   Thrown by handler to signal an error.
1854      */
1855         public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
1856                 throws XNIException {
1857         if (DEBUG_EVENTS) {
1858             System.out.println("==>emptyElement: " +element);
1859         }
1860 
1861                 startElement(element, attributes, augs);
1862         endElement(element, augs);
1863         }
1864 
1865     /**
1866      * This method notifies the start of a general entity.
1867      * <p>
1868      * <strong>Note:</strong> This method is not called for entity references
1869      * appearing as part of attribute values.
1870      *
1871      * @param name     The name of the general entity.
1872      * @param identifier The resource identifier.
1873      * @param encoding The auto-detected IANA encoding name of the entity
1874      *                 stream. This value will be null in those situations
1875      *                 where the entity encoding is not auto-detected (e.g.
1876      *                 internal entities or a document entity that is
1877      *                 parsed from a java.io.Reader).
1878      * @param augs     Additional information that may include infoset augmentations
1879      *
1880      * @exception XNIException Thrown by handler to signal an error.
1881      */
1882     public void startGeneralEntity(String name,
1883                                    XMLResourceIdentifier identifier,
1884                                    String encoding,
1885                                    Augmentations augs) throws XNIException{
1886     }
1887 
1888     /**
1889      * Notifies of the presence of a TextDecl line in an entity. If present,
1890      * this method will be called immediately following the startEntity call.
1891      * <p>
1892      * <strong>Note:</strong> This method will never be called for the
1893      * document entity; it is only called for external general entities
1894      * referenced in document content.
1895      * <p>
1896      * <strong>Note:</strong> This method is not called for entity references
1897      * appearing as part of attribute values.
1898      *
1899      * @param version  The XML version, or null if not specified.
1900      * @param encoding The IANA encoding name of the entity.
1901      * @param augs     Additional information that may include infoset augmentations
1902      *
1903      * @exception XNIException
1904      *                   Thrown by handler to signal an error.
1905      */
1906     public void textDecl(String version, String encoding, Augmentations augs) throws XNIException{
1907     }
1908 
1909     /**
1910      * This method notifies the end of a general entity.
1911      * <p>
1912      * <strong>Note:</strong> This method is not called for entity references
1913      * appearing as part of attribute values.
1914      *
1915      * @param name   The name of the entity.
1916      * @param augs   Additional information that may include infoset augmentations
1917      *
1918      * @exception XNIException
1919      *                   Thrown by handler to signal an error.
1920      */
1921     public void endGeneralEntity(String name, Augmentations augs) throws XNIException{
1922     }
1923 
1924     /**
1925      * Character content.
1926      *
1927      * @param text   The content.
1928      * @param augs   Additional information that may include infoset augmentations
1929      *
1930      * @exception XNIException
1931      *                   Thrown by handler to signal an error.
1932      */
1933     public void characters(XMLString text, Augmentations augs) throws XNIException{
1934     }
1935 
1936     /**
1937      * Ignorable whitespace. For this method to be called, the document
1938      * source must have some way of determining that the text containing
1939      * only whitespace characters should be considered ignorable. For
1940      * example, the validator can determine if a length of whitespace
1941      * characters in the document are ignorable based on the element
1942      * content model.
1943      *
1944      * @param text   The ignorable whitespace.
1945      * @param augs   Additional information that may include infoset augmentations
1946      *
1947      * @exception XNIException
1948      *                   Thrown by handler to signal an error.
1949      */
1950     public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException{
1951         allWhitespace = true;
1952     }
1953 
1954     /**
1955      * The end of an element.
1956      *
1957      * @param element The name of the element.
1958      * @param augs    Additional information that may include infoset augmentations
1959      *
1960      * @exception XNIException
1961      *                   Thrown by handler to signal an error.
1962      */
1963         public void endElement(QName element, Augmentations augs) throws XNIException {
1964                 if (DEBUG_EVENTS) {
1965                         System.out.println("==>endElement: " + element);
1966                 }
1967 
1968         if(augs != null) {
1969                 ElementPSVI elementPSVI = (ElementPSVI) augs.getItem(Constants.ELEMENT_PSVI);
1970                 if (elementPSVI != null) {
1971                         ElementImpl elementNode = (ElementImpl) fCurrentNode;
1972                         if (fPSVI) {
1973                                 ((PSVIElementNSImpl) fCurrentNode).setPSVI(elementPSVI);
1974                         }
1975                         // include element default content (if one is available)
1976                         String normalizedValue = elementPSVI.getSchemaValue().getNormalizedValue();
1977                         if ((fConfiguration.features & DOMConfigurationImpl.DTNORMALIZATION) != 0) {
1978                     if (normalizedValue !=null)
1979                                     elementNode.setTextContent(normalizedValue);
1980                         }
1981                         else {
1982                                 // NOTE: this is a hack: it is possible that DOM had an empty element
1983                                 // and validator sent default value using characters(), which we don't
1984                                 // implement. Thus, here we attempt to add the default value.
1985                                 String text = elementNode.getTextContent();
1986                                 if (text.length() == 0) {
1987                                         // default content could be provided
1988                         if (normalizedValue !=null)
1989                             elementNode.setTextContent(normalizedValue);
1990                                 }
1991                         }
1992                 }
1993         }
1994         }
1995 
1996 
1997     /**
1998      * The start of a CDATA section.
1999      *
2000      * @param augs   Additional information that may include infoset augmentations
2001      *
2002      * @exception XNIException
2003      *                   Thrown by handler to signal an error.
2004      */
2005     public void startCDATA(Augmentations augs) throws XNIException{
2006     }
2007 
2008     /**
2009      * The end of a CDATA section.
2010      *
2011      * @param augs   Additional information that may include infoset augmentations
2012      *
2013      * @exception XNIException
2014      *                   Thrown by handler to signal an error.
2015      */
2016     public void endCDATA(Augmentations augs) throws XNIException{
2017     }
2018 
2019     /**
2020      * The end of the document.
2021      *
2022      * @param augs   Additional information that may include infoset augmentations
2023      *
2024      * @exception XNIException
2025      *                   Thrown by handler to signal an error.
2026      */
2027     public void endDocument(Augmentations augs) throws XNIException{
2028     }
2029 
2030 
2031     /** Sets the document source. */
2032     public void setDocumentSource(XMLDocumentSource source){
2033     }
2034 
2035 
2036     /** Returns the document source. */
2037     public XMLDocumentSource getDocumentSource(){
2038         return null;
2039     }
2040 
2041 }  // DOMNormalizer class