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