• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
DOM3TreeWalker( SerializationHandler serialHandler, DOMErrorHandler errHandler, LSSerializerFilter filter, String newLine)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      */
traverse(Node pos)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      */
traverse(Node pos, Node top)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      */
dispatachChars(Node node)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      */
startNode(Node node)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      */
endNode(Node node)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      */
applyFilter(Node node, int nodeType)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      */
serializeDocType(DocumentType node, boolean bStart)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      */
serializeComment(Comment node)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      */
serializeElement(Element node, boolean bStart)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      */
serializeAttList(Element node)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@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      */
serializeText(Text node)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      */
serializeEntityReference( EntityReference node, boolean bStart)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      */
isXMLName(String s, boolean xml11Version)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      */
isValidQName( String prefix, String local, boolean xml11Version)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      */
isWFXMLChar(String chardata, Character refInvalidChar)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      */
isWFXMLChar(String chardata)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      */
isCommentWellFormed(String data)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      */
isElementWellFormed(Node node)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      */
isAttributeWellFormed(Node node)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      */
isPIWellFormed(ProcessingInstruction node)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      */
isCDATASectionWellFormed(CDATASection node)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      */
isTextWellFormed(Text node)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      */
isEntityReferneceWellFormed(EntityReference node)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      */
checkUnboundPrefixInEntRef(Node node)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      */
recordLocalNSDecl(Node node)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      */
fixupElementNS(Node node)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      */
initProperties(Properties properties)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