KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > serialize > XMLSerializer


1 /*
2  * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17
18
19 // Sep 14, 2000:
20
// Fixed problem with namespace handling. Contributed by
21
// David Blondeau <blondeau@intalio.com>
22
// Sep 14, 2000:
23
// Fixed serializer to report IO exception directly, instead at
24
// the end of document processing.
25
// Reported by Patrick Higgins <phiggins@transzap.com>
26
// Aug 21, 2000:
27
// Fixed bug in startDocument not calling prepare.
28
// Reported by Mikael Staldal <d96-mst-ingen-reklam@d.kth.se>
29
// Aug 21, 2000:
30
// Added ability to omit DOCTYPE declaration.
31

32
33 package org.apache.xml.serialize;
34
35
36 import java.io.IOException JavaDoc;
37 import java.io.OutputStream JavaDoc;
38 import java.io.Writer JavaDoc;
39 import java.util.Enumeration JavaDoc;
40
41 import org.apache.xerces.dom.DOMMessageFormatter;
42 import org.apache.xerces.util.NamespaceSupport;
43 import org.apache.xerces.util.SymbolTable;
44 import org.apache.xerces.util.XMLChar;
45 import org.apache.xerces.util.XMLSymbols;
46 import org.apache.xerces.xni.NamespaceContext;
47 import org.w3c.dom.Attr JavaDoc;
48 import org.w3c.dom.DOMError JavaDoc;
49 import org.w3c.dom.Element JavaDoc;
50 import org.w3c.dom.NamedNodeMap JavaDoc;
51 import org.w3c.dom.Node JavaDoc;
52 import org.w3c.dom.traversal.NodeFilter;
53 import org.xml.sax.AttributeList JavaDoc;
54 import org.xml.sax.Attributes JavaDoc;
55 import org.xml.sax.SAXException JavaDoc;
56 import org.xml.sax.helpers.AttributesImpl JavaDoc;
57
58 /**
59  * Implements an XML serializer supporting both DOM and SAX pretty
60  * serializing. For usage instructions see {@link Serializer}.
61  * <p>
62  * If an output stream is used, the encoding is taken from the
63  * output format (defaults to <tt>UTF-8</tt>). If a writer is
64  * used, make sure the writer uses the same encoding (if applies)
65  * as specified in the output format.
66  * <p>
67  * The serializer supports both DOM and SAX. SAX serializing is done by firing
68  * SAX events and using the serializer as a document handler. DOM serializing is done
69  * by calling {@link #serialize(Document)} or by using DOM Level 3
70  * {@link org.w3c.dom.ls.DOMSerializer} and
71  * serializing with {@link org.w3c.dom.ls.DOMSerializer#write},
72  * {@link org.w3c.dom.ls.DOMSerializer#writeToString}.
73  * <p>
74  * If an I/O exception occurs while serializing, the serializer
75  * will not throw an exception directly, but only throw it
76  * at the end of serializing (either DOM or SAX's {@link
77  * org.xml.sax.DocumentHandler#endDocument}.
78  * <p>
79  * For elements that are not specified as whitespace preserving,
80  * the serializer will potentially break long text lines at space
81  * boundaries, indent lines, and serialize elements on separate
82  * lines. Line terminators will be regarded as spaces, and
83  * spaces at beginning of line will be stripped.
84  * @author <a HREF="mailto:arkin@intalio.com">Assaf Arkin</a>
85  * @author <a HREF="mailto:rahul.srivastava@sun.com">Rahul Srivastava</a>
86  * @author Elena Litani IBM
87  * @version $Revision: 1.66 $ $Date: 2005/05/03 11:12:21 $
88  * @see Serializer
89  */

90 public class XMLSerializer
91 extends BaseMarkupSerializer {
92
93     //
94
// constants
95
//
96

97     protected static final boolean DEBUG = false;
98
99     //
100
// data
101
//
102

103     //
104
// DOM Level 3 implementation: variables intialized in DOMSerializerImpl
105
//
106

107     /** stores namespaces in scope */
108     protected NamespaceSupport fNSBinder;
109
110     /** stores all namespace bindings on the current element */
111     protected NamespaceSupport fLocalNSBinder;
112
113     /** symbol table for serialization */
114     protected SymbolTable fSymbolTable;
115
116     protected final static String JavaDoc PREFIX = "NS";
117
118     /**
119      * Controls whether namespace fixup should be performed during
120      * the serialization.
121      * NOTE: if this field is set to true the following
122      * fields need to be initialized: fNSBinder, fLocalNSBinder, fSymbolTable,
123      * XMLSymbols.EMPTY_STRING, fXmlSymbol, fXmlnsSymbol
124      */

125     protected boolean fNamespaces = false;
126
127     /**
128      * Controls whether namespace prefixes will be printed out during serialization
129      */

130     protected boolean fNamespacePrefixes = true;
131     
132
133     private boolean fPreserveSpace;
134
135
136     /**
137      * Constructs a new serializer. The serializer cannot be used without
138      * calling {@link #setOutputCharStream} or {@link #setOutputByteStream}
139      * first.
140      */

141     public XMLSerializer() {
142         super( new OutputFormat( Method.XML, null, false ) );
143     }
144
145
146     /**
147      * Constructs a new serializer. The serializer cannot be used without
148      * calling {@link #setOutputCharStream} or {@link #setOutputByteStream}
149      * first.
150      */

151     public XMLSerializer( OutputFormat format ) {
152         super( format != null ? format : new OutputFormat( Method.XML, null, false ) );
153         _format.setMethod( Method.XML );
154     }
155
156
157     /**
158      * Constructs a new serializer that writes to the specified writer
159      * using the specified output format. If <tt>format</tt> is null,
160      * will use a default output format.
161      *
162      * @param writer The writer to use
163      * @param format The output format to use, null for the default
164      */

165     public XMLSerializer( Writer JavaDoc writer, OutputFormat format ) {
166         super( format != null ? format : new OutputFormat( Method.XML, null, false ) );
167         _format.setMethod( Method.XML );
168         setOutputCharStream( writer );
169     }
170
171
172     /**
173      * Constructs a new serializer that writes to the specified output
174      * stream using the specified output format. If <tt>format</tt>
175      * is null, will use a default output format.
176      *
177      * @param output The output stream to use
178      * @param format The output format to use, null for the default
179      */

180     public XMLSerializer( OutputStream JavaDoc output, OutputFormat format ) {
181         super( format != null ? format : new OutputFormat( Method.XML, null, false ) );
182         _format.setMethod( Method.XML );
183         setOutputByteStream( output );
184     }
185
186
187     public void setOutputFormat( OutputFormat format ) {
188         super.setOutputFormat( format != null ? format : new OutputFormat( Method.XML, null, false ) );
189     }
190
191
192     /**
193      * This methods turns on namespace fixup algorithm during
194      * DOM serialization.
195      * @see org.w3c.dom.ls.DOMSerializer
196      *
197      * @param namespaces
198      */

199     public void setNamespaces (boolean namespaces){
200         fNamespaces = namespaces;
201         if (fNSBinder == null) {
202             fNSBinder = new NamespaceSupport();
203             fLocalNSBinder = new NamespaceSupport();
204             fSymbolTable = new SymbolTable();
205         }
206     }
207
208     //-----------------------------------------//
209
// SAX content handler serializing methods //
210
//-----------------------------------------//
211

212
213     public void startElement( String JavaDoc namespaceURI, String JavaDoc localName,
214                               String JavaDoc rawName, Attributes JavaDoc attrs )
215     throws SAXException JavaDoc
216     {
217         int i;
218         boolean preserveSpace;
219         ElementState state;
220         String JavaDoc name;
221         String JavaDoc value;
222         boolean addNSAttr = false;
223
224         if (DEBUG) {
225             System.out.println("==>startElement("+namespaceURI+","+localName+
226                                ","+rawName+")");
227         }
228
229         try {
230             if (_printer == null) {
231                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null);
232                 throw new IllegalStateException JavaDoc(msg);
233             }
234
235             state = getElementState();
236             if (isDocumentState()) {
237                 // If this is the root element handle it differently.
238
// If the first root element in the document, serialize
239
// the document's DOCTYPE. Space preserving defaults
240
// to that of the output format.
241
if (! _started)
242                     startDocument( ( localName == null || localName.length() == 0 ) ? rawName : localName );
243             } else {
244                 // For any other element, if first in parent, then
245
// close parent's opening tag and use the parnet's
246
// space preserving.
247
if (state.empty)
248                     _printer.printText( '>' );
249                 // Must leave CData section first
250
if (state.inCData) {
251                     _printer.printText( "]]>" );
252                     state.inCData = false;
253                 }
254                 // Indent this element on a new line if the first
255
// content of the parent element or immediately
256
// following an element or a comment
257
if (_indenting && ! state.preserveSpace &&
258                     ( state.empty || state.afterElement || state.afterComment))
259                     _printer.breakLine();
260             }
261             preserveSpace = state.preserveSpace;
262
263             //We remove the namespaces from the attributes list so that they will
264
//be in _prefixes
265
attrs = extractNamespaces(attrs);
266
267             // Do not change the current element state yet.
268
// This only happens in endElement().
269
if (rawName == null || rawName.length() == 0) {
270                 if (localName == null) {
271                     String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "NoName", null);
272                     throw new SAXException JavaDoc(msg);
273                 }
274                 if (namespaceURI != null && ! namespaceURI.equals( "" )) {
275                     String JavaDoc prefix;
276                     prefix = getPrefix( namespaceURI );
277                     if (prefix != null && prefix.length() > 0)
278                         rawName = prefix + ":" + localName;
279                     else
280                         rawName = localName;
281                 } else
282                     rawName = localName;
283                 addNSAttr = true;
284             }
285
286             _printer.printText( '<' );
287             _printer.printText( rawName );
288             _printer.indent();
289
290             // For each attribute print it's name and value as one part,
291
// separated with a space so the element can be broken on
292
// multiple lines.
293
if (attrs != null) {
294                 for (i = 0 ; i < attrs.getLength() ; ++i) {
295                     _printer.printSpace();
296
297                     name = attrs.getQName( i );
298                     if (name != null && name.length() == 0) {
299                         String JavaDoc prefix;
300                         String JavaDoc attrURI;
301
302                         name = attrs.getLocalName( i );
303                         attrURI = attrs.getURI( i );
304                         if (( attrURI != null && attrURI.length() != 0 ) &&
305                             ( namespaceURI == null || namespaceURI.length() == 0 ||
306                               ! attrURI.equals( namespaceURI ) )) {
307                             prefix = getPrefix( attrURI );
308                             if (prefix != null && prefix.length() > 0)
309                                 name = prefix + ":" + name;
310                         }
311                     }
312
313                     value = attrs.getValue( i );
314                     if (value == null)
315                         value = "";
316                     _printer.printText( name );
317                     _printer.printText( "=\"" );
318                     printEscaped( value );
319                     _printer.printText( '"' );
320
321                     // If the attribute xml:space exists, determine whether
322
// to preserve spaces in this and child nodes based on
323
// its value.
324
if (name.equals( "xml:space" )) {
325                         if (value.equals( "preserve" ))
326                             preserveSpace = true;
327                         else
328                             preserveSpace = _format.getPreserveSpace();
329                     }
330                 }
331             }
332
333             if (_prefixes != null) {
334                 Enumeration JavaDoc keys;
335
336                 keys = _prefixes.keys();
337                 while (keys.hasMoreElements()) {
338                     _printer.printSpace();
339                     value = (String JavaDoc) keys.nextElement();
340                     name = (String JavaDoc) _prefixes.get( value );
341                     if (name.length() == 0) {
342                         _printer.printText( "xmlns=\"" );
343                         printEscaped( value );
344                         _printer.printText( '"' );
345                     } else {
346                         _printer.printText( "xmlns:" );
347                         _printer.printText( name );
348                         _printer.printText( "=\"" );
349                         printEscaped( value );
350                         _printer.printText( '"' );
351                     }
352                 }
353             }
354
355             // Now it's time to enter a new element state
356
// with the tag name and space preserving.
357
// We still do not change the curent element state.
358
state = enterElementState( namespaceURI, localName, rawName, preserveSpace );
359             name = ( localName == null || localName.length() == 0 ) ? rawName : namespaceURI + "^" + localName;
360             state.doCData = _format.isCDataElement( name );
361             state.unescaped = _format.isNonEscapingElement( name );
362         } catch (IOException JavaDoc except) {
363             throw new SAXException JavaDoc( except );
364         }
365     }
366
367
368     public void endElement( String JavaDoc namespaceURI, String JavaDoc localName,
369                             String JavaDoc rawName )
370     throws SAXException JavaDoc
371     {
372         try {
373             endElementIO( namespaceURI, localName, rawName );
374         } catch (IOException JavaDoc except) {
375             throw new SAXException JavaDoc( except );
376         }
377     }
378
379
380     public void endElementIO( String JavaDoc namespaceURI, String JavaDoc localName,
381                               String JavaDoc rawName )
382     throws IOException JavaDoc
383     {
384         ElementState state;
385         if (DEBUG) {
386             System.out.println("==>endElement: " +rawName);
387         }
388         // Works much like content() with additions for closing
389
// an element. Note the different checks for the closed
390
// element's state and the parent element's state.
391
_printer.unindent();
392         state = getElementState();
393         if (state.empty) {
394             _printer.printText( "/>" );
395         } else {
396             // Must leave CData section first
397
if (state.inCData)
398                 _printer.printText( "]]>" );
399             // This element is not empty and that last content was
400
// another element, so print a line break before that
401
// last element and this element's closing tag.
402
if (_indenting && ! state.preserveSpace && (state.afterElement || state.afterComment))
403                 _printer.breakLine();
404             _printer.printText( "</" );
405             _printer.printText( state.rawName );
406             _printer.printText( '>' );
407         }
408         // Leave the element state and update that of the parent
409
// (if we're not root) to not empty and after element.
410
state = leaveElementState();
411         state.afterElement = true;
412         state.afterComment = false;
413         state.empty = false;
414         if (isDocumentState())
415             _printer.flush();
416     }
417
418
419     //------------------------------------------//
420
// SAX document handler serializing methods //
421
//------------------------------------------//
422

423
424     public void startElement( String JavaDoc tagName, AttributeList JavaDoc attrs )
425     throws SAXException JavaDoc
426     {
427         int i;
428         boolean preserveSpace;
429         ElementState state;
430         String JavaDoc name;
431         String JavaDoc value;
432
433
434         if (DEBUG) {
435             System.out.println("==>startElement("+tagName+")");
436         }
437
438         try {
439             if (_printer == null) {
440                 String JavaDoc msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.SERIALIZER_DOMAIN, "NoWriterSupplied", null);
441                 throw new IllegalStateException JavaDoc(msg);
442             }
443
444             state = getElementState();
445             if (isDocumentState()) {
446                 // If this is the root element handle it differently.
447
// If the first root element in the document, serialize
448
// the document's DOCTYPE. Space preserving defaults
449
// to that of the output format.
450
if (! _started)
451                     startDocument( tagName );
452             } else {
453                 // For any other element, if first in parent, then
454
// close parent's opening tag and use the parnet's
455
// space preserving.
456
if (state.empty)
457                     _printer.printText( '>' );
458                 // Must leave CData section first
459
if (state.inCData) {
460                     _printer.printText( "]]>" );
461                     state.inCData = false;
462                 }
463                 // Indent this element on a new line if the first
464
// content of the parent element or immediately
465
// following an element.
466
if (_indenting && ! state.preserveSpace &&
467                     ( state.empty || state.afterElement || state.afterComment))
468                     _printer.breakLine();
469             }
470             preserveSpace = state.preserveSpace;
471
472             // Do not change the current element state yet.
473
// This only happens in endElement().
474

475             _printer.printText( '<' );
476             _printer.printText( tagName );
477             _printer.indent();
478
479             // For each attribute print it's name and value as one part,
480
// separated with a space so the element can be broken on
481
// multiple lines.
482
if (attrs != null) {
483                 for (i = 0 ; i < attrs.getLength() ; ++i) {
484                     _printer.printSpace();
485                     name = attrs.getName( i );
486                     value = attrs.getValue( i );
487                     if (value != null) {
488                         _printer.printText( name );
489                         _printer.printText( "=\"" );
490                         printEscaped( value );
491                         _printer.printText( '"' );
492                     }
493
494                     // If the attribute xml:space exists, determine whether
495
// to preserve spaces in this and child nodes based on
496
// its value.
497
if (name.equals( "xml:space" )) {
498                         if (value.equals( "preserve" ))
499                             preserveSpace = true;
500                         else
501                             preserveSpace = _format.getPreserveSpace();
502                     }
503                 }
504             }
505             // Now it's time to enter a new element state
506
// with the tag name and space preserving.
507
// We still do not change the curent element state.
508
state = enterElementState( null, null, tagName, preserveSpace );
509             state.doCData = _format.isCDataElement( tagName );
510             state.unescaped = _format.isNonEscapingElement( tagName );
511         } catch (IOException JavaDoc except) {
512             throw new SAXException JavaDoc( except );
513         }
514
515     }
516
517
518     public void endElement( String JavaDoc tagName )
519     throws SAXException JavaDoc
520     {
521         endElement( null, null, tagName );
522     }
523
524
525
526     //------------------------------------------//
527
// Generic node serializing methods methods //
528
//------------------------------------------//
529

530
531     /**
532      * Called to serialize the document's DOCTYPE by the root element.
533      * The document type declaration must name the root element,
534      * but the root element is only known when that element is serialized,
535      * and not at the start of the document.
536      * <p>
537      * This method will check if it has not been called before ({@link #_started}),
538      * will serialize the document type declaration, and will serialize all
539      * pre-root comments and PIs that were accumulated in the document
540      * (see {@link #serializePreRoot}). Pre-root will be serialized even if
541      * this is not the first root element of the document.
542      */

543     protected void startDocument( String JavaDoc rootTagName )
544     throws IOException JavaDoc
545     {
546         int i;
547         String JavaDoc dtd;
548
549         dtd = _printer.leaveDTD();
550         if (! _started) {
551
552             if (! _format.getOmitXMLDeclaration()) {
553                 StringBuffer JavaDoc buffer;
554
555                 // Serialize the document declaration appreaing at the head
556
// of very XML document (unless asked not to).
557
buffer = new StringBuffer JavaDoc( "<?xml version=\"" );
558                 if (_format.getVersion() != null)
559                     buffer.append( _format.getVersion() );
560                 else
561                     buffer.append( "1.0" );
562                 buffer.append( '"' );
563                 String JavaDoc format_encoding = _format.getEncoding();
564                 if (format_encoding != null) {
565                     buffer.append( " encoding=\"" );
566                     buffer.append( format_encoding );
567                     buffer.append( '"' );
568                 }
569                 if (_format.getStandalone() && _docTypeSystemId == null &&
570                     _docTypePublicId == null)
571                     buffer.append( " standalone=\"yes\"" );
572                 buffer.append( "?>" );
573                 _printer.printText( buffer );
574                 _printer.breakLine();
575             }
576
577             if (! _format.getOmitDocumentType()) {
578                 if (_docTypeSystemId != null) {
579                     // System identifier must be specified to print DOCTYPE.
580
// If public identifier is specified print 'PUBLIC
581
// <public> <system>', if not, print 'SYSTEM <system>'.
582
_printer.printText( "<!DOCTYPE " );
583                     _printer.printText( rootTagName );
584                     if (_docTypePublicId != null) {
585                         _printer.printText( " PUBLIC " );
586                         printDoctypeURL( _docTypePublicId );
587                         if (_indenting) {
588                             _printer.breakLine();
589                             for (i = 0 ; i < 18 + rootTagName.length() ; ++i)
590                                 _printer.printText( " " );
591                         } else
592                             _printer.printText( " " );
593                         printDoctypeURL( _docTypeSystemId );
594                     } else {
595                         _printer.printText( " SYSTEM " );
596                         printDoctypeURL( _docTypeSystemId );
597                     }
598
599                     // If we accumulated any DTD contents while printing.
600
// this would be the place to print it.
601
if (dtd != null && dtd.length() > 0) {
602                         _printer.printText( " [" );
603                         printText( dtd, true, true );
604                         _printer.printText( ']' );
605                     }
606
607                     _printer.printText( ">" );
608                     _printer.breakLine();
609                 } else if (dtd != null && dtd.length() > 0) {
610                     _printer.printText( "<!DOCTYPE " );
611                     _printer.printText( rootTagName );
612                     _printer.printText( " [" );
613                     printText( dtd, true, true );
614                     _printer.printText( "]>" );
615                     _printer.breakLine();
616                 }
617             }
618         }
619         _started = true;
620         // Always serialize these, even if not te first root element.
621
serializePreRoot();
622     }
623
624
625     /**
626      * Called to serialize a DOM element. Equivalent to calling {@link
627      * #startElement}, {@link #endElement} and serializing everything
628      * inbetween, but better optimized.
629      */

630     protected void serializeElement( Element JavaDoc elem )
631     throws IOException JavaDoc
632     {
633         Attr JavaDoc attr;
634         NamedNodeMap JavaDoc attrMap;
635         int i;
636         Node JavaDoc child;
637         ElementState state;
638         String JavaDoc name;
639         String JavaDoc value;
640         String JavaDoc tagName;
641
642         String JavaDoc prefix, localUri;
643         String JavaDoc uri;
644         if (fNamespaces) {
645             // local binder stores namespace declaration
646
// that has been printed out during namespace fixup of
647
// the current element
648
fLocalNSBinder.reset();
649
650             // add new namespace context
651
fNSBinder.pushContext();
652         }
653
654         if (DEBUG) {
655             System.out.println("==>startElement: " +elem.getNodeName() +" ns="+elem.getNamespaceURI());
656         }
657         tagName = elem.getTagName();
658         state = getElementState();
659         if (isDocumentState()) {
660             // If this is the root element handle it differently.
661
// If the first root element in the document, serialize
662
// the document's DOCTYPE. Space preserving defaults
663
// to that of the output format.
664

665             if (! _started) {
666                 startDocument( tagName);
667             }
668         } else {
669             // For any other element, if first in parent, then
670
// close parent's opening tag and use the parent's
671
// space preserving.
672
if (state.empty)
673                 _printer.printText( '>' );
674             // Must leave CData section first
675
if (state.inCData) {
676                 _printer.printText( "]]>" );
677                 state.inCData = false;
678             }
679             // Indent this element on a new line if the first
680
// content of the parent element or immediately
681
// following an element.
682
if (_indenting && ! state.preserveSpace &&
683                 ( state.empty || state.afterElement || state.afterComment))
684                 _printer.breakLine();
685         }
686
687         // Do not change the current element state yet.
688
// This only happens in endElement().
689
fPreserveSpace = state.preserveSpace;
690
691
692         int length = 0;
693         attrMap = null;
694         // retrieve attributes
695
if (elem.hasAttributes()) {
696             attrMap = elem.getAttributes();
697             length = attrMap.getLength();
698         }
699
700         if (!fNamespaces) { // no namespace fixup should be performed
701

702             // serialize element name
703
_printer.printText( '<' );
704             _printer.printText( tagName );
705             _printer.indent();
706
707             // For each attribute print it's name and value as one part,
708
// separated with a space so the element can be broken on
709
// multiple lines.
710
for ( i = 0 ; i < length ; ++i ) {
711                 attr = (Attr JavaDoc) attrMap.item( i );
712                 name = attr.getName();
713                 value = attr.getValue();
714                 if ( value == null )
715                     value = "";
716                 printAttribute (name, value, attr.getSpecified(), attr);
717             }
718         } else { // do namespace fixup
719

720             // REVISIT: some optimization could probably be done to avoid traversing
721
// attributes twice.
722
//
723

724             // ---------------------------------------
725
// record all valid namespace declarations
726
// before attempting to fix element's namespace
727
// ---------------------------------------
728

729             for (i = 0;i < length;i++) {
730
731                 attr = (Attr JavaDoc) attrMap.item( i );
732                 uri = attr.getNamespaceURI();
733                 // check if attribute is a namespace decl
734
if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) {
735
736                     value = attr.getNodeValue();
737                     if (value == null) {
738                         value=XMLSymbols.EMPTY_STRING;
739                     }
740
741                     if (value.equals(NamespaceContext.XMLNS_URI)) {
742                         if (fDOMErrorHandler != null) {
743                             String JavaDoc msg = DOMMessageFormatter.formatMessage(
744                                 DOMMessageFormatter.XML_DOMAIN,"CantBindXMLNS",null );
745                             modifyDOMError(msg, DOMError.SEVERITY_ERROR, null, attr);
746                             boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
747                             if (!continueProcess) {
748                                 // stop the namespace fixup and validation
749
throw new RuntimeException JavaDoc(
750                                     DOMMessageFormatter.formatMessage(
751                                     DOMMessageFormatter.SERIALIZER_DOMAIN,
752                                     "SerializationStopped", null));
753                             }
754                         }
755                     } else {
756                         prefix = attr.getPrefix();
757                         prefix = (prefix == null ||
758                                   prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix);
759                         String JavaDoc localpart = fSymbolTable.addSymbol( attr.getLocalName());
760                         if (prefix == XMLSymbols.PREFIX_XMLNS) { //xmlns:prefix
761
value = fSymbolTable.addSymbol(value);
762                             // record valid decl
763
if (value.length() != 0) {
764                                 fNSBinder.declarePrefix(localpart, value);
765                             } else {
766                                 // REVISIT: issue error on invalid declarations
767
// xmlns:foo = ""
768
}
769                             continue;
770                         } else { // xmlns
771
// empty prefix is always bound ("" or some string)
772

773                             value = fSymbolTable.addSymbol(value);
774                             fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, value);
775                             continue;
776                         }
777                     } // end-else: valid declaration
778
} // end-if: namespace declaration
779
} // end-for
780

781             //-----------------------
782
// get element uri/prefix
783
//-----------------------
784
uri = elem.getNamespaceURI();
785             prefix = elem.getPrefix();
786
787             //----------------------
788
// output element name
789
//----------------------
790
// REVISIT: this could be removed if we always convert empty string to null
791
// for the namespaces.
792
if ((uri !=null && prefix !=null ) && uri.length() == 0 && prefix.length()!=0) {
793                 // uri is an empty string and element has some prefix
794
// the namespace alg later will fix up the namespace attributes
795
// remove element prefix
796
prefix = null;
797                 _printer.printText( '<' );
798                 _printer.printText( elem.getLocalName() );
799                 _printer.indent();
800             } else {
801                 _printer.printText( '<' );
802                 _printer.printText( tagName );
803                 _printer.indent();
804             }
805
806
807             // ---------------------------------------------------------
808
// Fix up namespaces for element: per DOM L3
809
// Need to consider the following cases:
810
//
811
// case 1: <foo:elem xmlns:ns1="myURI" xmlns="default"/>
812
// Assume "foo", "ns1" are declared on the parent. We should not miss
813
// redeclaration for both "ns1" and default namespace. To solve this
814
// we add a local binder that stores declaration only for current element.
815
// This way we avoid outputing duplicate declarations for the same element
816
// as well as we are not omitting redeclarations.
817
//
818
// case 2: <elem xmlns="" xmlns="default"/>
819
// We need to bind default namespace to empty string, to be able to
820
// omit duplicate declarations for the same element
821
//
822
// case 3: <xsl:stylesheet xmlns:xsl="http://xsl">
823
// We create another element body bound to the "http://xsl" namespace
824
// as well as namespace attribute rebounding xsl to another namespace.
825
// <xsl:body xmlns:xsl="http://another">
826
// Need to make sure that the new namespace decl value is changed to
827
// "http://xsl"
828
//
829
// ---------------------------------------------------------
830
// check if prefix/namespace is correct for current element
831
// ---------------------------------------------------------
832

833
834             if (uri != null) { // Element has a namespace
835
uri = fSymbolTable.addSymbol(uri);
836                 prefix = (prefix == null ||
837                           prefix.length() == 0) ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix);
838                 if (fNSBinder.getURI(prefix) == uri) {
839                     // The xmlns:prefix=namespace or xmlns="default" was declared at parent.
840
// The binder always stores mapping of empty prefix to "".
841
// (NOTE: local binder does not store this kind of binding!)
842
// Thus the case where element was declared with uri="" (with or without a prefix)
843
// will be covered here.
844

845                 } else {
846                     // the prefix is either undeclared
847
// or
848
// conflict: the prefix is bound to another URI
849
if (fNamespacePrefixes) {
850                         printNamespaceAttr(prefix, uri);
851                     }
852                     fLocalNSBinder.declarePrefix(prefix, uri);
853                     fNSBinder.declarePrefix(prefix, uri);
854                 }
855             } else { // Element has no namespace
856
if (elem.getLocalName() == null) {
857                     // DOM Level 1 node!
858
if (fDOMErrorHandler != null) {
859                         String JavaDoc msg = DOMMessageFormatter.formatMessage(
860                             DOMMessageFormatter.DOM_DOMAIN, "NullLocalElementName",
861                             new Object JavaDoc[]{elem.getNodeName()});
862                         modifyDOMError(msg,DOMError.SEVERITY_ERROR, null, elem);
863                         boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
864                         // REVISIT: should we terminate upon request?
865
if (!continueProcess) {
866                            throw new RuntimeException JavaDoc(
867                                DOMMessageFormatter.formatMessage(
868                                DOMMessageFormatter.SERIALIZER_DOMAIN,
869                                "SerializationStopped", null));
870                         }
871                     }
872                 } else { // uri=null and no colon (DOM L2 node)
873
uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING);
874
875                     if (uri !=null && uri.length() > 0) {
876                         // there is a default namespace decl that is bound to
877
// non-zero length uri, output xmlns=""
878
if (fNamespacePrefixes) {
879                             printNamespaceAttr(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING);
880                         }
881                         fLocalNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING);
882                         fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING);
883                     }
884                 }
885             }
886
887
888             // -----------------------------------------
889
// Fix up namespaces for attributes: per DOM L3
890
// check if prefix/namespace is correct the attributes
891
// -----------------------------------------
892

893             for (i = 0; i < length; i++) {
894
895                 attr = (Attr JavaDoc) attrMap.item( i );
896                 value = attr.getValue();
897                 name = attr.getNodeName();
898               
899                 uri = attr.getNamespaceURI();
900
901                 // Fix attribute that was declared with a prefix and namespace=""
902
if (uri !=null && uri.length() == 0) {
903                     uri=null;
904                     // we must remove prefix for this attribute
905
name=attr.getLocalName();
906                 }
907
908                 if (DEBUG) {
909                     System.out.println("==>process attribute: "+attr.getNodeName());
910                 }
911                 // make sure that value is never null.
912
if (value == null) {
913                     value=XMLSymbols.EMPTY_STRING;
914                 }
915
916                 if (uri != null) { // attribute has namespace !=null
917
prefix = attr.getPrefix();
918                     prefix = prefix == null ? XMLSymbols.EMPTY_STRING :fSymbolTable.addSymbol(prefix);
919                     String JavaDoc localpart = fSymbolTable.addSymbol( attr.getLocalName());
920
921
922
923                     // ---------------------------------------------------
924
// print namespace declarations namespace declarations
925
// ---------------------------------------------------
926
if (uri != null && uri.equals(NamespaceContext.XMLNS_URI)) {
927                         // check if we need to output this declaration
928
prefix = attr.getPrefix();
929                         prefix = (prefix == null ||
930                                   prefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix);
931                         localpart = fSymbolTable.addSymbol( attr.getLocalName());
932                         if (prefix == XMLSymbols.PREFIX_XMLNS) { //xmlns:prefix
933
localUri = fLocalNSBinder.getURI(localpart); // local prefix mapping
934
value = fSymbolTable.addSymbol(value);
935                             if (value.length() != 0 ) {
936                                 if (localUri == null) {
937                                     // declaration was not printed while fixing element namespace binding
938

939                                     // If the DOM Level 3 namespace-prefixes feature is set to false
940
// do not print xmlns attributes
941
if (fNamespacePrefixes) {
942                                         printNamespaceAttr(localpart, value);
943                                     }
944                                         
945                                     // case 4: <elem xmlns:xx="foo" xx:attr=""/>
946
// where attribute is bound to "bar".
947
// If the xmlns:xx is output here first, later we should not
948
// redeclare "xx" prefix. Instead we would pick up different prefix
949
// for the attribute.
950
// final: <elem xmlns:xx="foo" NS1:attr="" xmlns:NS1="bar"/>
951
fLocalNSBinder.declarePrefix(localpart, value);
952                                 }
953                             } else {
954                                 // REVISIT: issue error on invalid declarations
955
// xmlns:foo = ""
956
}
957                             continue;
958                         } else { // xmlns
959
// empty prefix is always bound ("" or some string)
960

961                             uri = fNSBinder.getURI(XMLSymbols.EMPTY_STRING);
962                             localUri=fLocalNSBinder.getURI(XMLSymbols.EMPTY_STRING);
963                             value = fSymbolTable.addSymbol(value);
964                             if (localUri == null ){
965                                 // declaration was not printed while fixing element namespace binding
966
if (fNamespacePrefixes) {
967                                     printNamespaceAttr(XMLSymbols.EMPTY_STRING, value);
968                                 }
969                                 // case 4 does not apply here since attributes can't use
970
// default namespace
971
}
972                             continue;
973                         }
974
975                     }
976                     uri = fSymbolTable.addSymbol(uri);
977
978                     // find if for this prefix a URI was already declared
979
String JavaDoc declaredURI = fNSBinder.getURI(prefix);
980
981                     if (prefix == XMLSymbols.EMPTY_STRING || declaredURI != uri) {
982                         // attribute has no prefix (default namespace decl does not apply to attributes)
983
// OR
984
// attribute prefix is not declared
985
// OR
986
// conflict: attr URI does not match the prefix in scope
987

988                         name = attr.getNodeName();
989                         // Find if any prefix for attributes namespace URI is available
990
// in the scope
991
String JavaDoc declaredPrefix = fNSBinder.getPrefix(uri);
992
993                         if (declaredPrefix !=null && declaredPrefix !=XMLSymbols.EMPTY_STRING) {
994                             // use the prefix that was found
995
prefix = declaredPrefix;
996                             name=prefix+":"+localpart;
997                         } else {
998                             if (DEBUG) {
999                                 System.out.println("==> cound not find prefix for the attribute: " +prefix);
1000                            }
1001
1002                            if (prefix != XMLSymbols.EMPTY_STRING && fLocalNSBinder.getURI(prefix) == null) {
1003                                // the current prefix is not null and it has no in scope declaration
1004

1005                                // use this prefix
1006
} else {
1007                                // find a prefix following the pattern "NS" +index (starting at 1)
1008
// make sure this prefix is not declared in the current scope.
1009
int counter = 1;
1010                                prefix = fSymbolTable.addSymbol(PREFIX + counter++);
1011                                while (fLocalNSBinder.getURI(prefix)!=null) {
1012                                    prefix = fSymbolTable.addSymbol(PREFIX +counter++);
1013                                }
1014                                name=prefix+":"+localpart;
1015                            }
1016                            // add declaration for the new prefix
1017
if (fNamespacePrefixes) {
1018                                printNamespaceAttr(prefix, uri);
1019                            }
1020                            value = fSymbolTable.addSymbol(value);
1021                            fLocalNSBinder.declarePrefix(prefix, value);
1022                            fNSBinder.declarePrefix(prefix, uri);
1023                        }
1024
1025                        // change prefix for this attribute
1026
}
1027
1028                    printAttribute (name, (value==null)?XMLSymbols.EMPTY_STRING:value, attr.getSpecified(), attr);
1029                } else { // attribute uri == null
1030
if (attr.getLocalName() == null) {
1031                        if (fDOMErrorHandler != null) {
1032                            String JavaDoc msg = DOMMessageFormatter.formatMessage(
1033                                DOMMessageFormatter.DOM_DOMAIN,
1034                                "NullLocalAttrName", new Object JavaDoc[]{attr.getNodeName()});
1035                            modifyDOMError(msg, DOMError.SEVERITY_ERROR, null, attr);
1036                            boolean continueProcess = fDOMErrorHandler.handleError(fDOMError);
1037                            if (!continueProcess) {
1038                                // stop the namespace fixup and validation
1039
throw new RuntimeException JavaDoc(
1040                                   DOMMessageFormatter.formatMessage(
1041                                   DOMMessageFormatter.SERIALIZER_DOMAIN,
1042                                   "SerializationStopped", null));
1043                            }
1044                        }
1045                        printAttribute (name, value, attr.getSpecified(), attr);
1046                    } else { // uri=null and no colon
1047

1048                        // no fix up is needed: default namespace decl does not
1049
// apply to attributes
1050
printAttribute (name, value, attr.getSpecified(), attr);
1051                    }
1052                }
1053            } // end loop for attributes
1054

1055        }// end namespace fixup algorithm
1056

1057
1058        // If element has children, then serialize them, otherwise
1059
// serialize en empty tag.
1060
if (elem.hasChildNodes()) {
1061            // Enter an element state, and serialize the children
1062
// one by one. Finally, end the element.
1063
state = enterElementState( null, null, tagName, fPreserveSpace );
1064            state.doCData = _format.isCDataElement( tagName );
1065            state.unescaped = _format.isNonEscapingElement( tagName );
1066            child = elem.getFirstChild();
1067            while (child != null) {
1068                serializeNode( child );
1069                child = child.getNextSibling();
1070            }
1071            if (fNamespaces) {
1072                fNSBinder.popContext();
1073            }
1074            endElementIO( null, null, tagName );
1075        } else {
1076            if (DEBUG) {
1077                System.out.println("==>endElement: " +elem.getNodeName());
1078            }
1079            if (fNamespaces) {
1080                fNSBinder.popContext();
1081            }
1082            _printer.unindent();
1083            _printer.printText( "/>" );
1084            // After element but parent element is no longer empty.
1085
state.afterElement = true;
1086            state.afterComment = false;
1087            state.empty = false;
1088            if (isDocumentState())
1089                _printer.flush();
1090        }
1091    }
1092
1093
1094
1095    /**
1096     * Serializes a namespace attribute with the given prefix and value for URI.
1097     * In case prefix is empty will serialize default namespace declaration.
1098     *
1099     * @param prefix
1100     * @param uri
1101     * @exception IOException
1102     */

1103
1104    private void printNamespaceAttr(String JavaDoc prefix, String JavaDoc uri) throws IOException JavaDoc{
1105        _printer.printSpace();
1106        if (prefix == XMLSymbols.EMPTY_STRING) {
1107            if (DEBUG) {
1108                System.out.println("=>add xmlns=\""+uri+"\" declaration");
1109            }
1110            _printer.printText( XMLSymbols.PREFIX_XMLNS );
1111        } else {
1112            if (DEBUG) {
1113                System.out.println("=>add xmlns:"+prefix+"=\""+uri+"\" declaration");
1114            }
1115            _printer.printText( "xmlns:"+prefix );
1116        }
1117        _printer.printText( "=\"" );
1118        printEscaped( uri );
1119        _printer.printText( '"' );
1120    }
1121
1122
1123
1124    /**
1125     * Prints attribute.
1126     * NOTE: xml:space attribute modifies output format
1127     *
1128     * @param name
1129     * @param value
1130     * @param isSpecified
1131     * @exception IOException
1132     */

1133    private void printAttribute (String JavaDoc name, String JavaDoc value, boolean isSpecified, Attr JavaDoc attr) throws IOException JavaDoc{
1134
1135        if (isSpecified || (features & DOMSerializerImpl.DISCARDDEFAULT) == 0) {
1136            if (fDOMFilter !=null &&
1137                (fDOMFilter.getWhatToShow() & NodeFilter.SHOW_ATTRIBUTE)!= 0) {
1138                short code = fDOMFilter.acceptNode(attr);
1139                switch (code) {
1140                    case NodeFilter.FILTER_REJECT:
1141                    case NodeFilter.FILTER_SKIP: {
1142                        return;
1143                    }
1144                    default: {
1145                        // fall through
1146
}
1147                }
1148            }
1149            _printer.printSpace();
1150            _printer.printText( name );
1151            _printer.printText( "=\"" );
1152            printEscaped( value );
1153            _printer.printText( '"' );
1154        }
1155
1156        // If the attribute xml:space exists, determine whether
1157
// to preserve spaces in this and child nodes based on
1158
// its value.
1159
if (name.equals( "xml:space" )) {
1160            if (value.equals( "preserve" ))
1161                fPreserveSpace = true;
1162            else
1163                fPreserveSpace = _format.getPreserveSpace();
1164        }
1165    }
1166
1167    protected String JavaDoc getEntityRef( int ch ) {
1168        // Encode special XML characters into the equivalent character references.
1169
// These five are defined by default for all XML documents.
1170
switch (ch) {
1171        case '<':
1172            return "lt";
1173        case '>':
1174            return "gt";
1175        case '"':
1176            return "quot";
1177        case '\'':
1178            return "apos";
1179        case '&':
1180            return "amp";
1181        }
1182        return null;
1183    }
1184
1185
1186    /** Retrieve and remove the namespaces declarations from the list of attributes.
1187     *
1188     */

1189    private Attributes JavaDoc extractNamespaces( Attributes JavaDoc attrs )
1190    throws SAXException JavaDoc
1191    {
1192        AttributesImpl JavaDoc attrsOnly;
1193        String JavaDoc rawName;
1194        int i;
1195        int indexColon;
1196        String JavaDoc prefix;
1197        int length;
1198
1199        if (attrs == null) {
1200            return null;
1201        }
1202        length = attrs.getLength();
1203        attrsOnly = new AttributesImpl JavaDoc( attrs );
1204
1205        for (i = length - 1 ; i >= 0 ; --i) {
1206            rawName = attrsOnly.getQName( i );
1207
1208            //We have to exclude the namespaces declarations from the attributes
1209
//Append only when the feature http://xml.org/sax/features/namespace-prefixes"
1210
//is TRUE
1211
if (rawName.startsWith( "xmlns" )) {
1212                if (rawName.length() == 5) {
1213                    startPrefixMapping( "", attrs.getValue( i ) );
1214                    attrsOnly.removeAttribute( i );
1215                } else if (rawName.charAt(5) == ':') {
1216                    startPrefixMapping(rawName.substring(6), attrs.getValue(i));
1217                    attrsOnly.removeAttribute( i );
1218                }
1219            }
1220        }
1221        return attrsOnly;
1222    }
1223
1224    //
1225
// Printing attribute value
1226
//
1227
protected void printEscaped(String JavaDoc source) throws IOException JavaDoc {
1228        int length = source.length();
1229        for (int i = 0; i < length; ++i) {
1230            int ch = source.charAt(i);
1231            if (!XMLChar.isValid(ch)) {
1232                if (++i < length) {
1233                    surrogates(ch, source.charAt(i));
1234                } else {
1235                    fatalError("The character '" + (char) ch + "' is an invalid XML character");
1236                }
1237                continue;
1238            }
1239            // escape NL, CR, TAB
1240
if (ch == '\n' || ch == '\r' || ch == '\t') {
1241                printHex(ch);
1242            } else if (ch == '<') {
1243                _printer.printText("&lt;");
1244            } else if (ch == '&') {
1245                _printer.printText("&amp;");
1246            } else if (ch == '"') {
1247                _printer.printText("&quot;");
1248            } else if ((ch >= ' ' && _encodingInfo.isPrintable((char) ch))) {
1249                _printer.printText((char) ch);
1250            } else {
1251                printHex(ch);
1252            }
1253        }
1254    }
1255
1256    /** print text data */
1257    protected void printXMLChar( int ch) throws IOException JavaDoc {
1258        if (ch == '\r') {
1259            printHex(ch);
1260        } else if ( ch == '<') {
1261            _printer.printText("&lt;");
1262        } else if (ch == '&') {
1263            _printer.printText("&amp;");
1264        } else if (ch == '>'){
1265            // character sequence "]]>" can't appear in content, therefore
1266
// we should escape '>'
1267
_printer.printText("&gt;");
1268        } else if ( ch == '\n' || ch == '\t' ||
1269                    ( ch >= ' ' && _encodingInfo.isPrintable((char)ch))) {
1270            _printer.printText((char)ch);
1271        } else {
1272            printHex(ch);
1273        }
1274    }
1275
1276    protected void printText( String JavaDoc text, boolean preserveSpace, boolean unescaped )
1277    throws IOException JavaDoc {
1278        int index;
1279        char ch;
1280        int length = text.length();
1281        if ( preserveSpace ) {
1282            // Preserving spaces: the text must print exactly as it is,
1283
// without breaking when spaces appear in the text and without
1284
// consolidating spaces. If a line terminator is used, a line
1285
// break will occur.
1286
for ( index = 0 ; index < length ; ++index ) {
1287                ch = text.charAt( index );
1288                if (!XMLChar.isValid(ch)) {
1289                    // check if it is surrogate
1290
if (++index <length) {
1291                        surrogates(ch, text.charAt(index));
1292                    } else {
1293                        fatalError("The character '"+(char)ch+"' is an invalid XML character");
1294                    }
1295                    continue;
1296                }
1297                if ( unescaped ) {
1298                    _printer.printText( ch );
1299                } else
1300                    printXMLChar( ch );
1301            }
1302        } else {
1303            // Not preserving spaces: print one part at a time, and
1304
// use spaces between parts to break them into different
1305
// lines. Spaces at beginning of line will be stripped
1306
// by printing mechanism. Line terminator is treated
1307
// no different than other text part.
1308
for ( index = 0 ; index < length ; ++index ) {
1309                ch = text.charAt( index );
1310                if (!XMLChar.isValid(ch)) {
1311                    // check if it is surrogate
1312
if (++index <length) {
1313                        surrogates(ch, text.charAt(index));
1314                    } else {
1315                        fatalError("The character '"+(char)ch+"' is an invalid XML character");
1316                    }
1317                    continue;
1318                }
1319
1320                if ( unescaped )
1321                    _printer.printText( ch );
1322                else
1323                    printXMLChar( ch);
1324            }
1325        }
1326    }
1327
1328
1329
1330    protected void printText( char[] chars, int start, int length,
1331                              boolean preserveSpace, boolean unescaped ) throws IOException JavaDoc {
1332        int index;
1333        char ch;
1334
1335        if ( preserveSpace ) {
1336            // Preserving spaces: the text must print exactly as it is,
1337
// without breaking when spaces appear in the text and without
1338
// consolidating spaces. If a line terminator is used, a line
1339
// break will occur.
1340
while ( length-- > 0 ) {
1341                ch = chars[start++];
1342                if (!XMLChar.isValid(ch)) {
1343                    // check if it is surrogate
1344
if ( length-- > 0 ) {
1345                        surrogates(ch, chars[start++]);
1346                    } else {
1347                        fatalError("The character '"+(char)ch+"' is an invalid XML character");
1348                    }
1349                    continue;
1350                }
1351                if ( unescaped )
1352                    _printer.printText( ch );
1353                else
1354                    printXMLChar( ch );
1355            }
1356        } else {
1357            // Not preserving spaces: print one part at a time, and
1358
// use spaces between parts to break them into different
1359
// lines. Spaces at beginning of line will be stripped
1360
// by printing mechanism. Line terminator is treated
1361
// no different than other text part.
1362
while ( length-- > 0 ) {
1363                ch = chars[start++];
1364                if (!XMLChar.isValid(ch)) {
1365                    // check if it is surrogate
1366
if ( length-- > 0 ) {
1367                        surrogates(ch, chars[start++]);
1368                    } else {
1369                        fatalError("The character '"+(char)ch+"' is an invalid XML character");
1370                    }
1371                    continue;
1372                }
1373                if ( unescaped )
1374                    _printer.printText( ch );
1375                else
1376                    printXMLChar( ch );
1377            }
1378        }
1379    }
1380
1381
1382   /**
1383    * DOM Level 3:
1384    * Check a node to determine if it contains unbound namespace prefixes.
1385    *
1386    * @param node The node to check for unbound namespace prefices
1387    */

1388    protected void checkUnboundNamespacePrefixedNode (Node JavaDoc node) throws IOException JavaDoc{
1389
1390        if (fNamespaces) {
1391
1392            if (DEBUG) {
1393                System.out.println("==>serializeNode("+node.getNodeName()+") [Entity Reference - Namespaces on]");
1394                System.out.println("==>Declared Prefix Count: " + fNSBinder.getDeclaredPrefixCount());
1395                System.out.println("==>Node Name: " + node.getNodeName());
1396                System.out.println("==>First Child Node Name: " + node.getFirstChild().getNodeName());
1397                System.out.println("==>First Child Node Prefix: " + node.getFirstChild().getPrefix());
1398                System.out.println("==>First Child Node NamespaceURI: " + node.getFirstChild().getNamespaceURI());
1399            }
1400
1401        
1402            Node JavaDoc child, next;
1403            for (child = node.getFirstChild(); child != null; child = next) {
1404                next = child.getNextSibling();
1405                if (DEBUG) {
1406                    System.out.println("==>serializeNode("+child.getNodeName()+") [Child Node]");
1407                    System.out.println("==>serializeNode("+child.getPrefix()+") [Child Node Prefix]");
1408                }
1409    
1410                //If a NamespaceURI is not declared for the current
1411
//node's prefix, raise a fatal error.
1412
String JavaDoc prefix = child.getPrefix();
1413                prefix = (prefix == null ||
1414                        prefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(prefix);
1415                if (fNSBinder.getURI(prefix) == null && prefix != null) {
1416                    fatalError("The replacement text of the entity node '"
1417                                + node.getNodeName()
1418                                + "' contains an element node '"
1419                                + child.getNodeName()
1420                                + "' with an undeclared prefix '"
1421                                + prefix + "'.");
1422                }
1423
1424                if (child.getNodeType() == Node.ELEMENT_NODE) {
1425                    
1426                    NamedNodeMap JavaDoc attrs = child.getAttributes();
1427                    
1428                    for (int i = 0; i< attrs.getLength(); i++ ) {
1429                        
1430                        String JavaDoc attrPrefix = attrs.item(i).getPrefix();
1431                        attrPrefix = (attrPrefix == null ||
1432                                attrPrefix.length() == 0) ? XMLSymbols.EMPTY_STRING : fSymbolTable.addSymbol(attrPrefix);
1433                        if (fNSBinder.getURI(attrPrefix) == null && attrPrefix != null) {
1434                            fatalError("The replacement text of the entity node '"
1435                                        + node.getNodeName()
1436                                        + "' contains an element node '"
1437                                        + child.getNodeName()
1438                                        + "' with an attribute '"
1439                                        + attrs.item(i).getNodeName()
1440                                        + "' an undeclared prefix '"
1441                                        + attrPrefix + "'.");
1442                        }
1443                        
1444                    }
1445
1446                }
1447                    
1448                if (child.hasChildNodes()) {
1449                    checkUnboundNamespacePrefixedNode(child);
1450                }
1451            }
1452        }
1453    }
1454
1455    public boolean reset() {
1456        super.reset();
1457        if (fNSBinder != null){
1458            fNSBinder.reset();
1459            // during serialization always have a mapping to empty string
1460
// so we assume there is a declaration.
1461
fNSBinder.declarePrefix(XMLSymbols.EMPTY_STRING, XMLSymbols.EMPTY_STRING);
1462        }
1463        return true;
1464    }
1465
1466}
1467
1468
1469
1470
1471
Popular Tags