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