KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > apache > xml > serialize > BaseMarkupSerializer


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58
59 // Sep 14, 2000:
60
// Fixed comments to preserve whitespaces and add a line break
61
// when indenting. Reported by Gervase Markham <GRM@dataconnection.com>
62
// Sep 14, 2000:
63
// Fixed serializer to report IO exception directly, instead at
64
// the end of document processing.
65
// Reported by Patrick Higgins <phiggins@transzap.com>
66
// Sep 13, 2000:
67
// CR in character data will print as &#0D;
68
// Aug 25, 2000:
69
// Fixed processing instruction printing inside element content
70
// to not escape content. Reported by Mikael Staldal
71
// <d96-mst@d.kth.se>
72
// Aug 25, 2000:
73
// Added ability to omit comments.
74
// Contributed by Anupam Bagchi <abagchi@jtcsv.com>
75
// Aug 26, 2000:
76
// Fixed bug in newline handling when preserving spaces.
77
// Contributed by Mike Dusseault <mdusseault@home.com>
78
// Aug 29, 2000:
79
// Fixed state.unescaped not being set to false when
80
// entering element state.
81
// Reported by Lowell Vaughn <lvaughn@agillion.com>
82

83
84 package org.enhydra.apache.xml.serialize;
85
86
87 import java.io.IOException JavaDoc;
88 import java.io.OutputStream JavaDoc;
89 import java.io.Writer JavaDoc;
90 import java.util.Hashtable JavaDoc;
91 import java.util.Vector JavaDoc;
92
93 import org.w3c.dom.DOMImplementation JavaDoc;
94 import org.w3c.dom.Document JavaDoc;
95 import org.w3c.dom.DocumentFragment JavaDoc;
96 import org.w3c.dom.DocumentType JavaDoc;
97 import org.w3c.dom.Element JavaDoc;
98 import org.w3c.dom.Entity JavaDoc;
99 import org.w3c.dom.NamedNodeMap JavaDoc;
100 import org.w3c.dom.Node JavaDoc;
101 import org.w3c.dom.Notation JavaDoc;
102 import org.xml.sax.ContentHandler JavaDoc;
103 import org.xml.sax.DTDHandler JavaDoc;
104 import org.xml.sax.DocumentHandler JavaDoc;
105 import org.xml.sax.Locator JavaDoc;
106 import org.xml.sax.SAXException JavaDoc;
107 import org.xml.sax.ext.DeclHandler JavaDoc;
108 import org.xml.sax.ext.LexicalHandler JavaDoc;
109
110
111 /**
112  * Base class for a serializer supporting both DOM and SAX pretty
113  * serializing of XML/HTML/XHTML documents. Derives classes perform
114  * the method-specific serializing, this class provides the common
115  * serializing mechanisms.
116  * <p>
117  * The serializer must be initialized with the proper writer and
118  * output format before it can be used by calling {@link #init}.
119  * The serializer can be reused any number of times, but cannot
120  * be used concurrently by two threads.
121  * <p>
122  * If an output stream is used, the encoding is taken from the
123  * output format (defaults to <tt>UTF-8</tt>). If a writer is
124  * used, make sure the writer uses the same encoding (if applies)
125  * as specified in the output format.
126  * <p>
127  * The serializer supports both DOM and SAX. DOM serializing is done
128  * by calling {@link #serialize} and SAX serializing is done by firing
129  * SAX events and using the serializer as a document handler.
130  * This also applies to derived class.
131  * <p>
132  * If an I/O exception occurs while serializing, the serializer
133  * will not throw an exception directly, but only throw it
134  * at the end of serializing (either DOM or SAX's {@link
135  * org.xml.sax.DocumentHandler#endDocument}.
136  * <p>
137  * For elements that are not specified as whitespace preserving,
138  * the serializer will potentially break long text lines at space
139  * boundaries, indent lines, and serialize elements on separate
140  * lines. Line terminators will be regarded as spaces, and
141  * spaces at beginning of line will be stripped.
142  * <p>
143  * When indenting, the serializer is capable of detecting seemingly
144  * element content, and serializing these elements indented on separate
145  * lines. An element is serialized indented when it is the first or
146  * last child of an element, or immediate following or preceding
147  * another element.
148  *
149  *
150  * @version $Revision: 1.2 $ $Date: 2005/01/26 08:28:45 $
151  * @author <a HREF="mailto:arkin@intalio.com">Assaf Arkin</a>
152  * @see Serializer
153  * @see DOMSerializer
154  */

155 public abstract class BaseMarkupSerializer
156     implements ContentHandler JavaDoc, DocumentHandler JavaDoc, LexicalHandler JavaDoc,
157                DTDHandler JavaDoc, DeclHandler JavaDoc, DOMSerializer, Serializer
158 {
159
160
161     private EncodingInfo _encodingInfo;
162
163
164     /**
165      * Holds array of all element states that have been entered.
166      * The array is automatically resized. When leaving an element,
167      * it's state is not removed but reused when later returning
168      * to the same nesting level.
169      */

170     private ElementState[] _elementStates;
171
172
173     /**
174      * The index of the next state to place in the array,
175      * or one plus the index of the current state. When zero,
176      * we are in no state.
177      */

178     private int _elementStateCount;
179
180
181     /**
182      * Vector holding comments and PIs that come before the root
183      * element (even after it), see {@link #serializePreRoot}.
184      */

185     private Vector JavaDoc _preRoot;
186
187
188     /**
189      * If the document has been started (header serialized), this
190      * flag is set to true so it's not started twice.
191      */

192     protected boolean _started;
193
194
195     /**
196      * True if the serializer has been prepared. This flag is set
197      * to false when the serializer is reset prior to using it,
198      * and to true after it has been prepared for usage.
199      */

200     private boolean _prepared;
201
202
203     /**
204      * Association between namespace URIs (keys) and prefixes (values).
205      * Accumulated here prior to starting an element and placing this
206      * list in the element state.
207      */

208     protected Hashtable JavaDoc _prefixes;
209
210
211     /**
212      * The system identifier of the document type, if known.
213      */

214     protected String JavaDoc _docTypePublicId;
215
216
217     /**
218      * The system identifier of the document type, if known.
219      */

220     protected String JavaDoc _docTypeSystemId;
221
222
223     /**
224      * The output format associated with this serializer. This will never
225      * be a null reference. If no format was passed to the constructor,
226      * the default one for this document type will be used. The format
227      * object is never changed by the serializer.
228      */

229     protected OutputFormat _format;
230
231
232     /**
233      * The printer used for printing text parts.
234      */

235     protected Printer _printer;
236
237
238     /**
239      * True if indenting printer.
240      */

241     protected boolean _indenting;
242
243
244     /**
245      * The underlying writer.
246      */

247     private Writer JavaDoc _writer;
248
249
250     /**
251      * The output stream.
252      */

253     private OutputStream JavaDoc _output;
254
255
256     //--------------------------------//
257
// Constructor and initialization //
258
//--------------------------------//
259

260
261     /**
262      * Protected constructor can only be used by derived class.
263      * Must initialize the serializer before serializing any document,
264      * see {@link #init}.
265      */

266     protected BaseMarkupSerializer( OutputFormat format )
267     {
268         int i;
269
270         _elementStates = new ElementState[ 10 ];
271         for ( i = 0 ; i < _elementStates.length ; ++i )
272             _elementStates[ i ] = new ElementState();
273         _format = format;
274     }
275
276
277     public DocumentHandler JavaDoc asDocumentHandler()
278         throws IOException JavaDoc
279     {
280         prepare();
281         return this;
282     }
283
284
285     public ContentHandler JavaDoc asContentHandler()
286         throws IOException JavaDoc
287     {
288         prepare();
289         return this;
290     }
291
292
293     public DOMSerializer asDOMSerializer()
294         throws IOException JavaDoc
295     {
296         prepare();
297         return this;
298     }
299
300
301     public void setOutputByteStream( OutputStream JavaDoc output )
302     {
303         if ( output == null )
304             throw new NullPointerException JavaDoc( "SER001 Argument 'output' is null." );
305         _output = output;
306         _writer = null;
307         reset();
308     }
309
310
311     public void setOutputCharStream( Writer JavaDoc writer )
312     {
313         if ( writer == null )
314             throw new NullPointerException JavaDoc( "SER001 Argument 'writer' is null." );
315         _writer = writer;
316         _output = null;
317         reset();
318     }
319
320
321     public void setOutputFormat( OutputFormat format )
322     {
323         if ( format == null )
324             throw new NullPointerException JavaDoc( "SER001 Argument 'format' is null." );
325         _format = format;
326         reset();
327     }
328
329
330     public boolean reset()
331     {
332         if ( _elementStateCount > 1 )
333             throw new IllegalStateException JavaDoc( "Serializer reset in the middle of serialization" );
334         _prepared = false;
335         return true;
336     }
337
338
339     protected void prepare()
340         throws IOException JavaDoc
341     {
342         if ( _prepared )
343             return;
344
345         if ( _writer == null && _output == null )
346             throw new IOException JavaDoc( "SER002 No writer supplied for serializer" );
347         // If the output stream has been set, use it to construct
348
// the writer. It is possible that the serializer has been
349
// reused with the same output stream and different encoding.
350

351         _encodingInfo = _format.getEncodingInfo();
352
353         if ( _output != null ) {
354             _writer = _encodingInfo.getWriter(_output);
355         }
356
357         if ( _format.getIndenting() ) {
358             _indenting = true;
359             _printer = new IndentPrinter( _writer, _format );
360         } else {
361             _indenting = false;
362             _printer = new Printer( _writer, _format );
363         }
364
365         ElementState state;
366
367         _elementStateCount = 0;
368         state = _elementStates[ 0 ];
369         state.namespaceURI = null;
370         state.localName = null;
371         state.rawName = null;
372         state.preserveSpace = _format.getPreserveSpace();
373         state.empty = true;
374         state.afterElement = false;
375         state.afterComment = false;
376         state.doCData = state.inCData = false;
377         state.prefixes = null;
378
379         _docTypePublicId = _format.getDoctypePublic();
380         _docTypeSystemId = _format.getDoctypeSystem();
381         _started = false;
382         _prepared = true;
383     }
384
385
386
387     //----------------------------------//
388
// DOM document serializing methods //
389
//----------------------------------//
390

391
392     /**
393      * Serializes the DOM element using the previously specified
394      * writer and output format. Throws an exception only if
395      * an I/O exception occured while serializing.
396      *
397      * @param elem The element to serialize
398      * @throws IOException An I/O exception occured while
399      * serializing
400      */

401     public void serialize( Element JavaDoc elem )
402         throws IOException JavaDoc
403     {
404         prepare();
405         serializeNode( elem );
406         _printer.flush();
407         if ( _printer.getException() != null )
408             throw _printer.getException();
409     }
410
411
412     /**
413      * Serializes the DOM document fragmnt using the previously specified
414      * writer and output format. Throws an exception only if
415      * an I/O exception occured while serializing.
416      *
417      * @param elem The element to serialize
418      * @throws IOException An I/O exception occured while
419      * serializing
420      */

421     public void serialize( DocumentFragment JavaDoc frag )
422         throws IOException JavaDoc
423     {
424         prepare();
425         serializeNode( frag );
426         _printer.flush();
427         if ( _printer.getException() != null )
428             throw _printer.getException();
429     }
430
431
432     /**
433      * Serializes the DOM document using the previously specified
434      * writer and output format. Throws an exception only if
435      * an I/O exception occured while serializing.
436      *
437      * @param doc The document to serialize
438      * @throws IOException An I/O exception occured while
439      * serializing
440      */

441     public void serialize( Document JavaDoc doc )
442         throws IOException JavaDoc
443     {
444         prepare();
445         serializeNode( doc );
446         serializePreRoot();
447         _printer.flush();
448         if ( _printer.getException() != null )
449             throw _printer.getException();
450     }
451
452
453     //------------------------------------------//
454
// SAX document handler serializing methods //
455
//------------------------------------------//
456

457
458     public void startDocument()
459         throws SAXException JavaDoc
460     {
461         try {
462             prepare();
463         } catch ( IOException JavaDoc except ) {
464             throw new SAXException JavaDoc( except.toString() );
465         }
466         // Nothing to do here. All the magic happens in startDocument(String)
467
}
468     
469     
470     public void characters( char[] chars, int start, int length )
471         throws SAXException JavaDoc
472     {
473         ElementState state;
474
475         try {
476         state = content();
477
478         // Check if text should be print as CDATA section or unescaped
479
// based on elements listed in the output format (the element
480
// state) or whether we are inside a CDATA section or entity.
481

482         if ( state.inCData || state.doCData ) {
483             int saveIndent;
484
485             // Print a CDATA section. The text is not escaped, but ']]>'
486
// appearing in the code must be identified and dealt with.
487
// The contents of a text node is considered space preserving.
488
if ( ! state.inCData ) {
489                 _printer.printText( "<![CDATA[" );
490                 state.inCData = true;
491             }
492             saveIndent = _printer.getNextIndent();
493             _printer.setNextIndent( 0 );
494             for ( int index = 0 ; index < length ; ++index ) {
495                 if ( index + 2 < length && chars[ index ] == ']' &&
496                      chars[ index + 1 ] == ']' && chars[ index + 2 ] == '>' ) {
497
498                     printText( chars, start, index + 2, true, true );
499                     _printer.printText( "]]><![CDATA[" );
500                     start += index + 2;
501                     length -= index + 2;
502                     index = 0;
503                 }
504             }
505             if ( length > 0 )
506                 printText( chars, start, length, true, true );
507             _printer.setNextIndent( saveIndent );
508
509         } else {
510
511             int saveIndent;
512
513             if ( state.preserveSpace ) {
514                 // If preserving space then hold of indentation so no
515
// excessive spaces are printed at line breaks, escape
516
// the text content without replacing spaces and print
517
// the text breaking only at line breaks.
518
saveIndent = _printer.getNextIndent();
519                 _printer.setNextIndent( 0 );
520                 printText( chars, start, length, true, state.unescaped );
521                 _printer.setNextIndent( saveIndent );
522             } else {
523                 printText( chars, start, length, false, state.unescaped );
524             }
525         }
526         } catch ( IOException JavaDoc except ) {
527             throw new SAXException JavaDoc( except );
528         }
529     }
530
531
532     public void ignorableWhitespace( char[] chars, int start, int length )
533         throws SAXException JavaDoc
534     {
535         int i;
536
537         try {
538         content();
539
540         // Print ignorable whitespaces only when indenting, after
541
// all they are indentation. Cancel the indentation to
542
// not indent twice.
543
if ( _indenting ) {
544             _printer.setThisIndent( 0 );
545             for ( i = start ; length-- > 0 ; ++i )
546                 _printer.printText( chars[ i ] );
547         }
548         } catch ( IOException JavaDoc except ) {
549             throw new SAXException JavaDoc( except );
550         }
551     }
552
553
554     public final void processingInstruction( String JavaDoc target, String JavaDoc code )
555         throws SAXException JavaDoc
556     {
557         try {
558             processingInstructionIO( target, code );
559         } catch ( IOException JavaDoc except ) {
560         throw new SAXException JavaDoc( except );
561         }
562     }
563
564     public void processingInstructionIO( String JavaDoc target, String JavaDoc code )
565         throws IOException JavaDoc
566     {
567         int index;
568         StringBuffer JavaDoc buffer;
569         ElementState state;
570
571         state = content();
572         buffer = new StringBuffer JavaDoc( 40 );
573
574         // Create the processing instruction textual representation.
575
// Make sure we don't have '?>' inside either target or code.
576
index = target.indexOf( "?>" );
577         if ( index >= 0 )
578             buffer.append( "<?" ).append( target.substring( 0, index ) );
579         else
580             buffer.append( "<?" ).append( target );
581         if ( code != null ) {
582             buffer.append( ' ' );
583             index = code.indexOf( "?>" );
584             if ( index >= 0 )
585                 buffer.append( code.substring( 0, index ) );
586             else
587                 buffer.append( code );
588         }
589         buffer.append( "?>" );
590
591         // If before the root element (or after it), do not print
592
// the PI directly but place it in the pre-root vector.
593
if ( isDocumentState() ) {
594             if ( _preRoot == null )
595                 _preRoot = new Vector JavaDoc();
596             _preRoot.addElement( buffer.toString() );
597         } else {
598             _printer.indent();
599             printText( buffer.toString(), true, true );
600             _printer.unindent();
601             if ( _indenting )
602             state.afterElement = true;
603         }
604     }
605
606
607     public void comment( char[] chars, int start, int length )
608         throws SAXException JavaDoc
609     {
610         try {
611         comment( new String JavaDoc( chars, start, length ) );
612         } catch ( IOException JavaDoc except ) {
613             throw new SAXException JavaDoc( except );
614     }
615     }
616
617
618     public void comment( String JavaDoc text )
619         throws IOException JavaDoc
620     {
621         StringBuffer JavaDoc buffer;
622         int index;
623         ElementState state;
624         
625         if ( _format.getOmitComments() )
626             return;
627
628         state = content();
629         buffer = new StringBuffer JavaDoc( 40 );
630         // Create the processing comment textual representation.
631
// Make sure we don't have '-->' inside the comment.
632
index = text.indexOf( "-->" );
633         if ( index >= 0 )
634             buffer.append( "<!--" ).append( text.substring( 0, index ) ).append( "-->" );
635         else
636             buffer.append( "<!--" ).append( text ).append( "-->" );
637
638         // If before the root element (or after it), do not print
639
// the comment directly but place it in the pre-root vector.
640
if ( isDocumentState() ) {
641             if ( _preRoot == null )
642                 _preRoot = new Vector JavaDoc();
643             _preRoot.addElement( buffer.toString() );
644         } else {
645             // Indent this element on a new line if the first
646
// content of the parent element or immediately
647
// following an element.
648
if ( _indenting && ! state.preserveSpace)
649                 _printer.breakLine();
650                         _printer.indent();
651             printText( buffer.toString(), true, true );
652                         _printer.unindent();
653             if ( _indenting )
654                 state.afterElement = true;
655         }
656                 state.afterComment = true;
657                 state.afterElement = false;
658     }
659
660
661     public void startCDATA()
662     {
663         ElementState state;
664
665         state = getElementState();
666         state.doCData = true;
667     }
668
669
670     public void endCDATA()
671     {
672         ElementState state;
673
674         state = getElementState();
675         state.doCData = false;
676     }
677
678
679     public void startNonEscaping()
680     {
681         ElementState state;
682
683         state = getElementState();
684         state.unescaped = true;
685     }
686
687
688     public void endNonEscaping()
689     {
690         ElementState state;
691
692         state = getElementState();
693         state.unescaped = false;
694     }
695
696
697     public void startPreserving()
698     {
699         ElementState state;
700
701         state = getElementState();
702         state.preserveSpace = true;
703     }
704
705
706     public void endPreserving()
707     {
708         ElementState state;
709
710         state = getElementState();
711         state.preserveSpace = false;
712     }
713
714
715     /**
716      * Called at the end of the document to wrap it up.
717      * Will flush the output stream and throw an exception
718      * if any I/O error occured while serializing.
719      *
720      * @throws SAXException An I/O exception occured during
721      * serializing
722      */

723     public void endDocument()
724         throws SAXException JavaDoc
725     {
726         try {
727         // Print all the elements accumulated outside of
728
// the root element.
729
serializePreRoot();
730         // Flush the output, this is necessary for buffered output.
731
_printer.flush();
732         } catch ( IOException JavaDoc except ) {
733             throw new SAXException JavaDoc( except );
734     }
735     }
736
737
738     public void startEntity( String JavaDoc name )
739     {
740         // ???
741
}
742
743
744     public void endEntity( String JavaDoc name )
745     {
746         // ???
747
}
748
749
750     public void setDocumentLocator( Locator JavaDoc locator )
751     {
752         // Nothing to do
753
}
754
755
756     //-----------------------------------------//
757
// SAX content handler serializing methods //
758
//-----------------------------------------//
759

760
761     public void skippedEntity ( String JavaDoc name )
762         throws SAXException JavaDoc
763     {
764         try {
765         endCDATA();
766         content();
767         _printer.printText( '&' );
768         _printer.printText( name );
769         _printer.printText( ';' );
770         } catch ( IOException JavaDoc except ) {
771             throw new SAXException JavaDoc( except );
772     }
773     }
774
775
776     public void startPrefixMapping( String JavaDoc prefix, String JavaDoc uri )
777         throws SAXException JavaDoc
778     {
779         if ( _prefixes == null )
780             _prefixes = new Hashtable JavaDoc();
781         _prefixes.put( uri, prefix == null ? "" : prefix );
782     }
783
784
785     public void endPrefixMapping( String JavaDoc prefix )
786         throws SAXException JavaDoc
787     {
788     }
789
790
791     //------------------------------------------//
792
// SAX DTD/Decl handler serializing methods //
793
//------------------------------------------//
794

795
796     public final void startDTD( String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId )
797         throws SAXException JavaDoc
798     {
799         try {
800         _printer.enterDTD();
801         _docTypePublicId = publicId;
802         _docTypeSystemId = systemId;
803         } catch ( IOException JavaDoc except ) {
804             throw new SAXException JavaDoc( except );
805         }
806     }
807
808
809     public void endDTD()
810     {
811         // Nothing to do here, all the magic occurs in startDocument(String).
812
}
813
814
815     public void elementDecl( String JavaDoc name, String JavaDoc model )
816         throws SAXException JavaDoc
817     {
818         try {
819         _printer.enterDTD();
820         _printer.printText( "<!ELEMENT " );
821         _printer.printText( name );
822         _printer.printText( ' ' );
823         _printer.printText( model );
824         _printer.printText( '>' );
825         if ( _indenting )
826             _printer.breakLine();
827         } catch ( IOException JavaDoc except ) {
828             throw new SAXException JavaDoc( except );
829         }
830     }
831
832
833     public void attributeDecl( String JavaDoc eName, String JavaDoc aName, String JavaDoc type,
834                                String JavaDoc valueDefault, String JavaDoc value )
835         throws SAXException JavaDoc
836     {
837         try {
838         _printer.enterDTD();
839         _printer.printText( "<!ATTLIST " );
840         _printer.printText( eName );
841         _printer.printText( ' ' );
842         _printer.printText( aName );
843         _printer.printText( ' ' );
844         _printer.printText( type );
845         if ( valueDefault != null ) {
846             _printer.printText( ' ' );
847             _printer.printText( valueDefault );
848         }
849         if ( value != null ) {
850             _printer.printText( " \"" );
851             printEscaped( value );
852             _printer.printText( '"' );
853         }
854         _printer.printText( '>' );
855         if ( _indenting )
856             _printer.breakLine();
857         } catch ( IOException JavaDoc except ) {
858             throw new SAXException JavaDoc( except );
859     }
860     }
861
862
863     public void internalEntityDecl( String JavaDoc name, String JavaDoc value )
864         throws SAXException JavaDoc
865     {
866         try {
867         _printer.enterDTD();
868         _printer.printText( "<!ENTITY " );
869         _printer.printText( name );
870         _printer.printText( " \"" );
871         printEscaped( value );
872         _printer.printText( "\">" );
873         if ( _indenting )
874             _printer.breakLine();
875         } catch ( IOException JavaDoc except ) {
876             throw new SAXException JavaDoc( except );
877         }
878     }
879
880
881     public void externalEntityDecl( String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId )
882         throws SAXException JavaDoc
883     {
884         try {
885         _printer.enterDTD();
886         unparsedEntityDecl( name, publicId, systemId, null );
887         } catch ( IOException JavaDoc except ) {
888             throw new SAXException JavaDoc( except );
889         }
890     }
891
892
893     public void unparsedEntityDecl( String JavaDoc name, String JavaDoc publicId,
894                                     String JavaDoc systemId, String JavaDoc notationName )
895         throws SAXException JavaDoc
896     {
897         try {
898         _printer.enterDTD();
899         if ( publicId == null ) {
900             _printer.printText( "<!ENTITY " );
901             _printer.printText( name );
902             _printer.printText( " SYSTEM " );
903             printDoctypeURL( systemId );
904  &nbs