jaxp/src/com/sun/org/apache/xml/internal/serializer/dom3/DOM3TreeWalker.java
changeset 25834 aba3efbf4ec5
equal deleted inserted replaced
25833:054a597b18f8 25834:aba3efbf4ec5
       
     1 /*
       
     2  * Licensed to the Apache Software Foundation (ASF) under one
       
     3  * or more contributor license agreements. See the NOTICE file
       
     4  * distributed with this work for additional information
       
     5  * regarding copyright ownership. The ASF licenses this file
       
     6  * to you under the Apache License, Version 2.0 (the  "License");
       
     7  * you may not use this file except in compliance with the License.
       
     8  * You may obtain a copy of the License at
       
     9  *
       
    10  *     http://www.apache.org/licenses/LICENSE-2.0
       
    11  *
       
    12  * Unless required by applicable law or agreed to in writing, software
       
    13  * distributed under the License is distributed on an "AS IS" BASIS,
       
    14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    15  * See the License for the specific language governing permissions and
       
    16  * limitations under the License.
       
    17  */
       
    18 /*
       
    19  * $Id:  $
       
    20  */
       
    21 
       
    22 package com.sun.org.apache.xml.internal.serializer.dom3;
       
    23 
       
    24 import java.io.File;
       
    25 import java.io.IOException;
       
    26 import java.io.Writer;
       
    27 import java.util.Enumeration;
       
    28 import java.util.Hashtable;
       
    29 import java.util.Properties;
       
    30 
       
    31 import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;
       
    32 import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
       
    33 import com.sun.org.apache.xml.internal.serializer.utils.MsgKey;
       
    34 import com.sun.org.apache.xml.internal.serializer.utils.Utils;
       
    35 import com.sun.org.apache.xerces.internal.util.XML11Char;
       
    36 import com.sun.org.apache.xerces.internal.util.XMLChar;
       
    37 import org.w3c.dom.Attr;
       
    38 import org.w3c.dom.CDATASection;
       
    39 import org.w3c.dom.Comment;
       
    40 import org.w3c.dom.DOMError;
       
    41 import org.w3c.dom.DOMErrorHandler;
       
    42 import org.w3c.dom.Document;
       
    43 import org.w3c.dom.DocumentType;
       
    44 import org.w3c.dom.Element;
       
    45 import org.w3c.dom.Entity;
       
    46 import org.w3c.dom.EntityReference;
       
    47 import org.w3c.dom.NamedNodeMap;
       
    48 import org.w3c.dom.Node;
       
    49 import org.w3c.dom.NodeList;
       
    50 import org.w3c.dom.ProcessingInstruction;
       
    51 import org.w3c.dom.Text;
       
    52 import org.w3c.dom.ls.LSSerializerFilter;
       
    53 import org.w3c.dom.traversal.NodeFilter;
       
    54 import org.xml.sax.Locator;
       
    55 import org.xml.sax.SAXException;
       
    56 import org.xml.sax.ext.LexicalHandler;
       
    57 import org.xml.sax.helpers.LocatorImpl;
       
    58 
       
    59 /**
       
    60  * Built on org.apache.xml.serializer.TreeWalker and adds functionality to
       
    61  * traverse and serialize a DOM Node (Level 2 or Level 3) as specified in
       
    62  * the DOM Level 3 LS Recommedation by evaluating and applying DOMConfiguration
       
    63  * parameters and filters if any during serialization.
       
    64  *
       
    65  * @xsl.usage internal
       
    66  */
       
    67 final class DOM3TreeWalker {
       
    68 
       
    69     /**
       
    70      * The SerializationHandler, it extends ContentHandler and when
       
    71      * this class is instantiated via the constructor provided, a
       
    72      * SerializationHandler object is passed to it.
       
    73      */
       
    74     private SerializationHandler fSerializer = null;
       
    75 
       
    76     /** We do not need DOM2Helper since DOM Level 3 LS applies to DOM Level 2 or newer */
       
    77 
       
    78     /** Locator object for this TreeWalker          */
       
    79     private LocatorImpl fLocator = new LocatorImpl();
       
    80 
       
    81     /** ErrorHandler */
       
    82     private DOMErrorHandler fErrorHandler = null;
       
    83 
       
    84     /** LSSerializerFilter */
       
    85     private LSSerializerFilter fFilter = null;
       
    86 
       
    87     /** If the serializer is an instance of a LexicalHandler */
       
    88     private LexicalHandler fLexicalHandler = null;
       
    89 
       
    90     private int fWhatToShowFilter;
       
    91 
       
    92     /** New Line character to use in serialization */
       
    93     private String fNewLine = null;
       
    94 
       
    95     /** DOMConfiguration Properties */
       
    96     private Properties fDOMConfigProperties = null;
       
    97 
       
    98     /** Keeps track if we are in an entity reference when entities=true */
       
    99     private boolean fInEntityRef = false;
       
   100 
       
   101     /** Stores the version of the XML document to be serialize */
       
   102     private String fXMLVersion = null;
       
   103 
       
   104     /** XML Version, default 1.0 */
       
   105     private boolean fIsXMLVersion11 = false;
       
   106 
       
   107     /** Is the Node a Level 3 DOM node */
       
   108     private boolean fIsLevel3DOM = false;
       
   109 
       
   110     /** DOM Configuration Parameters */
       
   111     private int fFeatures = 0;
       
   112 
       
   113     /** Flag indicating whether following text to be processed is raw text          */
       
   114     boolean fNextIsRaw = false;
       
   115 
       
   116     //
       
   117     private static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";
       
   118 
       
   119     //
       
   120     private static final String XMLNS_PREFIX = "xmlns";
       
   121 
       
   122     //
       
   123     private static final String XML_URI = "http://www.w3.org/XML/1998/namespace";
       
   124 
       
   125     //
       
   126     private static final String XML_PREFIX = "xml";
       
   127 
       
   128     /** stores namespaces in scope */
       
   129     protected NamespaceSupport fNSBinder;
       
   130 
       
   131     /** stores all namespace bindings on the current element */
       
   132     protected NamespaceSupport fLocalNSBinder;
       
   133 
       
   134     /** stores the current element depth */
       
   135     private int fElementDepth = 0;
       
   136 
       
   137     // ***********************************************************************
       
   138     // DOMConfiguration paramter settings
       
   139     // ***********************************************************************
       
   140     // Parameter canonical-form, true [optional] - NOT SUPPORTED
       
   141     private final static int CANONICAL = 0x1 << 0;
       
   142 
       
   143     // Parameter cdata-sections, true [required] (default)
       
   144     private final static int CDATA = 0x1 << 1;
       
   145 
       
   146     // Parameter check-character-normalization, true [optional] - NOT SUPPORTED
       
   147     private final static int CHARNORMALIZE = 0x1 << 2;
       
   148 
       
   149     // Parameter comments, true [required] (default)
       
   150     private final static int COMMENTS = 0x1 << 3;
       
   151 
       
   152     // Parameter datatype-normalization, true [optional] - NOT SUPPORTED
       
   153     private final static int DTNORMALIZE = 0x1 << 4;
       
   154 
       
   155     // Parameter element-content-whitespace, true [required] (default) - value - false [optional] NOT SUPPORTED
       
   156     private final static int ELEM_CONTENT_WHITESPACE = 0x1 << 5;
       
   157 
       
   158     // Parameter entities, true [required] (default)
       
   159     private final static int ENTITIES = 0x1 << 6;
       
   160 
       
   161     // Parameter infoset, true [required] (default), false has no effect --> True has no effect for the serializer
       
   162     private final static int INFOSET = 0x1 << 7;
       
   163 
       
   164     // Parameter namespaces, true [required] (default)
       
   165     private final static int NAMESPACES = 0x1 << 8;
       
   166 
       
   167     // Parameter namespace-declarations, true [required] (default)
       
   168     private final static int NAMESPACEDECLS = 0x1 << 9;
       
   169 
       
   170     // Parameter normalize-characters, true [optional] - NOT SUPPORTED
       
   171     private final static int NORMALIZECHARS = 0x1 << 10;
       
   172 
       
   173     // Parameter split-cdata-sections, true [required] (default)
       
   174     private final static int SPLITCDATA = 0x1 << 11;
       
   175 
       
   176     // Parameter validate, true [optional] - NOT SUPPORTED
       
   177     private final static int VALIDATE = 0x1 << 12;
       
   178 
       
   179     // Parameter validate-if-schema, true [optional] - NOT SUPPORTED
       
   180     private final static int SCHEMAVALIDATE = 0x1 << 13;
       
   181 
       
   182     // Parameter split-cdata-sections, true [required] (default)
       
   183     private final static int WELLFORMED = 0x1 << 14;
       
   184 
       
   185     // Parameter discard-default-content, true [required] (default)
       
   186     // Not sure how this will be used in level 2 Documents
       
   187     private final static int DISCARDDEFAULT = 0x1 << 15;
       
   188 
       
   189     // Parameter format-pretty-print, true [optional]
       
   190     private final static int PRETTY_PRINT = 0x1 << 16;
       
   191 
       
   192     // Parameter ignore-unknown-character-denormalizations, true [required] (default)
       
   193     // We currently do not support XML 1.1 character normalization
       
   194     private final static int IGNORE_CHAR_DENORMALIZE = 0x1 << 17;
       
   195 
       
   196     // Parameter discard-default-content, true [required] (default)
       
   197     private final static int XMLDECL = 0x1 << 18;
       
   198 
       
   199     /**
       
   200      * Constructor.
       
   201      * @param   contentHandler serialHandler The implemention of the SerializationHandler interface
       
   202      */
       
   203     DOM3TreeWalker(
       
   204         SerializationHandler serialHandler,
       
   205         DOMErrorHandler errHandler,
       
   206         LSSerializerFilter filter,
       
   207         String newLine) {
       
   208         fSerializer = serialHandler;
       
   209         //fErrorHandler = errHandler == null ? new DOMErrorHandlerImpl() : errHandler; // Should we be using the default?
       
   210         fErrorHandler = errHandler;
       
   211         fFilter = filter;
       
   212         fLexicalHandler = null;
       
   213         fNewLine = newLine;
       
   214 
       
   215         fNSBinder = new NamespaceSupport();
       
   216         fLocalNSBinder = new NamespaceSupport();
       
   217 
       
   218         fDOMConfigProperties = fSerializer.getOutputFormat();
       
   219         fSerializer.setDocumentLocator(fLocator);
       
   220         initProperties(fDOMConfigProperties);
       
   221 
       
   222         try {
       
   223             // Bug see Bugzilla  26741
       
   224             fLocator.setSystemId(
       
   225                 System.getProperty("user.dir") + File.separator + "dummy.xsl");
       
   226         } catch (SecurityException se) { // user.dir not accessible from applet
       
   227 
       
   228         }
       
   229     }
       
   230 
       
   231     /**
       
   232      * Perform a pre-order traversal non-recursive style.
       
   233      *
       
   234      * Note that TreeWalker assumes that the subtree is intended to represent
       
   235      * a complete (though not necessarily well-formed) document and, during a
       
   236      * traversal, startDocument and endDocument will always be issued to the
       
   237      * SAX listener.
       
   238      *
       
   239      * @param pos Node in the tree where to start traversal
       
   240      *
       
   241      * @throws TransformerException
       
   242      */
       
   243     public void traverse(Node pos) throws org.xml.sax.SAXException {
       
   244         this.fSerializer.startDocument();
       
   245 
       
   246         // Determine if the Node is a DOM Level 3 Core Node.
       
   247         if (pos.getNodeType() != Node.DOCUMENT_NODE) {
       
   248             Document ownerDoc = pos.getOwnerDocument();
       
   249             if (ownerDoc != null
       
   250                 && ownerDoc.getImplementation().hasFeature("Core", "3.0")) {
       
   251                 fIsLevel3DOM = true;
       
   252             }
       
   253         } else {
       
   254             if (((Document) pos)
       
   255                 .getImplementation()
       
   256                 .hasFeature("Core", "3.0")) {
       
   257                 fIsLevel3DOM = true;
       
   258             }
       
   259         }
       
   260 
       
   261         if (fSerializer instanceof LexicalHandler) {
       
   262             fLexicalHandler = ((LexicalHandler) this.fSerializer);
       
   263         }
       
   264 
       
   265         if (fFilter != null)
       
   266             fWhatToShowFilter = fFilter.getWhatToShow();
       
   267 
       
   268         Node top = pos;
       
   269 
       
   270         while (null != pos) {
       
   271             startNode(pos);
       
   272 
       
   273             Node nextNode = null;
       
   274 
       
   275             nextNode = pos.getFirstChild();
       
   276 
       
   277             while (null == nextNode) {
       
   278                 endNode(pos);
       
   279 
       
   280                 if (top.equals(pos))
       
   281                     break;
       
   282 
       
   283                 nextNode = pos.getNextSibling();
       
   284 
       
   285                 if (null == nextNode) {
       
   286                     pos = pos.getParentNode();
       
   287 
       
   288                     if ((null == pos) || (top.equals(pos))) {
       
   289                         if (null != pos)
       
   290                             endNode(pos);
       
   291 
       
   292                         nextNode = null;
       
   293 
       
   294                         break;
       
   295                     }
       
   296                 }
       
   297             }
       
   298 
       
   299             pos = nextNode;
       
   300         }
       
   301         this.fSerializer.endDocument();
       
   302     }
       
   303 
       
   304     /**
       
   305      * Perform a pre-order traversal non-recursive style.
       
   306 
       
   307      * Note that TreeWalker assumes that the subtree is intended to represent
       
   308      * a complete (though not necessarily well-formed) document and, during a
       
   309      * traversal, startDocument and endDocument will always be issued to the
       
   310      * SAX listener.
       
   311      *
       
   312      * @param pos Node in the tree where to start traversal
       
   313      * @param top Node in the tree where to end traversal
       
   314      *
       
   315      * @throws TransformerException
       
   316      */
       
   317     public void traverse(Node pos, Node top) throws org.xml.sax.SAXException {
       
   318 
       
   319         this.fSerializer.startDocument();
       
   320 
       
   321         // Determine if the Node is a DOM Level 3 Core Node.
       
   322         if (pos.getNodeType() != Node.DOCUMENT_NODE) {
       
   323             Document ownerDoc = pos.getOwnerDocument();
       
   324             if (ownerDoc != null
       
   325                 && ownerDoc.getImplementation().hasFeature("Core", "3.0")) {
       
   326                 fIsLevel3DOM = true;
       
   327             }
       
   328         } else {
       
   329             if (((Document) pos)
       
   330                 .getImplementation()
       
   331                 .hasFeature("Core", "3.0")) {
       
   332                 fIsLevel3DOM = true;
       
   333             }
       
   334         }
       
   335 
       
   336         if (fSerializer instanceof LexicalHandler) {
       
   337             fLexicalHandler = ((LexicalHandler) this.fSerializer);
       
   338         }
       
   339 
       
   340         if (fFilter != null)
       
   341             fWhatToShowFilter = fFilter.getWhatToShow();
       
   342 
       
   343         while (null != pos) {
       
   344             startNode(pos);
       
   345 
       
   346             Node nextNode = null;
       
   347 
       
   348             nextNode = pos.getFirstChild();
       
   349 
       
   350             while (null == nextNode) {
       
   351                 endNode(pos);
       
   352 
       
   353                 if ((null != top) && top.equals(pos))
       
   354                     break;
       
   355 
       
   356                 nextNode = pos.getNextSibling();
       
   357 
       
   358                 if (null == nextNode) {
       
   359                     pos = pos.getParentNode();
       
   360 
       
   361                     if ((null == pos) || ((null != top) && top.equals(pos))) {
       
   362                         nextNode = null;
       
   363 
       
   364                         break;
       
   365                     }
       
   366                 }
       
   367             }
       
   368 
       
   369             pos = nextNode;
       
   370         }
       
   371         this.fSerializer.endDocument();
       
   372     }
       
   373 
       
   374     /**
       
   375      * Optimized dispatch of characters.
       
   376      */
       
   377     private final void dispatachChars(Node node)
       
   378         throws org.xml.sax.SAXException {
       
   379         if (fSerializer != null) {
       
   380             this.fSerializer.characters(node);
       
   381         } else {
       
   382             String data = ((Text) node).getData();
       
   383             this.fSerializer.characters(data.toCharArray(), 0, data.length());
       
   384         }
       
   385     }
       
   386 
       
   387     /**
       
   388      * Start processing given node
       
   389      *
       
   390      * @param node Node to process
       
   391      *
       
   392      * @throws org.xml.sax.SAXException
       
   393      */
       
   394     protected void startNode(Node node) throws org.xml.sax.SAXException {
       
   395         if (node instanceof Locator) {
       
   396             Locator loc = (Locator) node;
       
   397             fLocator.setColumnNumber(loc.getColumnNumber());
       
   398             fLocator.setLineNumber(loc.getLineNumber());
       
   399             fLocator.setPublicId(loc.getPublicId());
       
   400             fLocator.setSystemId(loc.getSystemId());
       
   401         } else {
       
   402             fLocator.setColumnNumber(0);
       
   403             fLocator.setLineNumber(0);
       
   404         }
       
   405 
       
   406         switch (node.getNodeType()) {
       
   407             case Node.DOCUMENT_TYPE_NODE :
       
   408                 serializeDocType((DocumentType) node, true);
       
   409                 break;
       
   410             case Node.COMMENT_NODE :
       
   411                 serializeComment((Comment) node);
       
   412                 break;
       
   413             case Node.DOCUMENT_FRAGMENT_NODE :
       
   414                 // Children are traversed
       
   415                 break;
       
   416             case Node.DOCUMENT_NODE :
       
   417                 break;
       
   418             case Node.ELEMENT_NODE :
       
   419                 serializeElement((Element) node, true);
       
   420                 break;
       
   421             case Node.PROCESSING_INSTRUCTION_NODE :
       
   422                 serializePI((ProcessingInstruction) node);
       
   423                 break;
       
   424             case Node.CDATA_SECTION_NODE :
       
   425                 serializeCDATASection((CDATASection) node);
       
   426                 break;
       
   427             case Node.TEXT_NODE :
       
   428                 serializeText((Text) node);
       
   429                 break;
       
   430             case Node.ENTITY_REFERENCE_NODE :
       
   431                 serializeEntityReference((EntityReference) node, true);
       
   432                 break;
       
   433             default :
       
   434                 }
       
   435     }
       
   436 
       
   437     /**
       
   438      * End processing of given node
       
   439      *
       
   440      *
       
   441      * @param node Node we just finished processing
       
   442      *
       
   443      * @throws org.xml.sax.SAXException
       
   444      */
       
   445     protected void endNode(Node node) throws org.xml.sax.SAXException {
       
   446 
       
   447         switch (node.getNodeType()) {
       
   448             case Node.DOCUMENT_NODE :
       
   449                 break;
       
   450             case Node.DOCUMENT_TYPE_NODE :
       
   451                 serializeDocType((DocumentType) node, false);
       
   452                 break;
       
   453             case Node.ELEMENT_NODE :
       
   454                 serializeElement((Element) node, false);
       
   455                 break;
       
   456             case Node.CDATA_SECTION_NODE :
       
   457                 break;
       
   458             case Node.ENTITY_REFERENCE_NODE :
       
   459                 serializeEntityReference((EntityReference) node, false);
       
   460                 break;
       
   461             default :
       
   462                 }
       
   463     }
       
   464 
       
   465     // ***********************************************************************
       
   466     // Node serialization methods
       
   467     // ***********************************************************************
       
   468     /**
       
   469      * Applies a filter on the node to serialize
       
   470      *
       
   471      * @param node The Node to serialize
       
   472      * @return True if the node is to be serialized else false if the node
       
   473      *         is to be rejected or skipped.
       
   474      */
       
   475     protected boolean applyFilter(Node node, int nodeType) {
       
   476         if (fFilter != null && (fWhatToShowFilter & nodeType) != 0) {
       
   477 
       
   478             short code = fFilter.acceptNode(node);
       
   479             switch (code) {
       
   480                 case NodeFilter.FILTER_REJECT :
       
   481                 case NodeFilter.FILTER_SKIP :
       
   482                     return false; // skip the node
       
   483                 default : // fall through..
       
   484             }
       
   485         }
       
   486         return true;
       
   487     }
       
   488 
       
   489     /**
       
   490      * Serializes a Document Type Node.
       
   491      *
       
   492      * @param node The Docuemnt Type Node to serialize
       
   493      * @param bStart Invoked at the start or end of node.  Default true.
       
   494      */
       
   495     protected void serializeDocType(DocumentType node, boolean bStart)
       
   496         throws SAXException {
       
   497         // The DocType and internalSubset can not be modified in DOM and is
       
   498         // considered to be well-formed as the outcome of successful parsing.
       
   499         String docTypeName = node.getNodeName();
       
   500         String publicId = node.getPublicId();
       
   501         String systemId = node.getSystemId();
       
   502         String internalSubset = node.getInternalSubset();
       
   503 
       
   504         //DocumentType nodes are never passed to the filter
       
   505 
       
   506         if (internalSubset != null && !"".equals(internalSubset)) {
       
   507 
       
   508             if (bStart) {
       
   509                 try {
       
   510                     // The Serializer does not provide a way to write out the
       
   511                     // DOCTYPE internal subset via an event call, so we write it
       
   512                     // out here.
       
   513                     Writer writer = fSerializer.getWriter();
       
   514                     StringBuffer dtd = new StringBuffer();
       
   515 
       
   516                     dtd.append("<!DOCTYPE ");
       
   517                     dtd.append(docTypeName);
       
   518                     if (null != publicId) {
       
   519                         dtd.append(" PUBLIC \"");
       
   520                         dtd.append(publicId);
       
   521                         dtd.append('\"');
       
   522                     }
       
   523 
       
   524                     if (null != systemId) {
       
   525                         if (null == publicId) {
       
   526                             dtd.append(" SYSTEM \"");
       
   527                         } else {
       
   528                             dtd.append(" \"");
       
   529                         }
       
   530                         dtd.append(systemId);
       
   531                         dtd.append('\"');
       
   532                     }
       
   533 
       
   534                     dtd.append(" [ ");
       
   535 
       
   536                     dtd.append(fNewLine);
       
   537                     dtd.append(internalSubset);
       
   538                     dtd.append("]>");
       
   539                     dtd.append(fNewLine);
       
   540 
       
   541                     writer.write(dtd.toString());
       
   542                     writer.flush();
       
   543 
       
   544                 } catch (IOException e) {
       
   545                     throw new SAXException(Utils.messages.createMessage(
       
   546                             MsgKey.ER_WRITING_INTERNAL_SUBSET, null), e);
       
   547                 }
       
   548             } // else if !bStart do nothing
       
   549 
       
   550         } else {
       
   551 
       
   552             if (bStart) {
       
   553                 if (fLexicalHandler != null) {
       
   554                     fLexicalHandler.startDTD(docTypeName, publicId, systemId);
       
   555                 }
       
   556             } else {
       
   557                 if (fLexicalHandler != null) {
       
   558                     fLexicalHandler.endDTD();
       
   559                 }
       
   560             }
       
   561         }
       
   562     }
       
   563 
       
   564     /**
       
   565      * Serializes a Comment Node.
       
   566      *
       
   567      * @param node The Comment Node to serialize
       
   568      */
       
   569     protected void serializeComment(Comment node) throws SAXException {
       
   570         // comments=true
       
   571         if ((fFeatures & COMMENTS) != 0) {
       
   572             String data = node.getData();
       
   573 
       
   574             // well-formed=true
       
   575             if ((fFeatures & WELLFORMED) != 0) {
       
   576                 isCommentWellFormed(data);
       
   577             }
       
   578 
       
   579             if (fLexicalHandler != null) {
       
   580                 // apply the LSSerializer filter after the operations requested by the
       
   581                 // DOMConfiguration parameters have been applied
       
   582                 if (!applyFilter(node, NodeFilter.SHOW_COMMENT)) {
       
   583                     return;
       
   584                 }
       
   585 
       
   586                 fLexicalHandler.comment(data.toCharArray(), 0, data.length());
       
   587             }
       
   588         }
       
   589     }
       
   590 
       
   591     /**
       
   592      * Serializes an Element Node.
       
   593      *
       
   594      * @param node The Element Node to serialize
       
   595      * @param bStart Invoked at the start or end of node.
       
   596      */
       
   597     protected void serializeElement(Element node, boolean bStart)
       
   598         throws SAXException {
       
   599         if (bStart) {
       
   600             fElementDepth++;
       
   601 
       
   602             // We use the Xalan specific startElement and starPrefixMapping calls
       
   603             // (and addAttribute and namespaceAfterStartElement) as opposed to
       
   604             // SAX specific, for performance reasons as they reduce the overhead
       
   605             // of creating an AttList object upfront.
       
   606 
       
   607             // well-formed=true
       
   608             if ((fFeatures & WELLFORMED) != 0) {
       
   609                 isElementWellFormed(node);
       
   610             }
       
   611 
       
   612             // REVISIT: We apply the LSSerializer filter for elements before
       
   613             // namesapce fixup
       
   614             if (!applyFilter(node, NodeFilter.SHOW_ELEMENT)) {
       
   615                 return;
       
   616             }
       
   617 
       
   618             // namespaces=true, record and fixup namspaced element
       
   619             if ((fFeatures & NAMESPACES) != 0) {
       
   620                 fNSBinder.pushContext();
       
   621                 fLocalNSBinder.reset();
       
   622 
       
   623                 recordLocalNSDecl(node);
       
   624                 fixupElementNS(node);
       
   625             }
       
   626 
       
   627             // Namespace normalization
       
   628             fSerializer.startElement(
       
   629                         node.getNamespaceURI(),
       
   630                     node.getLocalName(),
       
   631                     node.getNodeName());
       
   632 
       
   633             serializeAttList(node);
       
   634 
       
   635         } else {
       
   636                 fElementDepth--;
       
   637 
       
   638             // apply the LSSerializer filter
       
   639             if (!applyFilter(node, NodeFilter.SHOW_ELEMENT)) {
       
   640                 return;
       
   641             }
       
   642 
       
   643             this.fSerializer.endElement(
       
   644                 node.getNamespaceURI(),
       
   645                 node.getLocalName(),
       
   646                 node.getNodeName());
       
   647             // since endPrefixMapping was not used by SerializationHandler it was removed
       
   648             // for performance reasons.
       
   649 
       
   650             if ((fFeatures & NAMESPACES) != 0 ) {
       
   651                     fNSBinder.popContext();
       
   652             }
       
   653 
       
   654         }
       
   655     }
       
   656 
       
   657     /**
       
   658      * Serializes the Attr Nodes of an Element.
       
   659      *
       
   660      * @param node The OwnerElement whose Attr Nodes are to be serialized.
       
   661      */
       
   662     protected void serializeAttList(Element node) throws SAXException {
       
   663         NamedNodeMap atts = node.getAttributes();
       
   664         int nAttrs = atts.getLength();
       
   665 
       
   666         for (int i = 0; i < nAttrs; i++) {
       
   667             Node attr = atts.item(i);
       
   668 
       
   669             String localName = attr.getLocalName();
       
   670             String attrName = attr.getNodeName();
       
   671             String attrPrefix = attr.getPrefix() == null ? "" : attr.getPrefix();
       
   672             String attrValue = attr.getNodeValue();
       
   673 
       
   674             // Determine the Attr's type.
       
   675             String type = null;
       
   676             if (fIsLevel3DOM) {
       
   677                 type = ((Attr) attr).getSchemaTypeInfo().getTypeName();
       
   678             }
       
   679             type = type == null ? "CDATA" : type;
       
   680 
       
   681             String attrNS = attr.getNamespaceURI();
       
   682             if (attrNS !=null && attrNS.length() == 0) {
       
   683                 attrNS=null;
       
   684                 // we must remove prefix for this attribute
       
   685                 attrName=attr.getLocalName();
       
   686             }
       
   687 
       
   688             boolean isSpecified = ((Attr) attr).getSpecified();
       
   689             boolean addAttr = true;
       
   690             boolean applyFilter = false;
       
   691             boolean xmlnsAttr =
       
   692                 attrName.equals("xmlns") || attrName.startsWith("xmlns:");
       
   693 
       
   694             // well-formed=true
       
   695             if ((fFeatures & WELLFORMED) != 0) {
       
   696                 isAttributeWellFormed(attr);
       
   697             }
       
   698 
       
   699             //-----------------------------------------------------------------
       
   700             // start Attribute namespace fixup
       
   701             //-----------------------------------------------------------------
       
   702             // namespaces=true, normalize all non-namespace attributes
       
   703             // Step 3. Attribute
       
   704             if ((fFeatures & NAMESPACES) != 0 && !xmlnsAttr) {
       
   705 
       
   706                         // If the Attr has a namespace URI
       
   707                         if (attrNS != null) {
       
   708                                 attrPrefix = attrPrefix == null ? "" : attrPrefix;
       
   709 
       
   710                                 String declAttrPrefix = fNSBinder.getPrefix(attrNS);
       
   711                                 String declAttrNS = fNSBinder.getURI(attrPrefix);
       
   712 
       
   713                                 // attribute has no prefix (default namespace decl does not apply to
       
   714                                 // attributes)
       
   715                                 // OR
       
   716                                 // attribute prefix is not declared
       
   717                                 // OR
       
   718                                 // conflict: attribute has a prefix that conflicts with a binding
       
   719                                 if ("".equals(attrPrefix) || "".equals(declAttrPrefix)
       
   720                                                 || !attrPrefix.equals(declAttrPrefix)) {
       
   721 
       
   722                                         // namespaceURI matches an in scope declaration of one or
       
   723                                         // more prefixes
       
   724                                         if (declAttrPrefix != null && !"".equals(declAttrPrefix)) {
       
   725                                                 // pick the prefix that was found and change attribute's
       
   726                                                 // prefix and nodeName.
       
   727                                                 attrPrefix = declAttrPrefix;
       
   728 
       
   729                                                 if (declAttrPrefix.length() > 0 ) {
       
   730                                                         attrName = declAttrPrefix + ":" + localName;
       
   731                                                 } else {
       
   732                                                         attrName = localName;
       
   733                                                 }
       
   734                                         } else {
       
   735                                                 // The current prefix is not null and it has no in scope
       
   736                                                 // declaration
       
   737                                                 if (attrPrefix != null && !"".equals(attrPrefix)
       
   738                                                                 && declAttrNS == null) {
       
   739                                                         // declare this prefix
       
   740                                                         if ((fFeatures & NAMESPACEDECLS) != 0) {
       
   741                                                                 fSerializer.addAttribute(XMLNS_URI, attrPrefix,
       
   742                                                                                 XMLNS_PREFIX + ":" + attrPrefix, "CDATA",
       
   743                                                                                 attrNS);
       
   744                                                                 fNSBinder.declarePrefix(attrPrefix, attrNS);
       
   745                                                                 fLocalNSBinder.declarePrefix(attrPrefix, attrNS);
       
   746                                                         }
       
   747                                                 } else {
       
   748                                                         // find a prefix following the pattern "NS" +index
       
   749                                                         // (starting at 1)
       
   750                                                         // make sure this prefix is not declared in the current
       
   751                                                         // scope.
       
   752                                                         int counter = 1;
       
   753                                                         attrPrefix = "NS" + counter++;
       
   754 
       
   755                                                         while (fLocalNSBinder.getURI(attrPrefix) != null) {
       
   756                                                                 attrPrefix = "NS" + counter++;
       
   757                                                         }
       
   758                                                         // change attribute's prefix and Name
       
   759                                                         attrName = attrPrefix + ":" + localName;
       
   760 
       
   761                                                         // create a local namespace declaration attribute
       
   762                                                         // Add the xmlns declaration attribute
       
   763                                                         if ((fFeatures & NAMESPACEDECLS) != 0) {
       
   764 
       
   765                                                                 fSerializer.addAttribute(XMLNS_URI, attrPrefix,
       
   766                                                                                 XMLNS_PREFIX + ":" + attrPrefix, "CDATA",
       
   767                                                                                 attrNS);
       
   768                                                         fNSBinder.declarePrefix(attrPrefix, attrNS);
       
   769                                                         fLocalNSBinder.declarePrefix(attrPrefix, attrNS);
       
   770                                                         }
       
   771                                                 }
       
   772                                         }
       
   773                                 }
       
   774 
       
   775                         } else { // if the Attr has no namespace URI
       
   776                                 // Attr has no localName
       
   777                                 if (localName == null) {
       
   778                                         // DOM Level 1 node!
       
   779                                         String msg = Utils.messages.createMessage(
       
   780                                                         MsgKey.ER_NULL_LOCAL_ELEMENT_NAME,
       
   781                                                         new Object[] { attrName });
       
   782 
       
   783                                         if (fErrorHandler != null) {
       
   784                                                 fErrorHandler
       
   785                                                                 .handleError(new DOMErrorImpl(
       
   786                                                                                 DOMError.SEVERITY_ERROR, msg,
       
   787                                                                                 MsgKey.ER_NULL_LOCAL_ELEMENT_NAME, null,
       
   788                                                                                 null, null));
       
   789                                         }
       
   790 
       
   791                                 } else { // uri=null and no colon
       
   792                                         // attr has no namespace URI and no prefix
       
   793                                         // no action is required, since attrs don't use default
       
   794                                 }
       
   795                         }
       
   796 
       
   797             }
       
   798 
       
   799 
       
   800             // discard-default-content=true
       
   801             // Default attr's are not passed to the filter and this contraint
       
   802             // is applied only when discard-default-content=true
       
   803             // What about default xmlns attributes???? check for xmlnsAttr
       
   804             if ((((fFeatures & DISCARDDEFAULT) != 0) && isSpecified)
       
   805                 || ((fFeatures & DISCARDDEFAULT) == 0)) {
       
   806                 applyFilter = true;
       
   807             } else {
       
   808                 addAttr = false;
       
   809             }
       
   810 
       
   811             if (applyFilter) {
       
   812                 // apply the filter for Attributes that are not default attributes
       
   813                 // or namespace decl attributes
       
   814                 if (fFilter != null
       
   815                     && (fFilter.getWhatToShow() & NodeFilter.SHOW_ATTRIBUTE)
       
   816                         != 0) {
       
   817 
       
   818                     if (!xmlnsAttr) {
       
   819                         short code = fFilter.acceptNode(attr);
       
   820                         switch (code) {
       
   821                             case NodeFilter.FILTER_REJECT :
       
   822                             case NodeFilter.FILTER_SKIP :
       
   823                                 addAttr = false;
       
   824                                 break;
       
   825                             default : //fall through..
       
   826                         }
       
   827                     }
       
   828                 }
       
   829             }
       
   830 
       
   831             // if the node is a namespace node
       
   832             if (addAttr && xmlnsAttr) {
       
   833                 // If namespace-declarations=true, add the node , else don't add it
       
   834                 if ((fFeatures & NAMESPACEDECLS) != 0) {
       
   835                         // The namespace may have been fixed up, in that case don't add it.
       
   836                         if (localName != null && !"".equals(localName)) {
       
   837                                 fSerializer.addAttribute(attrNS, localName, attrName, type, attrValue);
       
   838                         }
       
   839                 }
       
   840             } else if (
       
   841                 addAttr && !xmlnsAttr) { // if the node is not a namespace node
       
   842                 // If namespace-declarations=true, add the node with the Attr nodes namespaceURI
       
   843                 // else add the node setting it's namespace to null or else the serializer will later
       
   844                 // attempt to add a xmlns attr for the prefixed attribute
       
   845                 if (((fFeatures & NAMESPACEDECLS) != 0) && (attrNS != null)) {
       
   846                     fSerializer.addAttribute(
       
   847                         attrNS,
       
   848                         localName,
       
   849                         attrName,
       
   850                         type,
       
   851                         attrValue);
       
   852                 } else {
       
   853                     fSerializer.addAttribute(
       
   854                         "",
       
   855                         localName,
       
   856                         attrName,
       
   857                         type,
       
   858                         attrValue);
       
   859                 }
       
   860             }
       
   861 
       
   862             //
       
   863             if (xmlnsAttr && ((fFeatures & NAMESPACEDECLS) != 0)) {
       
   864                 int index;
       
   865                 // Use "" instead of null, as Xerces likes "" for the
       
   866                 // name of the default namespace.  Fix attributed
       
   867                 // to "Steven Murray" <smurray@ebt.com>.
       
   868                 String prefix =
       
   869                     (index = attrName.indexOf(":")) < 0
       
   870                         ? ""
       
   871                         : attrName.substring(index + 1);
       
   872 
       
   873                 if (!"".equals(prefix)) {
       
   874                     fSerializer.namespaceAfterStartElement(prefix, attrValue);
       
   875                 }
       
   876             }
       
   877         }
       
   878 
       
   879     }
       
   880 
       
   881     /**
       
   882      * Serializes an ProcessingInstruction Node.
       
   883      *
       
   884      * @param node The ProcessingInstruction Node to serialize
       
   885      */
       
   886     protected void serializePI(ProcessingInstruction node)
       
   887         throws SAXException {
       
   888         ProcessingInstruction pi = node;
       
   889         String name = pi.getNodeName();
       
   890 
       
   891         // well-formed=true
       
   892         if ((fFeatures & WELLFORMED) != 0) {
       
   893             isPIWellFormed(node);
       
   894         }
       
   895 
       
   896         // apply the LSSerializer filter
       
   897         if (!applyFilter(node, NodeFilter.SHOW_PROCESSING_INSTRUCTION)) {
       
   898             return;
       
   899         }
       
   900 
       
   901         // String data = pi.getData();
       
   902         if (name.equals("xslt-next-is-raw")) {
       
   903             fNextIsRaw = true;
       
   904         } else {
       
   905             this.fSerializer.processingInstruction(name, pi.getData());
       
   906         }
       
   907     }
       
   908 
       
   909     /**
       
   910      * Serializes an CDATASection Node.
       
   911      *
       
   912      * @param node The CDATASection Node to serialize
       
   913      */
       
   914     protected void serializeCDATASection(CDATASection node)
       
   915         throws SAXException {
       
   916         // well-formed=true
       
   917         if ((fFeatures & WELLFORMED) != 0) {
       
   918             isCDATASectionWellFormed(node);
       
   919         }
       
   920 
       
   921         // cdata-sections = true
       
   922         if ((fFeatures & CDATA) != 0) {
       
   923 
       
   924             // split-cdata-sections = true
       
   925             // Assumption: This parameter has an effect only when
       
   926                         // cdata-sections=true
       
   927             // ToStream, by default splits cdata-sections. Hence the check
       
   928                         // below.
       
   929             String nodeValue = node.getNodeValue();
       
   930             int endIndex = nodeValue.indexOf("]]>");
       
   931             if ((fFeatures & SPLITCDATA) != 0) {
       
   932                 if (endIndex >= 0) {
       
   933                     // The first node split will contain the ]] markers
       
   934                     String relatedData = nodeValue.substring(0, endIndex + 2);
       
   935 
       
   936                     String msg =
       
   937                         Utils.messages.createMessage(
       
   938                             MsgKey.ER_CDATA_SECTIONS_SPLIT,
       
   939                             null);
       
   940 
       
   941                     if (fErrorHandler != null) {
       
   942                         fErrorHandler.handleError(
       
   943                             new DOMErrorImpl(
       
   944                                 DOMError.SEVERITY_WARNING,
       
   945                                 msg,
       
   946                                 MsgKey.ER_CDATA_SECTIONS_SPLIT,
       
   947                                 null,
       
   948                                 relatedData,
       
   949                                 null));
       
   950                     }
       
   951                 }
       
   952             } else {
       
   953                 if (endIndex >= 0) {
       
   954                     // The first node split will contain the ]] markers
       
   955                     String relatedData = nodeValue.substring(0, endIndex + 2);
       
   956 
       
   957                     String msg =
       
   958                         Utils.messages.createMessage(
       
   959                             MsgKey.ER_CDATA_SECTIONS_SPLIT,
       
   960                             null);
       
   961 
       
   962                     if (fErrorHandler != null) {
       
   963                         fErrorHandler.handleError(
       
   964                             new DOMErrorImpl(
       
   965                                 DOMError.SEVERITY_ERROR,
       
   966                                 msg,
       
   967                                 MsgKey.ER_CDATA_SECTIONS_SPLIT));
       
   968                     }
       
   969                     // Report an error and return.  What error???
       
   970                     return;
       
   971                 }
       
   972             }
       
   973 
       
   974             // apply the LSSerializer filter
       
   975             if (!applyFilter(node, NodeFilter.SHOW_CDATA_SECTION)) {
       
   976                 return;
       
   977             }
       
   978 
       
   979             // splits the cdata-section
       
   980             if (fLexicalHandler != null) {
       
   981                 fLexicalHandler.startCDATA();
       
   982             }
       
   983             dispatachChars(node);
       
   984             if (fLexicalHandler != null) {
       
   985                 fLexicalHandler.endCDATA();
       
   986             }
       
   987         } else {
       
   988             dispatachChars(node);
       
   989         }
       
   990     }
       
   991 
       
   992     /**
       
   993      * Serializes an Text Node.
       
   994      *
       
   995      * @param node The Text Node to serialize
       
   996      */
       
   997     protected void serializeText(Text node) throws SAXException {
       
   998         if (fNextIsRaw) {
       
   999             fNextIsRaw = false;
       
  1000             fSerializer.processingInstruction(
       
  1001                 javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING,
       
  1002                 "");
       
  1003             dispatachChars(node);
       
  1004             fSerializer.processingInstruction(
       
  1005                 javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING,
       
  1006                 "");
       
  1007         } else {
       
  1008             // keep track of dispatch or not to avoid duplicaiton of filter code
       
  1009             boolean bDispatch = false;
       
  1010 
       
  1011             // well-formed=true
       
  1012             if ((fFeatures & WELLFORMED) != 0) {
       
  1013                 isTextWellFormed(node);
       
  1014             }
       
  1015 
       
  1016             // if the node is whitespace
       
  1017             // Determine the Attr's type.
       
  1018             boolean isElementContentWhitespace = false;
       
  1019             if (fIsLevel3DOM) {
       
  1020                 isElementContentWhitespace =
       
  1021                        node.isElementContentWhitespace();
       
  1022             }
       
  1023 
       
  1024             if (isElementContentWhitespace) {
       
  1025                 // element-content-whitespace=true
       
  1026                 if ((fFeatures & ELEM_CONTENT_WHITESPACE) != 0) {
       
  1027                     bDispatch = true;
       
  1028                 }
       
  1029             } else {
       
  1030                 bDispatch = true;
       
  1031             }
       
  1032 
       
  1033             // apply the LSSerializer filter
       
  1034             if (!applyFilter(node, NodeFilter.SHOW_TEXT)) {
       
  1035                 return;
       
  1036             }
       
  1037 
       
  1038             if (bDispatch) {
       
  1039                 dispatachChars(node);
       
  1040             }
       
  1041         }
       
  1042     }
       
  1043 
       
  1044     /**
       
  1045      * Serializes an EntityReference Node.
       
  1046      *
       
  1047      * @param node The EntityReference Node to serialize
       
  1048      * @param bStart Inicates if called from start or endNode
       
  1049      */
       
  1050     protected void serializeEntityReference(
       
  1051         EntityReference node,
       
  1052         boolean bStart)
       
  1053         throws SAXException {
       
  1054         if (bStart) {
       
  1055             EntityReference eref = node;
       
  1056             // entities=true
       
  1057             if ((fFeatures & ENTITIES) != 0) {
       
  1058 
       
  1059                 // perform well-formedness and other checking only if
       
  1060                 // entities = true
       
  1061 
       
  1062                 // well-formed=true
       
  1063                 if ((fFeatures & WELLFORMED) != 0) {
       
  1064                     isEntityReferneceWellFormed(node);
       
  1065                 }
       
  1066 
       
  1067                 // check "unbound-prefix-in-entity-reference" [fatal]
       
  1068                 // Raised if the configuration parameter "namespaces" is set to true
       
  1069                 if ((fFeatures & NAMESPACES) != 0) {
       
  1070                     checkUnboundPrefixInEntRef(node);
       
  1071                 }
       
  1072 
       
  1073                 // The filter should not apply in this case, since the
       
  1074                 // EntityReference is not being expanded.
       
  1075                 // should we pass entity reference nodes to the filter???
       
  1076             }
       
  1077 
       
  1078             if (fLexicalHandler != null) {
       
  1079 
       
  1080                 // startEntity outputs only Text but not Element, Attr, Comment
       
  1081                 // and PI child nodes.  It does so by setting the m_inEntityRef
       
  1082                 // in ToStream and using this to decide if a node is to be
       
  1083                 // serialized or not.
       
  1084                 fLexicalHandler.startEntity(eref.getNodeName());
       
  1085             }
       
  1086 
       
  1087         } else {
       
  1088             EntityReference eref = node;
       
  1089             // entities=true or false,
       
  1090             if (fLexicalHandler != null) {
       
  1091                 fLexicalHandler.endEntity(eref.getNodeName());
       
  1092             }
       
  1093         }
       
  1094     }
       
  1095 
       
  1096 
       
  1097     // ***********************************************************************
       
  1098     // Methods to check well-formedness
       
  1099     // ***********************************************************************
       
  1100     /**
       
  1101      * Taken from org.apache.xerces.dom.CoreDocumentImpl
       
  1102      *
       
  1103      * Check the string against XML's definition of acceptable names for
       
  1104      * elements and attributes and so on using the XMLCharacterProperties
       
  1105      * utility class
       
  1106      */
       
  1107     protected boolean isXMLName(String s, boolean xml11Version) {
       
  1108 
       
  1109         if (s == null) {
       
  1110             return false;
       
  1111         }
       
  1112         if (!xml11Version)
       
  1113             return XMLChar.isValidName(s);
       
  1114         else
       
  1115             return XML11Char.isXML11ValidName(s);
       
  1116     }
       
  1117 
       
  1118     /**
       
  1119      * Taken from org.apache.xerces.dom.CoreDocumentImpl
       
  1120      *
       
  1121      * Checks if the given qualified name is legal with respect
       
  1122      * to the version of XML to which this document must conform.
       
  1123      *
       
  1124      * @param prefix prefix of qualified name
       
  1125      * @param local local part of qualified name
       
  1126      */
       
  1127     protected boolean isValidQName(
       
  1128         String prefix,
       
  1129         String local,
       
  1130         boolean xml11Version) {
       
  1131 
       
  1132         // check that both prefix and local part match NCName
       
  1133         if (local == null)
       
  1134             return false;
       
  1135         boolean validNCName = false;
       
  1136 
       
  1137         if (!xml11Version) {
       
  1138             validNCName =
       
  1139                 (prefix == null || XMLChar.isValidNCName(prefix))
       
  1140                     && XMLChar.isValidNCName(local);
       
  1141         } else {
       
  1142             validNCName =
       
  1143                 (prefix == null || XML11Char.isXML11ValidNCName(prefix))
       
  1144                     && XML11Char.isXML11ValidNCName(local);
       
  1145         }
       
  1146 
       
  1147         return validNCName;
       
  1148     }
       
  1149 
       
  1150     /**
       
  1151      * Checks if a XML character is well-formed
       
  1152      *
       
  1153      * @param characters A String of characters to be checked for Well-Formedness
       
  1154      * @param refInvalidChar A reference to the character to be returned that was determined invalid.
       
  1155      */
       
  1156     protected boolean isWFXMLChar(String chardata, Character refInvalidChar) {
       
  1157         if (chardata == null || (chardata.length() == 0)) {
       
  1158             return true;
       
  1159         }
       
  1160 
       
  1161         char[] dataarray = chardata.toCharArray();
       
  1162         int datalength = dataarray.length;
       
  1163 
       
  1164         // version of the document is XML 1.1
       
  1165         if (fIsXMLVersion11) {
       
  1166             //we need to check all characters as per production rules of XML11
       
  1167             int i = 0;
       
  1168             while (i < datalength) {
       
  1169                 if (XML11Char.isXML11Invalid(dataarray[i++])) {
       
  1170                     // check if this is a supplemental character
       
  1171                     char ch = dataarray[i - 1];
       
  1172                     if (XMLChar.isHighSurrogate(ch) && i < datalength) {
       
  1173                         char ch2 = dataarray[i++];
       
  1174                         if (XMLChar.isLowSurrogate(ch2)
       
  1175                             && XMLChar.isSupplemental(
       
  1176                                 XMLChar.supplemental(ch, ch2))) {
       
  1177                             continue;
       
  1178                         }
       
  1179                     }
       
  1180                     // Reference to invalid character which is returned
       
  1181                     refInvalidChar = new Character(ch);
       
  1182                     return false;
       
  1183                 }
       
  1184             }
       
  1185         } // version of the document is XML 1.0
       
  1186         else {
       
  1187             // we need to check all characters as per production rules of XML 1.0
       
  1188             int i = 0;
       
  1189             while (i < datalength) {
       
  1190                 if (XMLChar.isInvalid(dataarray[i++])) {
       
  1191                     // check if this is a supplemental character
       
  1192                     char ch = dataarray[i - 1];
       
  1193                     if (XMLChar.isHighSurrogate(ch) && i < datalength) {
       
  1194                         char ch2 = dataarray[i++];
       
  1195                         if (XMLChar.isLowSurrogate(ch2)
       
  1196                             && XMLChar.isSupplemental(
       
  1197                                 XMLChar.supplemental(ch, ch2))) {
       
  1198                             continue;
       
  1199                         }
       
  1200                     }
       
  1201                     // Reference to invalid character which is returned
       
  1202                     refInvalidChar = new Character(ch);
       
  1203                     return false;
       
  1204                 }
       
  1205             }
       
  1206         } // end-else fDocument.isXMLVersion()
       
  1207 
       
  1208         return true;
       
  1209     } // isXMLCharWF
       
  1210 
       
  1211     /**
       
  1212      * Checks if a XML character is well-formed.  If there is a problem with
       
  1213      * the character a non-null Character is returned else null is returned.
       
  1214      *
       
  1215      * @param characters A String of characters to be checked for Well-Formedness
       
  1216      * @return Character A reference to the character to be returned that was determined invalid.
       
  1217      */
       
  1218     protected Character isWFXMLChar(String chardata) {
       
  1219         Character refInvalidChar;
       
  1220         if (chardata == null || (chardata.length() == 0)) {
       
  1221             return null;
       
  1222         }
       
  1223 
       
  1224         char[] dataarray = chardata.toCharArray();
       
  1225         int datalength = dataarray.length;
       
  1226 
       
  1227         // version of the document is XML 1.1
       
  1228         if (fIsXMLVersion11) {
       
  1229             //we need to check all characters as per production rules of XML11
       
  1230             int i = 0;
       
  1231             while (i < datalength) {
       
  1232                 if (XML11Char.isXML11Invalid(dataarray[i++])) {
       
  1233                     // check if this is a supplemental character
       
  1234                     char ch = dataarray[i - 1];
       
  1235                     if (XMLChar.isHighSurrogate(ch) && i < datalength) {
       
  1236                         char ch2 = dataarray[i++];
       
  1237                         if (XMLChar.isLowSurrogate(ch2)
       
  1238                             && XMLChar.isSupplemental(
       
  1239                                 XMLChar.supplemental(ch, ch2))) {
       
  1240                             continue;
       
  1241                         }
       
  1242                     }
       
  1243                     // Reference to invalid character which is returned
       
  1244                     refInvalidChar = new Character(ch);
       
  1245                     return refInvalidChar;
       
  1246                 }
       
  1247             }
       
  1248         } // version of the document is XML 1.0
       
  1249         else {
       
  1250             // we need to check all characters as per production rules of XML 1.0
       
  1251             int i = 0;
       
  1252             while (i < datalength) {
       
  1253                 if (XMLChar.isInvalid(dataarray[i++])) {
       
  1254                     // check if this is a supplemental character
       
  1255                     char ch = dataarray[i - 1];
       
  1256                     if (XMLChar.isHighSurrogate(ch) && i < datalength) {
       
  1257                         char ch2 = dataarray[i++];
       
  1258                         if (XMLChar.isLowSurrogate(ch2)
       
  1259                             && XMLChar.isSupplemental(
       
  1260                                 XMLChar.supplemental(ch, ch2))) {
       
  1261                             continue;
       
  1262                         }
       
  1263                     }
       
  1264                     // Reference to invalid character which is returned
       
  1265                     refInvalidChar = new Character(ch);
       
  1266                     return refInvalidChar;
       
  1267                 }
       
  1268             }
       
  1269         } // end-else fDocument.isXMLVersion()
       
  1270 
       
  1271         return null;
       
  1272     } // isXMLCharWF
       
  1273 
       
  1274     /**
       
  1275      * Checks if a comment node is well-formed
       
  1276      *
       
  1277      * @param data The contents of the comment node
       
  1278      * @return a boolean indiacating if the comment is well-formed or not.
       
  1279      */
       
  1280     protected void isCommentWellFormed(String data) {
       
  1281         if (data == null || (data.length() == 0)) {
       
  1282             return;
       
  1283         }
       
  1284 
       
  1285         char[] dataarray = data.toCharArray();
       
  1286         int datalength = dataarray.length;
       
  1287 
       
  1288         // version of the document is XML 1.1
       
  1289         if (fIsXMLVersion11) {
       
  1290             // we need to check all chracters as per production rules of XML11
       
  1291             int i = 0;
       
  1292             while (i < datalength) {
       
  1293                 char c = dataarray[i++];
       
  1294                 if (XML11Char.isXML11Invalid(c)) {
       
  1295                     // check if this is a supplemental character
       
  1296                     if (XMLChar.isHighSurrogate(c) && i < datalength) {
       
  1297                         char c2 = dataarray[i++];
       
  1298                         if (XMLChar.isLowSurrogate(c2)
       
  1299                             && XMLChar.isSupplemental(
       
  1300                                 XMLChar.supplemental(c, c2))) {
       
  1301                             continue;
       
  1302                         }
       
  1303                     }
       
  1304                     String msg =
       
  1305                         Utils.messages.createMessage(
       
  1306                             MsgKey.ER_WF_INVALID_CHARACTER_IN_COMMENT,
       
  1307                             new Object[] { new Character(c)});
       
  1308 
       
  1309                     if (fErrorHandler != null) {
       
  1310                         fErrorHandler.handleError(
       
  1311                             new DOMErrorImpl(
       
  1312                                 DOMError.SEVERITY_FATAL_ERROR,
       
  1313                                 msg,
       
  1314                                 MsgKey.ER_WF_INVALID_CHARACTER,
       
  1315                                 null,
       
  1316                                 null,
       
  1317                                 null));
       
  1318                     }
       
  1319                 } else if (c == '-' && i < datalength && dataarray[i] == '-') {
       
  1320                     String msg =
       
  1321                         Utils.messages.createMessage(
       
  1322                             MsgKey.ER_WF_DASH_IN_COMMENT,
       
  1323                             null);
       
  1324 
       
  1325                     if (fErrorHandler != null) {
       
  1326                         fErrorHandler.handleError(
       
  1327                             new DOMErrorImpl(
       
  1328                                 DOMError.SEVERITY_FATAL_ERROR,
       
  1329                                 msg,
       
  1330                                 MsgKey.ER_WF_INVALID_CHARACTER,
       
  1331                                 null,
       
  1332                                 null,
       
  1333                                 null));
       
  1334                     }
       
  1335                 }
       
  1336             }
       
  1337         } // version of the document is XML 1.0
       
  1338         else {
       
  1339             // we need to check all chracters as per production rules of XML 1.0
       
  1340             int i = 0;
       
  1341             while (i < datalength) {
       
  1342                 char c = dataarray[i++];
       
  1343                 if (XMLChar.isInvalid(c)) {
       
  1344                     // check if this is a supplemental character
       
  1345                     if (XMLChar.isHighSurrogate(c) && i < datalength) {
       
  1346                         char c2 = dataarray[i++];
       
  1347                         if (XMLChar.isLowSurrogate(c2)
       
  1348                             && XMLChar.isSupplemental(
       
  1349                                 XMLChar.supplemental(c, c2))) {
       
  1350                             continue;
       
  1351                         }
       
  1352                     }
       
  1353                     String msg =
       
  1354                         Utils.messages.createMessage(
       
  1355                             MsgKey.ER_WF_INVALID_CHARACTER_IN_COMMENT,
       
  1356                             new Object[] { new Character(c)});
       
  1357 
       
  1358                     if (fErrorHandler != null) {
       
  1359                         fErrorHandler.handleError(
       
  1360                             new DOMErrorImpl(
       
  1361                                 DOMError.SEVERITY_FATAL_ERROR,
       
  1362                                 msg,
       
  1363                                 MsgKey.ER_WF_INVALID_CHARACTER,
       
  1364                                 null,
       
  1365                                 null,
       
  1366                                 null));
       
  1367                     }
       
  1368                 } else if (c == '-' && i < datalength && dataarray[i] == '-') {
       
  1369                     String msg =
       
  1370                         Utils.messages.createMessage(
       
  1371                             MsgKey.ER_WF_DASH_IN_COMMENT,
       
  1372                             null);
       
  1373 
       
  1374                     if (fErrorHandler != null) {
       
  1375                         fErrorHandler.handleError(
       
  1376                             new DOMErrorImpl(
       
  1377                                 DOMError.SEVERITY_FATAL_ERROR,
       
  1378                                 msg,
       
  1379                                 MsgKey.ER_WF_INVALID_CHARACTER,
       
  1380                                 null,
       
  1381                                 null,
       
  1382                                 null));
       
  1383                     }
       
  1384                 }
       
  1385             }
       
  1386         }
       
  1387         return;
       
  1388     }
       
  1389 
       
  1390     /**
       
  1391      * Checks if an element node is well-formed, by checking its Name for well-formedness.
       
  1392      *
       
  1393      * @param data The contents of the comment node
       
  1394      * @return a boolean indiacating if the comment is well-formed or not.
       
  1395      */
       
  1396     protected void isElementWellFormed(Node node) {
       
  1397         boolean isNameWF = false;
       
  1398         if ((fFeatures & NAMESPACES) != 0) {
       
  1399             isNameWF =
       
  1400                 isValidQName(
       
  1401                     node.getPrefix(),
       
  1402                     node.getLocalName(),
       
  1403                     fIsXMLVersion11);
       
  1404         } else {
       
  1405             isNameWF = isXMLName(node.getNodeName(), fIsXMLVersion11);
       
  1406         }
       
  1407 
       
  1408         if (!isNameWF) {
       
  1409             String msg =
       
  1410                 Utils.messages.createMessage(
       
  1411                     MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1412                     new Object[] { "Element", node.getNodeName()});
       
  1413 
       
  1414             if (fErrorHandler != null) {
       
  1415                 fErrorHandler.handleError(
       
  1416                     new DOMErrorImpl(
       
  1417                         DOMError.SEVERITY_FATAL_ERROR,
       
  1418                         msg,
       
  1419                         MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1420                         null,
       
  1421                         null,
       
  1422                         null));
       
  1423             }
       
  1424         }
       
  1425     }
       
  1426 
       
  1427     /**
       
  1428      * Checks if an attr node is well-formed, by checking it's Name and value
       
  1429      * for well-formedness.
       
  1430      *
       
  1431      * @param data The contents of the comment node
       
  1432      * @return a boolean indiacating if the comment is well-formed or not.
       
  1433      */
       
  1434     protected void isAttributeWellFormed(Node node) {
       
  1435         boolean isNameWF = false;
       
  1436         if ((fFeatures & NAMESPACES) != 0) {
       
  1437             isNameWF =
       
  1438                 isValidQName(
       
  1439                     node.getPrefix(),
       
  1440                     node.getLocalName(),
       
  1441                     fIsXMLVersion11);
       
  1442         } else {
       
  1443             isNameWF = isXMLName(node.getNodeName(), fIsXMLVersion11);
       
  1444         }
       
  1445 
       
  1446         if (!isNameWF) {
       
  1447             String msg =
       
  1448                 Utils.messages.createMessage(
       
  1449                     MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1450                     new Object[] { "Attr", node.getNodeName()});
       
  1451 
       
  1452             if (fErrorHandler != null) {
       
  1453                 fErrorHandler.handleError(
       
  1454                     new DOMErrorImpl(
       
  1455                         DOMError.SEVERITY_FATAL_ERROR,
       
  1456                         msg,
       
  1457                         MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1458                         null,
       
  1459                         null,
       
  1460                         null));
       
  1461             }
       
  1462         }
       
  1463 
       
  1464         // Check the Attr's node value
       
  1465         // WFC: No < in Attribute Values
       
  1466         String value = node.getNodeValue();
       
  1467         if (value.indexOf('<') >= 0) {
       
  1468             String msg =
       
  1469                 Utils.messages.createMessage(
       
  1470                     MsgKey.ER_WF_LT_IN_ATTVAL,
       
  1471                     new Object[] {
       
  1472                         ((Attr) node).getOwnerElement().getNodeName(),
       
  1473                         node.getNodeName()});
       
  1474 
       
  1475             if (fErrorHandler != null) {
       
  1476                 fErrorHandler.handleError(
       
  1477                     new DOMErrorImpl(
       
  1478                         DOMError.SEVERITY_FATAL_ERROR,
       
  1479                         msg,
       
  1480                         MsgKey.ER_WF_LT_IN_ATTVAL,
       
  1481                         null,
       
  1482                         null,
       
  1483                         null));
       
  1484             }
       
  1485         }
       
  1486 
       
  1487         // we need to loop through the children of attr nodes and check their values for
       
  1488         // well-formedness
       
  1489         NodeList children = node.getChildNodes();
       
  1490         for (int i = 0; i < children.getLength(); i++) {
       
  1491             Node child = children.item(i);
       
  1492             // An attribute node with no text or entity ref child for example
       
  1493             // doc.createAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ns");
       
  1494             // followes by
       
  1495             // element.setAttributeNodeNS(attribute);
       
  1496             // can potentially lead to this situation.  If the attribute
       
  1497             // was a prefix Namespace attribute declaration then then DOM Core
       
  1498             // should have some exception defined for this.
       
  1499             if (child == null) {
       
  1500                 // we should probably report an error
       
  1501                 continue;
       
  1502             }
       
  1503             switch (child.getNodeType()) {
       
  1504                 case Node.TEXT_NODE :
       
  1505                     isTextWellFormed((Text) child);
       
  1506                     break;
       
  1507                 case Node.ENTITY_REFERENCE_NODE :
       
  1508                     isEntityReferneceWellFormed((EntityReference) child);
       
  1509                     break;
       
  1510                 default :
       
  1511             }
       
  1512         }
       
  1513 
       
  1514         // TODO:
       
  1515         // WFC: Check if the attribute prefix is bound to
       
  1516         // http://www.w3.org/2000/xmlns/
       
  1517 
       
  1518         // WFC: Unique Att Spec
       
  1519         // Perhaps pass a seen boolean value to this method.  serializeAttList will determine
       
  1520         // if the attr was seen before.
       
  1521     }
       
  1522 
       
  1523     /**
       
  1524      * Checks if a PI node is well-formed, by checking it's Name and data
       
  1525      * for well-formedness.
       
  1526      *
       
  1527      * @param data The contents of the comment node
       
  1528      */
       
  1529     protected void isPIWellFormed(ProcessingInstruction node) {
       
  1530         // Is the PI Target a valid XML name
       
  1531         if (!isXMLName(node.getNodeName(), fIsXMLVersion11)) {
       
  1532             String msg =
       
  1533                 Utils.messages.createMessage(
       
  1534                     MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1535                     new Object[] { "ProcessingInstruction", node.getTarget()});
       
  1536 
       
  1537             if (fErrorHandler != null) {
       
  1538                 fErrorHandler.handleError(
       
  1539                     new DOMErrorImpl(
       
  1540                         DOMError.SEVERITY_FATAL_ERROR,
       
  1541                         msg,
       
  1542                         MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1543                         null,
       
  1544                         null,
       
  1545                         null));
       
  1546             }
       
  1547         }
       
  1548 
       
  1549         // Does the PI Data carry valid XML characters
       
  1550 
       
  1551         // REVISIT: Should we check if the PI DATA contains a ?> ???
       
  1552         Character invalidChar = isWFXMLChar(node.getData());
       
  1553         if (invalidChar != null) {
       
  1554             String msg =
       
  1555                 Utils.messages.createMessage(
       
  1556                     MsgKey.ER_WF_INVALID_CHARACTER_IN_PI,
       
  1557                     new Object[] { Integer.toHexString(Character.getNumericValue(invalidChar.charValue())) });
       
  1558 
       
  1559             if (fErrorHandler != null) {
       
  1560                 fErrorHandler.handleError(
       
  1561                     new DOMErrorImpl(
       
  1562                         DOMError.SEVERITY_FATAL_ERROR,
       
  1563                         msg,
       
  1564                         MsgKey.ER_WF_INVALID_CHARACTER,
       
  1565                         null,
       
  1566                         null,
       
  1567                         null));
       
  1568             }
       
  1569         }
       
  1570     }
       
  1571 
       
  1572     /**
       
  1573      * Checks if an CDATASection node is well-formed, by checking it's data
       
  1574      * for well-formedness.  Note that the presence of a CDATA termination mark
       
  1575      * in the contents of a CDATASection is handled by the parameter
       
  1576      * spli-cdata-sections
       
  1577      *
       
  1578      * @param data The contents of the comment node
       
  1579      */
       
  1580     protected void isCDATASectionWellFormed(CDATASection node) {
       
  1581         // Does the data valid XML character data
       
  1582         Character invalidChar = isWFXMLChar(node.getData());
       
  1583         //if (!isWFXMLChar(node.getData(), invalidChar)) {
       
  1584         if (invalidChar != null) {
       
  1585             String msg =
       
  1586                 Utils.messages.createMessage(
       
  1587                     MsgKey.ER_WF_INVALID_CHARACTER_IN_CDATA,
       
  1588                     new Object[] { Integer.toHexString(Character.getNumericValue(invalidChar.charValue())) });
       
  1589 
       
  1590             if (fErrorHandler != null) {
       
  1591                 fErrorHandler.handleError(
       
  1592                     new DOMErrorImpl(
       
  1593                         DOMError.SEVERITY_FATAL_ERROR,
       
  1594                         msg,
       
  1595                         MsgKey.ER_WF_INVALID_CHARACTER,
       
  1596                         null,
       
  1597                         null,
       
  1598                         null));
       
  1599             }
       
  1600         }
       
  1601     }
       
  1602 
       
  1603     /**
       
  1604      * Checks if an Text node is well-formed, by checking if it contains invalid
       
  1605      * XML characters.
       
  1606      *
       
  1607      * @param data The contents of the comment node
       
  1608      */
       
  1609     protected void isTextWellFormed(Text node) {
       
  1610         // Does the data valid XML character data
       
  1611         Character invalidChar = isWFXMLChar(node.getData());
       
  1612         if (invalidChar != null) {
       
  1613             String msg =
       
  1614                 Utils.messages.createMessage(
       
  1615                     MsgKey.ER_WF_INVALID_CHARACTER_IN_TEXT,
       
  1616                     new Object[] { Integer.toHexString(Character.getNumericValue(invalidChar.charValue())) });
       
  1617 
       
  1618             if (fErrorHandler != null) {
       
  1619                 fErrorHandler.handleError(
       
  1620                     new DOMErrorImpl(
       
  1621                         DOMError.SEVERITY_FATAL_ERROR,
       
  1622                         msg,
       
  1623                         MsgKey.ER_WF_INVALID_CHARACTER,
       
  1624                         null,
       
  1625                         null,
       
  1626                         null));
       
  1627             }
       
  1628         }
       
  1629     }
       
  1630 
       
  1631     /**
       
  1632      * Checks if an EntityRefernece node is well-formed, by checking it's node name.  Then depending
       
  1633      * on whether it is referenced in Element content or in an Attr Node, checks if the EntityReference
       
  1634      * references an unparsed entity or a external entity and if so throws raises the
       
  1635      * appropriate well-formedness error.
       
  1636      *
       
  1637      * @param data The contents of the comment node
       
  1638      * @parent The parent of the EntityReference Node
       
  1639      */
       
  1640     protected void isEntityReferneceWellFormed(EntityReference node) {
       
  1641         // Is the EntityReference name a valid XML name
       
  1642         if (!isXMLName(node.getNodeName(), fIsXMLVersion11)) {
       
  1643             String msg =
       
  1644                 Utils.messages.createMessage(
       
  1645                     MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1646                     new Object[] { "EntityReference", node.getNodeName()});
       
  1647 
       
  1648             if (fErrorHandler != null) {
       
  1649                 fErrorHandler.handleError(
       
  1650                     new DOMErrorImpl(
       
  1651                         DOMError.SEVERITY_FATAL_ERROR,
       
  1652                         msg,
       
  1653                         MsgKey.ER_WF_INVALID_CHARACTER_IN_NODE_NAME,
       
  1654                         null,
       
  1655                         null,
       
  1656                         null));
       
  1657             }
       
  1658         }
       
  1659 
       
  1660         // determine the parent node
       
  1661         Node parent = node.getParentNode();
       
  1662 
       
  1663         // Traverse the declared entities and check if the nodeName and namespaceURI
       
  1664         // of the EntityReference matches an Entity.  If so, check the if the notationName
       
  1665         // is not null, if so, report an error.
       
  1666         DocumentType docType = node.getOwnerDocument().getDoctype();
       
  1667         if (docType != null) {
       
  1668             NamedNodeMap entities = docType.getEntities();
       
  1669             for (int i = 0; i < entities.getLength(); i++) {
       
  1670                 Entity ent = (Entity) entities.item(i);
       
  1671 
       
  1672                 String nodeName =
       
  1673                     node.getNodeName() == null ? "" : node.getNodeName();
       
  1674                 String nodeNamespaceURI =
       
  1675                     node.getNamespaceURI() == null
       
  1676                         ? ""
       
  1677                         : node.getNamespaceURI();
       
  1678                 String entName =
       
  1679                     ent.getNodeName() == null ? "" : ent.getNodeName();
       
  1680                 String entNamespaceURI =
       
  1681                     ent.getNamespaceURI() == null ? "" : ent.getNamespaceURI();
       
  1682                 // If referenced in Element content
       
  1683                 // WFC: Parsed Entity
       
  1684                 if (parent.getNodeType() == Node.ELEMENT_NODE) {
       
  1685                     if (entNamespaceURI.equals(nodeNamespaceURI)
       
  1686                         && entName.equals(nodeName)) {
       
  1687 
       
  1688                         if (ent.getNotationName() != null) {
       
  1689                             String msg =
       
  1690                                 Utils.messages.createMessage(
       
  1691                                     MsgKey.ER_WF_REF_TO_UNPARSED_ENT,
       
  1692                                     new Object[] { node.getNodeName()});
       
  1693 
       
  1694                             if (fErrorHandler != null) {
       
  1695                                 fErrorHandler.handleError(
       
  1696                                     new DOMErrorImpl(
       
  1697                                         DOMError.SEVERITY_FATAL_ERROR,
       
  1698                                         msg,
       
  1699                                         MsgKey.ER_WF_REF_TO_UNPARSED_ENT,
       
  1700                                         null,
       
  1701                                         null,
       
  1702                                         null));
       
  1703                             }
       
  1704                         }
       
  1705                     }
       
  1706                 } // end if WFC: Parsed Entity
       
  1707 
       
  1708                 // If referenced in an Attr value
       
  1709                 // WFC: No External Entity References
       
  1710                 if (parent.getNodeType() == Node.ATTRIBUTE_NODE) {
       
  1711                     if (entNamespaceURI.equals(nodeNamespaceURI)
       
  1712                         && entName.equals(nodeName)) {
       
  1713 
       
  1714                         if (ent.getPublicId() != null
       
  1715                             || ent.getSystemId() != null
       
  1716                             || ent.getNotationName() != null) {
       
  1717                             String msg =
       
  1718                                 Utils.messages.createMessage(
       
  1719                                     MsgKey.ER_WF_REF_TO_EXTERNAL_ENT,
       
  1720                                     new Object[] { node.getNodeName()});
       
  1721 
       
  1722                             if (fErrorHandler != null) {
       
  1723                                 fErrorHandler.handleError(
       
  1724                                     new DOMErrorImpl(
       
  1725                                         DOMError.SEVERITY_FATAL_ERROR,
       
  1726                                         msg,
       
  1727                                         MsgKey.ER_WF_REF_TO_EXTERNAL_ENT,
       
  1728                                         null,
       
  1729                                         null,
       
  1730                                         null));
       
  1731                             }
       
  1732                         }
       
  1733                     }
       
  1734                 } //end if WFC: No External Entity References
       
  1735             }
       
  1736         }
       
  1737     } // isEntityReferneceWellFormed
       
  1738 
       
  1739     /**
       
  1740      * If the configuration parameter "namespaces" is set to true, this methods
       
  1741      * checks if an entity whose replacement text contains unbound namespace
       
  1742      * prefixes is referenced in a location where there are no bindings for
       
  1743      * the namespace prefixes and if so raises a LSException with the error-type
       
  1744      * "unbound-prefix-in-entity-reference"
       
  1745      *
       
  1746      * @param Node, The EntityReference nodes whose children are to be checked
       
  1747      */
       
  1748     protected void checkUnboundPrefixInEntRef(Node node) {
       
  1749         Node child, next;
       
  1750         for (child = node.getFirstChild(); child != null; child = next) {
       
  1751             next = child.getNextSibling();
       
  1752 
       
  1753             if (child.getNodeType() == Node.ELEMENT_NODE) {
       
  1754 
       
  1755                 //If a NamespaceURI is not declared for the current
       
  1756                 //node's prefix, raise a fatal error.
       
  1757                 String prefix = child.getPrefix();
       
  1758                 if (prefix != null
       
  1759                                 && fNSBinder.getURI(prefix) == null) {
       
  1760                     String msg =
       
  1761                         Utils.messages.createMessage(
       
  1762                             MsgKey.ER_ELEM_UNBOUND_PREFIX_IN_ENTREF,
       
  1763                             new Object[] {
       
  1764                                 node.getNodeName(),
       
  1765                                 child.getNodeName(),
       
  1766                                 prefix });
       
  1767 
       
  1768                     if (fErrorHandler != null) {
       
  1769                         fErrorHandler.handleError(
       
  1770                             new DOMErrorImpl(
       
  1771                                 DOMError.SEVERITY_FATAL_ERROR,
       
  1772                                 msg,
       
  1773                                 MsgKey.ER_ELEM_UNBOUND_PREFIX_IN_ENTREF,
       
  1774                                 null,
       
  1775                                 null,
       
  1776                                 null));
       
  1777                     }
       
  1778                 }
       
  1779 
       
  1780                 NamedNodeMap attrs = child.getAttributes();
       
  1781 
       
  1782                 for (int i = 0; i < attrs.getLength(); i++) {
       
  1783                     String attrPrefix = attrs.item(i).getPrefix();
       
  1784                     if (attrPrefix != null
       
  1785                                 && fNSBinder.getURI(attrPrefix) == null) {
       
  1786                         String msg =
       
  1787                             Utils.messages.createMessage(
       
  1788                                 MsgKey.ER_ATTR_UNBOUND_PREFIX_IN_ENTREF,
       
  1789                                 new Object[] {
       
  1790                                     node.getNodeName(),
       
  1791                                     child.getNodeName(),
       
  1792                                     attrs.item(i)});
       
  1793 
       
  1794                         if (fErrorHandler != null) {
       
  1795                             fErrorHandler.handleError(
       
  1796                                 new DOMErrorImpl(
       
  1797                                     DOMError.SEVERITY_FATAL_ERROR,
       
  1798                                     msg,
       
  1799                                     MsgKey.ER_ATTR_UNBOUND_PREFIX_IN_ENTREF,
       
  1800                                     null,
       
  1801                                     null,
       
  1802                                     null));
       
  1803                         }
       
  1804                     }
       
  1805                 }
       
  1806             }
       
  1807 
       
  1808             if (child.hasChildNodes()) {
       
  1809                 checkUnboundPrefixInEntRef(child);
       
  1810             }
       
  1811         }
       
  1812     }
       
  1813 
       
  1814     // ***********************************************************************
       
  1815     // Namespace normalization
       
  1816     // ***********************************************************************
       
  1817     /**
       
  1818      * Records local namespace declarations, to be used for normalization later
       
  1819      *
       
  1820      * @param Node, The element node, whose namespace declarations are to be recorded
       
  1821      */
       
  1822     protected void recordLocalNSDecl(Node node) {
       
  1823         NamedNodeMap atts = ((Element) node).getAttributes();
       
  1824         int length = atts.getLength();
       
  1825 
       
  1826         for (int i = 0; i < length; i++) {
       
  1827             Node attr = atts.item(i);
       
  1828 
       
  1829             String localName = attr.getLocalName();
       
  1830             String attrPrefix = attr.getPrefix();
       
  1831             String attrValue = attr.getNodeValue();
       
  1832             String attrNS = attr.getNamespaceURI();
       
  1833 
       
  1834             localName =
       
  1835                 localName == null
       
  1836                     || XMLNS_PREFIX.equals(localName) ? "" : localName;
       
  1837             attrPrefix = attrPrefix == null ? "" : attrPrefix;
       
  1838             attrValue = attrValue == null ? "" : attrValue;
       
  1839             attrNS = attrNS == null ? "" : attrNS;
       
  1840 
       
  1841             // check if attribute is a namespace decl
       
  1842             if (XMLNS_URI.equals(attrNS)) {
       
  1843 
       
  1844                 // No prefix may be bound to http://www.w3.org/2000/xmlns/.
       
  1845                 if (XMLNS_URI.equals(attrValue)) {
       
  1846                     String msg =
       
  1847                         Utils.messages.createMessage(
       
  1848                             MsgKey.ER_NS_PREFIX_CANNOT_BE_BOUND,
       
  1849                             new Object[] { attrPrefix, XMLNS_URI });
       
  1850 
       
  1851                     if (fErrorHandler != null) {
       
  1852                         fErrorHandler.handleError(
       
  1853                             new DOMErrorImpl(
       
  1854                                 DOMError.SEVERITY_ERROR,
       
  1855                                 msg,
       
  1856                                 MsgKey.ER_NS_PREFIX_CANNOT_BE_BOUND,
       
  1857                                 null,
       
  1858                                 null,
       
  1859                                 null));
       
  1860                     }
       
  1861                 } else {
       
  1862                     // store the namespace-declaration
       
  1863                         if (XMLNS_PREFIX.equals(attrPrefix) ) {
       
  1864                         // record valid decl
       
  1865                         if (attrValue.length() != 0) {
       
  1866                             fNSBinder.declarePrefix(localName, attrValue);
       
  1867                         } else {
       
  1868                             // Error; xmlns:prefix=""
       
  1869                         }
       
  1870                     } else { // xmlns
       
  1871                         // empty prefix is always bound ("" or some string)
       
  1872                         fNSBinder.declarePrefix("", attrValue);
       
  1873                     }
       
  1874                 }
       
  1875 
       
  1876             }
       
  1877         }
       
  1878     }
       
  1879 
       
  1880     /**
       
  1881      * Fixes an element's namespace
       
  1882      *
       
  1883      * @param Node, The element node, whose namespace is to be fixed
       
  1884      */
       
  1885     protected void fixupElementNS(Node node) throws SAXException {
       
  1886         String namespaceURI = ((Element) node).getNamespaceURI();
       
  1887         String prefix = ((Element) node).getPrefix();
       
  1888         String localName = ((Element) node).getLocalName();
       
  1889 
       
  1890         if (namespaceURI != null) {
       
  1891             //if ( Element's prefix/namespace pair (or default namespace,
       
  1892             // if no prefix) are within the scope of a binding )
       
  1893             prefix = prefix == null ? "" : prefix;
       
  1894             String inScopeNamespaceURI = fNSBinder.getURI(prefix);
       
  1895 
       
  1896             if ((inScopeNamespaceURI != null
       
  1897                 && inScopeNamespaceURI.equals(namespaceURI))) {
       
  1898                 // do nothing, declaration in scope is inherited
       
  1899 
       
  1900             } else {
       
  1901                 // Create a local namespace declaration attr for this namespace,
       
  1902                 // with Element's current prefix (or a default namespace, if
       
  1903                 // no prefix). If there's a conflicting local declaration
       
  1904                 // already present, change its value to use this namespace.
       
  1905 
       
  1906                 // Add the xmlns declaration attribute
       
  1907                 //fNSBinder.pushNamespace(prefix, namespaceURI, fElementDepth);
       
  1908                 if ((fFeatures & NAMESPACEDECLS) != 0) {
       
  1909                     if ("".equals(prefix) || "".equals(namespaceURI)) {
       
  1910                         ((Element)node).setAttributeNS(XMLNS_URI, XMLNS_PREFIX, namespaceURI);
       
  1911                     } else {
       
  1912                         ((Element)node).setAttributeNS(XMLNS_URI, XMLNS_PREFIX + ":" + prefix, namespaceURI);
       
  1913                     }
       
  1914                 }
       
  1915                 fLocalNSBinder.declarePrefix(prefix, namespaceURI);
       
  1916                 fNSBinder.declarePrefix(prefix, namespaceURI);
       
  1917 
       
  1918             }
       
  1919         } else {
       
  1920             // Element has no namespace
       
  1921             // DOM Level 1
       
  1922             if (localName == null || "".equals(localName)) {
       
  1923                 //  DOM Level 1 node!
       
  1924                 String msg =
       
  1925                     Utils.messages.createMessage(
       
  1926                         MsgKey.ER_NULL_LOCAL_ELEMENT_NAME,
       
  1927                         new Object[] { node.getNodeName()});
       
  1928 
       
  1929                 if (fErrorHandler != null) {
       
  1930                     fErrorHandler.handleError(
       
  1931                         new DOMErrorImpl(
       
  1932                             DOMError.SEVERITY_ERROR,
       
  1933                             msg,
       
  1934                             MsgKey.ER_NULL_LOCAL_ELEMENT_NAME,
       
  1935                             null,
       
  1936                             null,
       
  1937                             null));
       
  1938                 }
       
  1939             } else {
       
  1940                 namespaceURI = fNSBinder.getURI("");
       
  1941                 if (namespaceURI !=null && namespaceURI.length() > 0) {
       
  1942                     ((Element)node).setAttributeNS(XMLNS_URI, XMLNS_PREFIX, "");
       
  1943                         fLocalNSBinder.declarePrefix("", "");
       
  1944                     fNSBinder.declarePrefix("", "");
       
  1945                 }
       
  1946             }
       
  1947         }
       
  1948     }
       
  1949     /**
       
  1950      * This table is a quick lookup of a property key (String) to the integer that
       
  1951      * is the bit to flip in the fFeatures field, so the integers should have
       
  1952      * values 1,2,4,8,16...
       
  1953      *
       
  1954      */
       
  1955     private static final Hashtable s_propKeys = new Hashtable();
       
  1956     static {
       
  1957 
       
  1958         // Initialize the mappings of property keys to bit values (Integer objects)
       
  1959         // or mappings to a String object "", which indicates we are interested
       
  1960         // in the property, but it does not have a simple bit value to flip
       
  1961 
       
  1962         // cdata-sections
       
  1963         int i = CDATA;
       
  1964         Integer val = new Integer(i);
       
  1965         s_propKeys.put(
       
  1966             DOMConstants.S_DOM3_PROPERTIES_NS + DOMConstants.DOM_CDATA_SECTIONS,
       
  1967             val);
       
  1968 
       
  1969         // comments
       
  1970         int i1 = COMMENTS;
       
  1971         val = new Integer(i1);
       
  1972         s_propKeys.put(
       
  1973             DOMConstants.S_DOM3_PROPERTIES_NS + DOMConstants.DOM_COMMENTS,
       
  1974             val);
       
  1975 
       
  1976         // element-content-whitespace
       
  1977         int i2 = ELEM_CONTENT_WHITESPACE;
       
  1978         val = new Integer(i2);
       
  1979         s_propKeys.put(
       
  1980             DOMConstants.S_DOM3_PROPERTIES_NS
       
  1981                 + DOMConstants.DOM_ELEMENT_CONTENT_WHITESPACE,
       
  1982             val);
       
  1983         int i3 = ENTITIES;
       
  1984 
       
  1985         // entities
       
  1986         val = new Integer(i3);
       
  1987         s_propKeys.put(
       
  1988             DOMConstants.S_DOM3_PROPERTIES_NS + DOMConstants.DOM_ENTITIES,
       
  1989             val);
       
  1990 
       
  1991         // namespaces
       
  1992         int i4 = NAMESPACES;
       
  1993         val = new Integer(i4);
       
  1994         s_propKeys.put(
       
  1995             DOMConstants.S_DOM3_PROPERTIES_NS + DOMConstants.DOM_NAMESPACES,
       
  1996             val);
       
  1997 
       
  1998         // namespace-declarations
       
  1999         int i5 = NAMESPACEDECLS;
       
  2000         val = new Integer(i5);
       
  2001         s_propKeys.put(
       
  2002             DOMConstants.S_DOM3_PROPERTIES_NS
       
  2003                 + DOMConstants.DOM_NAMESPACE_DECLARATIONS,
       
  2004             val);
       
  2005 
       
  2006         // split-cdata-sections
       
  2007         int i6 = SPLITCDATA;
       
  2008         val = new Integer(i6);
       
  2009         s_propKeys.put(
       
  2010             DOMConstants.S_DOM3_PROPERTIES_NS + DOMConstants.DOM_SPLIT_CDATA,
       
  2011             val);
       
  2012 
       
  2013         // discard-default-content
       
  2014         int i7 = WELLFORMED;
       
  2015         val = new Integer(i7);
       
  2016         s_propKeys.put(
       
  2017             DOMConstants.S_DOM3_PROPERTIES_NS + DOMConstants.DOM_WELLFORMED,
       
  2018             val);
       
  2019 
       
  2020         // discard-default-content
       
  2021         int i8 = DISCARDDEFAULT;
       
  2022         val = new Integer(i8);
       
  2023         s_propKeys.put(
       
  2024             DOMConstants.S_DOM3_PROPERTIES_NS
       
  2025                 + DOMConstants.DOM_DISCARD_DEFAULT_CONTENT,
       
  2026             val);
       
  2027 
       
  2028         // We are interested in these properties, but they don't have a simple
       
  2029         // bit value to deal with.
       
  2030         s_propKeys.put(
       
  2031             DOMConstants.S_DOM3_PROPERTIES_NS
       
  2032                 + DOMConstants.DOM_FORMAT_PRETTY_PRINT,
       
  2033             "");
       
  2034         s_propKeys.put(DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL, "");
       
  2035         s_propKeys.put(
       
  2036             DOMConstants.S_XERCES_PROPERTIES_NS + DOMConstants.S_XML_VERSION,
       
  2037             "");
       
  2038         s_propKeys.put(DOMConstants.S_XSL_OUTPUT_ENCODING, "");
       
  2039         s_propKeys.put(OutputPropertiesFactory.S_KEY_ENTITIES, "");
       
  2040     }
       
  2041 
       
  2042     /**
       
  2043      * Initializes fFeatures based on the DOMConfiguration Parameters set.
       
  2044      *
       
  2045      * @param properties DOMConfiguraiton properties that were set and which are
       
  2046      * to be used while serializing the DOM.
       
  2047      */
       
  2048     protected void initProperties(Properties properties) {
       
  2049 
       
  2050         for (Enumeration keys = properties.keys(); keys.hasMoreElements();) {
       
  2051 
       
  2052             final String key = (String) keys.nextElement();
       
  2053 
       
  2054             // caonical-form
       
  2055             // Other features will be enabled or disabled when this is set to true or false.
       
  2056 
       
  2057             // error-handler; set via the constructor
       
  2058 
       
  2059             // infoset
       
  2060             // Other features will be enabled or disabled when this is set to true
       
  2061 
       
  2062             // A quick lookup for the given set of properties (cdata-sections ...)
       
  2063             final Object iobj = s_propKeys.get(key);
       
  2064             if (iobj != null) {
       
  2065                 if (iobj instanceof Integer) {
       
  2066                     // Dealing with a property that has a simple bit value that
       
  2067                     // we need to set
       
  2068 
       
  2069                     // cdata-sections
       
  2070                     // comments
       
  2071                     // element-content-whitespace
       
  2072                     // entities
       
  2073                     // namespaces
       
  2074                     // namespace-declarations
       
  2075                     // split-cdata-sections
       
  2076                     // well-formed
       
  2077                     // discard-default-content
       
  2078                     final int BITFLAG = ((Integer) iobj).intValue();
       
  2079                     if ((properties.getProperty(key).endsWith("yes"))) {
       
  2080                         fFeatures = fFeatures | BITFLAG;
       
  2081                     } else {
       
  2082                         fFeatures = fFeatures & ~BITFLAG;
       
  2083                     }
       
  2084                 } else {
       
  2085                     // We are interested in the property, but it is not
       
  2086                     // a simple bit that we need to set.
       
  2087 
       
  2088                     if ((DOMConstants.S_DOM3_PROPERTIES_NS
       
  2089                         + DOMConstants.DOM_FORMAT_PRETTY_PRINT)
       
  2090                         .equals(key)) {
       
  2091                         // format-pretty-print; set internally on the serializers via xsl:output properties in LSSerializer
       
  2092                         if ((properties.getProperty(key).endsWith("yes"))) {
       
  2093                             fSerializer.setIndent(true);
       
  2094                             fSerializer.setIndentAmount(4);
       
  2095                         } else {
       
  2096                             fSerializer.setIndent(false);
       
  2097                         }
       
  2098                     } else if (
       
  2099                         (DOMConstants.S_XSL_OUTPUT_OMIT_XML_DECL).equals(
       
  2100                             key)) {
       
  2101                         // omit-xml-declaration; set internally on the serializers via xsl:output properties in LSSerializer
       
  2102                         if ((properties.getProperty(key).endsWith("yes"))) {
       
  2103                             fSerializer.setOmitXMLDeclaration(true);
       
  2104                         } else {
       
  2105                             fSerializer.setOmitXMLDeclaration(false);
       
  2106                         }
       
  2107                     } else if (
       
  2108                         (
       
  2109                             DOMConstants.S_XERCES_PROPERTIES_NS
       
  2110                                 + DOMConstants.S_XML_VERSION).equals(
       
  2111                             key)) {
       
  2112                         // Retreive the value of the XML Version attribute via the xml-version
       
  2113                         String version = properties.getProperty(key);
       
  2114                         if ("1.1".equals(version)) {
       
  2115                             fIsXMLVersion11 = true;
       
  2116                             fSerializer.setVersion(version);
       
  2117                         } else {
       
  2118                             fSerializer.setVersion("1.0");
       
  2119                         }
       
  2120                     } else if (
       
  2121                         (DOMConstants.S_XSL_OUTPUT_ENCODING).equals(key)) {
       
  2122                         // Retreive the value of the XML Encoding attribute
       
  2123                         String encoding = properties.getProperty(key);
       
  2124                         if (encoding != null) {
       
  2125                             fSerializer.setEncoding(encoding);
       
  2126                         }
       
  2127                     } else if ((OutputPropertiesFactory.S_KEY_ENTITIES).equals(key)) {
       
  2128                         // Retreive the value of the XML Encoding attribute
       
  2129                         String entities = properties.getProperty(key);
       
  2130                         if (DOMConstants.S_XSL_VALUE_ENTITIES.equals(entities)) {
       
  2131                             fSerializer.setDTDEntityExpansion(false);
       
  2132                         }
       
  2133                     } else {
       
  2134                         // We shouldn't get here, ever, now what?
       
  2135                     }
       
  2136                 }
       
  2137             }
       
  2138         }
       
  2139         // Set the newLine character to use
       
  2140         if (fNewLine != null) {
       
  2141             fSerializer.setOutputProperty(OutputPropertiesFactory.S_KEY_LINE_SEPARATOR, fNewLine);
       
  2142         }
       
  2143     }
       
  2144 
       
  2145 } //TreeWalker