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