KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xml > internal > serializer > ToStream


1 /*
2  * Copyright 2001-2004 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  * $Id: ToStream.java,v 1.29 2004/02/18 22:57:44 minchau Exp $
18  */

19 package com.sun.org.apache.xml.internal.serializer;
20
21 import java.io.IOException JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.io.UnsupportedEncodingException JavaDoc;
24 import java.io.Writer JavaDoc;
25 import java.util.Properties JavaDoc;
26 import java.util.StringTokenizer JavaDoc;
27 import java.util.Vector JavaDoc;
28
29 import javax.xml.transform.OutputKeys JavaDoc;
30 import javax.xml.transform.Transformer JavaDoc;
31
32 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
33 import com.sun.org.apache.xml.internal.res.XMLMessages;
34 import com.sun.org.apache.xml.internal.utils.BoolStack;
35 import com.sun.org.apache.xml.internal.utils.FastStringBuffer;
36 import com.sun.org.apache.xml.internal.utils.QName;
37 import com.sun.org.apache.xml.internal.utils.TreeWalker;
38 import com.sun.org.apache.xml.internal.utils.WrappedRuntimeException;
39 import org.w3c.dom.Node JavaDoc;
40 import org.xml.sax.Attributes JavaDoc;
41 import org.xml.sax.ContentHandler JavaDoc;
42 import org.xml.sax.SAXException JavaDoc;
43
44 //import com.sun.media.sound.IESecurity;
45

46 /**
47  * This abstract class is a base class for other stream
48  * serializers (xml, html, text ...) that write output to a stream.
49  * @author Santiago Pericas-Geertsen
50  * @author G. Todd Miller
51  */

52 abstract public class ToStream extends SerializerBase
53 {
54
55     private static final String JavaDoc COMMENT_BEGIN = "<!--";
56     private static final String JavaDoc COMMENT_END = "-->";
57
58     /** Stack to keep track of disabling output escaping. */
59     protected BoolStack m_disableOutputEscapingStates = new BoolStack();
60
61     /**
62      * Boolean that tells if we already tried to get the converter.
63      */

64     boolean m_triedToGetConverter = false;
65     /**
66      * Method reference to the sun.io.CharToByteConverter#canConvert method
67      * for this encoding. Invalid if m_charToByteConverter is null.
68      */

69     java.lang.reflect.Method JavaDoc m_canConvertMeth;
70
71     /**
72      * Opaque reference to the sun.io.CharToByteConverter for this
73      * encoding.
74      */

75     Object JavaDoc m_charToByteConverter = null;
76
77     /**
78      * Stack to keep track of whether or not we need to
79      * preserve whitespace.
80      *
81      * Used to push/pop values used for the field m_ispreserve, but
82      * m_ispreserve is only relevant if m_doIndent is true.
83      * If m_doIndent is false this field has no impact.
84      *
85      */

86     protected BoolStack m_preserves = new BoolStack();
87
88     /**
89      * State flag to tell if preservation of whitespace
90      * is important.
91      *
92      * Used only in shouldIndent() but only if m_doIndent is true.
93      * If m_doIndent is false this flag has no impact.
94      *
95      */

96     protected boolean m_ispreserve = false;
97
98     /**
99      * State flag that tells if the previous node processed
100      * was text, so we can tell if we should preserve whitespace.
101      *
102      * Used in endDocument() and shouldIndent() but
103      * only if m_doIndent is true.
104      * If m_doIndent is false this flag has no impact.
105      */

106     protected boolean m_isprevtext = false;
107
108     /**
109      * The maximum character size before we have to resort
110      * to escaping.
111      */

112     protected int m_maxCharacter = Encodings.getLastPrintable();
113
114     /**
115      * The system line separator for writing out line breaks.
116      */

117     protected final char[] m_lineSep =
118         System.getProperty("line.separator").toCharArray();
119         
120     /**
121      * True if the the system line separator is to be used.
122      */

123     protected boolean m_lineSepUse = true;
124
125     /**
126      * The length of the line seperator, since the write is done
127      * one character at a time.
128      */

129     protected final int m_lineSepLen = m_lineSep.length;
130
131     /**
132      * Map that tells which characters should have special treatment, and it
133      * provides character to entity name lookup.
134      */

135     protected CharInfo m_charInfo;
136
137     /** True if we control the buffer, and we should flush the output on endDocument. */
138     boolean m_shouldFlush = true;
139
140     /**
141      * Add space before '/>' for XHTML.
142      */

143     protected boolean m_spaceBeforeClose = false;
144
145     /**
146      * Flag to signal that a newline should be added.
147      *
148      * Used only in indent() which is called only if m_doIndent is true.
149      * If m_doIndent is false this flag has no impact.
150      */

151     boolean m_startNewLine;
152
153     /**
154      * Tells if we're in an internal document type subset.
155      */

156     protected boolean m_inDoctype = false;
157
158     /**
159        * Flag to quickly tell if the encoding is UTF8.
160        */

161     boolean m_isUTF8 = false;
162
163     /** The xsl:output properties. */
164     protected Properties JavaDoc m_format;
165
166     /**
167      * remembers if we are in between the startCDATA() and endCDATA() callbacks
168      */

169     protected boolean m_cdataStartCalled = false;
170
171     /**
172      * Default constructor
173      */

174     public ToStream()
175     {
176     }
177
178     /**
179      * This helper method to writes out "]]>" when closing a CDATA section.
180      *
181      * @throws org.xml.sax.SAXException
182      */

183     protected void closeCDATA() throws org.xml.sax.SAXException JavaDoc
184     {
185         try
186         {
187             m_writer.write(CDATA_DELIMITER_CLOSE);
188             // write out a CDATA section closing "]]>"
189
m_cdataTagOpen = false; // Remember that we have done so.
190
}
191         catch (IOException JavaDoc e)
192         {
193             throw new SAXException JavaDoc(e);
194         }
195     }
196
197     /**
198      * Serializes the DOM node. Throws an exception only if an I/O
199      * exception occured while serializing.
200      *
201      * @param elem The element to serialize
202      *
203      * @param node Node to serialize.
204      * @throws IOException An I/O exception occured while serializing
205      */

206     public void serialize(Node JavaDoc node) throws IOException JavaDoc
207     {
208
209         try
210         {
211             TreeWalker walker =
212                 new TreeWalker(this, new com.sun.org.apache.xml.internal.utils.DOM2Helper());
213
214             walker.traverse(node);
215         }
216         catch (org.xml.sax.SAXException JavaDoc se)
217         {
218             throw new WrappedRuntimeException(se);
219         }
220     }
221
222     /**
223      * Return true if the character is the high member of a surrogate pair.
224      *
225      * NEEDSDOC @param c
226      *
227      * NEEDSDOC ($objectName$) @return
228      */

229     static final boolean isUTF16Surrogate(char c)
230     {
231         return (c & 0xFC00) == 0xD800;
232     }
233
234     /**
235      * Taken from XSLTC
236      */

237     private boolean m_escaping = true;
238
239     /**
240      * Flush the formatter's result stream.
241      *
242      * @throws org.xml.sax.SAXException
243      */

244     protected final void flushWriter() throws org.xml.sax.SAXException JavaDoc
245     {
246         final java.io.Writer JavaDoc writer = m_writer;
247         if (null != writer)
248         {
249             try
250             {
251                 if (writer instanceof WriterToUTF8Buffered)
252                 {
253                     if (m_shouldFlush)
254                          ((WriterToUTF8Buffered) writer).flush();
255                     else
256                          ((WriterToUTF8Buffered) writer).flushBuffer();
257                 }
258                 if (writer instanceof WriterToASCI)
259                 {
260                     if (m_shouldFlush)
261                         writer.flush();
262                 }
263                 else
264                 {
265                     // Flush always.
266
// Not a great thing if the writer was created
267
// by this class, but don't have a choice.
268
writer.flush();
269                 }
270             }
271             catch (IOException JavaDoc ioe)
272             {
273                 throw new org.xml.sax.SAXException JavaDoc(ioe);
274             }
275         }
276     }
277
278     /**
279      * Get the output stream where the events will be serialized to.
280      *
281      * @return reference to the result stream, or null of only a writer was
282      * set.
283      */

284     public OutputStream JavaDoc getOutputStream()
285     {
286
287         if (m_writer instanceof WriterToUTF8Buffered)
288             return ((WriterToUTF8Buffered) m_writer).getOutputStream();
289         if (m_writer instanceof WriterToASCI)
290             return ((WriterToASCI) m_writer).getOutputStream();
291         else
292             return null;
293     }
294
295     // Implement DeclHandler
296

297     /**
298      * Report an element type declaration.
299      *
300      * <p>The content model will consist of the string "EMPTY", the
301      * string "ANY", or a parenthesised group, optionally followed
302      * by an occurrence indicator. The model will be normalized so
303      * that all whitespace is removed,and will include the enclosing
304      * parentheses.</p>
305      *
306      * @param name The element type name.
307      * @param model The content model as a normalized string.
308      * @exception SAXException The application may raise an exception.
309      */

310     public void elementDecl(String JavaDoc name, String JavaDoc model) throws SAXException JavaDoc
311     {
312         // Do not inline external DTD
313
if (m_inExternalDTD)
314             return;
315         try
316         {
317             final java.io.Writer JavaDoc writer = m_writer;
318             if (m_needToOutputDocTypeDecl)
319             {
320                 outputDocTypeDecl(m_elemContext.m_elementName, false);
321                 m_needToOutputDocTypeDecl = false;
322             }
323             if (m_inDoctype)
324             {
325                 writer.write(" [");
326                 writer.write(m_lineSep, 0, m_lineSepLen);
327
328                 m_inDoctype = false;
329             }
330
331             writer.write("<!ELEMENT ");
332             writer.write(name);
333             writer.write(' ');
334             writer.write(model);
335             writer.write('>');
336             writer.write(m_lineSep, 0, m_lineSepLen);
337         }
338         catch (IOException JavaDoc e)
339         {
340             throw new SAXException JavaDoc(e);
341         }
342
343     }
344
345     /**
346      * Report an internal entity declaration.
347      *
348      * <p>Only the effective (first) declaration for each entity
349      * will be reported.</p>
350      *
351      * @param name The name of the entity. If it is a parameter
352      * entity, the name will begin with '%'.
353      * @param value The replacement text of the entity.
354      * @exception SAXException The application may raise an exception.
355      * @see #externalEntityDecl
356      * @see org.xml.sax.DTDHandler#unparsedEntityDecl
357      */

358     public void internalEntityDecl(String JavaDoc name, String JavaDoc value)
359         throws SAXException JavaDoc
360     {
361         // Do not inline external DTD
362
if (m_inExternalDTD)
363             return;
364         try
365         {
366             if (m_needToOutputDocTypeDecl)
367             {
368                 outputDocTypeDecl(m_elemContext.m_elementName, false);
369                 m_needToOutputDocTypeDecl = false;
370             }
371             if (m_inDoctype)
372             {
373                 final java.io.Writer JavaDoc writer = m_writer;
374                 writer.write(" [");
375                 writer.write(m_lineSep, 0, m_lineSepLen);
376
377                 m_inDoctype = false;
378             }
379
380             outputEntityDecl(name, value);
381         }
382         catch (IOException JavaDoc e)
383         {
384             throw new SAXException JavaDoc(e);
385         }
386
387     }
388
389     /**
390      * Output the doc type declaration.
391      *
392      * @param name non-null reference to document type name.
393      * NEEDSDOC @param value
394      *
395      * @throws org.xml.sax.SAXException
396      */

397     void outputEntityDecl(String JavaDoc name, String JavaDoc value) throws IOException JavaDoc
398     {
399         final java.io.Writer JavaDoc writer = m_writer;
400         writer.write("<!ENTITY ");
401         writer.write(name);
402         writer.write(" \"");
403         writer.write(value);
404         writer.write("\">");
405         writer.write(m_lineSep, 0, m_lineSepLen);
406     }
407
408     /**
409      * Output a system-dependent line break.
410      *
411      * @throws org.xml.sax.SAXException
412      */

413     protected final void outputLineSep() throws IOException JavaDoc
414     {
415
416         m_writer.write(m_lineSep, 0, m_lineSepLen);
417     }
418
419     /**
420      * Specifies an output format for this serializer. It the
421      * serializer has already been associated with an output format,
422      * it will switch to the new format. This method should not be
423      * called while the serializer is in the process of serializing
424      * a document.
425      *
426      * @param format The output format to use
427      */

428     public void setOutputFormat(Properties JavaDoc format)
429     {
430
431         boolean shouldFlush = m_shouldFlush;
432
433         init(m_writer, format, false, false);
434
435         m_shouldFlush = shouldFlush;
436     }
437
438     /**
439      * Initialize the serializer with the specified writer and output format.
440      * Must be called before calling any of the serialize methods.
441      *
442      * @param writer The writer to use
443      * @param format The output format
444      * @param shouldFlush True if the writer should be flushed at EndDocument.
445      */

446     private synchronized void init(
447         Writer JavaDoc writer,
448         Properties JavaDoc format,
449         boolean defaultProperties,
450         boolean shouldFlush)
451     {
452
453         m_shouldFlush = shouldFlush;
454
455         
456         // if we are tracing events we need to trace what
457
// characters are written to the output writer.
458
if (m_tracer != null
459          && !(writer instanceof SerializerTraceWriter) )
460             m_writer = new SerializerTraceWriter(writer, m_tracer);
461         else
462             m_writer = writer;
463         
464
465         m_format = format;
466         // m_cdataSectionNames =
467
// OutputProperties.getQNameProperties(
468
// OutputKeys.CDATA_SECTION_ELEMENTS,
469
// format);
470
setCdataSectionElements(OutputKeys.CDATA_SECTION_ELEMENTS, format);
471
472         setIndentAmount(
473             OutputPropertyUtils.getIntProperty(
474                 OutputPropertiesFactory.S_KEY_INDENT_AMOUNT,
475                 format));
476         setIndent(
477             OutputPropertyUtils.getBooleanProperty(OutputKeys.INDENT, format));
478
479         boolean shouldNotWriteXMLHeader =
480             OutputPropertyUtils.getBooleanProperty(
481                 OutputKeys.OMIT_XML_DECLARATION,
482                 format);
483         setOmitXMLDeclaration(shouldNotWriteXMLHeader);
484         setDoctypeSystem(format.getProperty(OutputKeys.DOCTYPE_SYSTEM));
485         String JavaDoc doctypePublic = format.getProperty(OutputKeys.DOCTYPE_PUBLIC);
486         setDoctypePublic(doctypePublic);
487
488         // if standalone was explicitly specified
489
if (format.get(OutputKeys.STANDALONE) != null)
490         {
491             String JavaDoc val = format.getProperty(OutputKeys.STANDALONE);
492             if (defaultProperties)
493                 setStandaloneInternal(val);
494             else
495                 setStandalone(val);
496         }
497
498         setMediaType(format.getProperty(OutputKeys.MEDIA_TYPE));
499
500         if (null != doctypePublic)
501         {
502             if (doctypePublic.startsWith("-//W3C//DTD XHTML"))
503                 m_spaceBeforeClose = true;
504         }
505
506         // initCharsMap();
507
String JavaDoc encoding = getEncoding();
508         if (null == encoding)
509         {
510             encoding =
511                 Encodings.getMimeEncoding(
512                     format.getProperty(OutputKeys.ENCODING));
513             setEncoding(encoding);
514         }
515
516         m_isUTF8 = encoding.equals(Encodings.DEFAULT_MIME_ENCODING);
517         m_maxCharacter = Encodings.getLastPrintable(encoding);
518
519         // Access this only from the Hashtable level... we don't want to
520
// get default properties.
521
String JavaDoc entitiesFileName =
522             (String JavaDoc) format.get(OutputPropertiesFactory.S_KEY_ENTITIES);
523
524         if (null != entitiesFileName)
525         {
526
527             String JavaDoc method =
528                 (String JavaDoc) format.get(OutputKeys.METHOD);
529             
530             m_charInfo = CharInfo.getCharInfo(entitiesFileName, method);
531         }
532
533     }
534
535     /**
536      * Initialize the serializer with the specified writer and output format.
537      * Must be called before calling any of the serialize methods.
538      *
539      * @param writer The writer to use
540      * @param format The output format
541      */

542     private synchronized void init(Writer JavaDoc writer, Properties JavaDoc format)
543     {
544         init(writer, format, false, false);
545     }
546     /**
547      * Initialize the serializer with the specified output stream and output
548      * format. Must be called before calling any of the serialize methods.
549      *
550      * @param output The output stream to use
551      * @param format The output format
552      * @param defaultProperties true if the properties are the default
553      * properties
554      *
555      * @throws UnsupportedEncodingException The encoding specified in the
556      * output format is not supported
557      */

558     protected synchronized void init(
559         OutputStream JavaDoc output,
560         Properties JavaDoc format,
561         boolean defaultProperties)
562         throws UnsupportedEncodingException JavaDoc
563     {
564
565         String JavaDoc encoding = getEncoding();
566         if (encoding == null)
567         {
568             // if not already set then get it from the properties
569
encoding =
570                 Encodings.getMimeEncoding(
571                     format.getProperty(OutputKeys.ENCODING));
572             setEncoding(encoding);
573         }
574
575         if (encoding.equalsIgnoreCase("UTF-8"))
576         {
577             m_isUTF8 = true;
578             // if (output instanceof java.io.BufferedOutputStream)
579
// {
580
// init(new WriterToUTF8(output), format, defaultProperties, true);
581
// }
582
// else if (output instanceof java.io.FileOutputStream)
583
// {
584
// init(new WriterToUTF8Buffered(output), format, defaultProperties, true);
585
// }
586
// else
587
// {
588
// // Not sure what to do in this case. I'm going to be conservative
589
// // and not buffer.
590
// init(new WriterToUTF8(output), format, defaultProperties, true);
591
// }
592

593
594                 init(
595                     new WriterToUTF8Buffered(output),
596                     format,
597                     defaultProperties,
598                     true);
599
600
601         }
602         else if (
603             encoding.equals("WINDOWS-1250")
604                 || encoding.equals("US-ASCII")
605                 || encoding.equals("ASCII"))
606         {
607             init(new WriterToASCI(output), format, defaultProperties, true);
608         }
609         else
610         {
611             Writer JavaDoc osw;
612
613             try
614             {
615                 osw = Encodings.getWriter(output, encoding);
616             }
617             catch (UnsupportedEncodingException JavaDoc uee)
618             {
619                 System.out.println(
620                     "Warning: encoding \""
621                         + encoding
622                         + "\" not supported"
623                         + ", using "
624                         + Encodings.DEFAULT_MIME_ENCODING);
625
626                 encoding = Encodings.DEFAULT_MIME_ENCODING;
627                 setEncoding(encoding);
628                 osw = Encodings.getWriter(output, encoding);
629             }
630
631             m_maxCharacter = Encodings.getLastPrintable(encoding);
632
633             init(osw, format, defaultProperties, true);
634         }
635
636     }
637
638     /**
639      * Returns the output format for this serializer.
640      *
641      * @return The output format in use
642      */

643     public Properties JavaDoc getOutputFormat()
644     {
645         return m_format;
646     }
647
648     /**
649      * Specifies a writer to which the document should be serialized.
650      * This method should not be called while the serializer is in
651      * the process of serializing a document.
652      *
653      * @param writer The output writer stream
654      */

655     public void setWriter(Writer JavaDoc writer)
656     {
657         // if we are tracing events we need to trace what
658
// characters are written to the output writer.
659
if (m_tracer != null
660          && !(writer instanceof SerializerTraceWriter) )
661             m_writer = new SerializerTraceWriter(writer, m_tracer);
662         else
663             m_writer = writer;
664     }
665     
666     /**
667      * Set if the operating systems end-of-line line separator should
668      * be used when serializing. If set false NL character
669      * (decimal 10) is left alone, otherwise the new-line will be replaced on
670      * output with the systems line separator. For example on UNIX this is
671      * NL, while on Windows it is two characters, CR NL, where CR is the
672      * carriage-return (decimal 13).
673      *
674      * @param use_sytem_line_break True if an input NL is replaced with the
675      * operating systems end-of-line separator.
676      * @return The previously set value of the serializer.
677      */

678     public boolean setLineSepUse(boolean use_sytem_line_break)
679     {
680         boolean oldValue = m_lineSepUse;
681         m_lineSepUse = use_sytem_line_break;
682         return oldValue;
683     }
684
685     /**
686      * Specifies an output stream to which the document should be
687      * serialized. This method should not be called while the
688      * serializer is in the process of serializing a document.
689      * <p>
690      * The encoding specified in the output properties is used, or
691      * if no encoding was specified, the default for the selected
692      * output method.
693      *
694      * @param output The output stream
695      */

696     public void setOutputStream(OutputStream JavaDoc output)
697     {
698
699         try
700         {
701             Properties JavaDoc format;
702             if (null == m_format)
703                 format =
704                     OutputPropertiesFactory.getDefaultMethodProperties(
705                         Method.XML);
706             else
707                 format = m_format;
708             init(output, format, true);
709         }
710         catch (UnsupportedEncodingException JavaDoc uee)
711         {
712
713             // Should have been warned in init, I guess...
714
}
715     }
716
717     /**
718      * @see com.sun.org.apache.xml.internal.serializer.SerializationHandler#setEscaping(boolean)
719      */

720     public boolean setEscaping(boolean escape)
721     {
722         final boolean temp = m_escaping;
723         m_escaping = escape;
724         return temp;
725
726     }
727
728
729     /**
730      * Might print a newline character and the indentation amount
731      * of the given depth.
732      *
733      * @param depth the indentation depth (element nesting depth)
734      *
735      * @throws org.xml.sax.SAXException if an error occurs during writing.
736      */

737     protected void indent(int depth) throws IOException JavaDoc
738     {
739
740         if (m_startNewLine)
741             outputLineSep();
742         /* For m_indentAmount > 0 this extra test might be slower
743          * but Xalan's default value is 0, so this extra test
744          * will run faster in that situation.
745          */

746         if (m_indentAmount > 0)
747             printSpace(depth * m_indentAmount);
748
749     }
750     
751     /**
752      * Indent at the current element nesting depth.
753      * @throws IOException
754      */

755     protected void indent() throws IOException JavaDoc
756     {
757         indent(m_elemContext.m_currentElemDepth);
758     }
759     /**
760      * Prints <var>n</var> spaces.
761      * @param pw The character output stream to use.
762      * @param n Number of spaces to print.
763      *
764      * @throws org.xml.sax.SAXException if an error occurs when writing.
765      */

766     private void printSpace(int n) throws IOException JavaDoc
767     {
768         final java.io.Writer JavaDoc writer = m_writer;
769         for (int i = 0; i < n; i++)
770         {
771             writer.write(' ');
772         }
773
774     }
775
776     /**
777      * Report an attribute type declaration.
778      *
779      * <p>Only the effective (first) declaration for an attribute will
780      * be reported. The type will be one of the strings "CDATA",
781      * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
782      * "ENTITIES", or "NOTATION", or a parenthesized token group with
783      * the separator "|" and all whitespace removed.</p>
784      *
785      * @param eName The name of the associated element.
786      * @param aName The name of the attribute.
787      * @param type A string representing the attribute type.
788      * @param valueDefault A string representing the attribute default
789      * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
790      * none of these applies.
791      * @param value A string representing the attribute's default value,
792      * or null if there is none.
793      * @exception SAXException The application may raise an exception.
794      */

795     public void attributeDecl(
796         String JavaDoc eName,
797         String JavaDoc aName,
798         String JavaDoc type,
799         String JavaDoc valueDefault,
800         String JavaDoc value)
801         throws SAXException JavaDoc
802     {
803         // Do not inline external DTD
804
if (m_inExternalDTD)
805             return;
806         try
807         {
808             final java.io.Writer JavaDoc writer = m_writer;
809             if (m_needToOutputDocTypeDecl)
810             {
811                 outputDocTypeDecl(m_elemContext.m_elementName, false);
812                 m_needToOutputDocTypeDecl = false;
813             }
814             if (m_inDoctype)
815             {
816                 writer.write(" [");
817                 writer.write(m_lineSep, 0, m_lineSepLen);
818
819                 m_inDoctype = false;
820             }
821
822             writer.write("<!ATTLIST ");
823             writer.write(eName);
824             writer.write(' ');
825
826             writer.write(aName);
827             writer.write(' ');
828             writer.write(type);
829             if (valueDefault != null)
830             {
831                 writer.write(' ');
832                 writer.write(valueDefault);
833             }
834
835             //writer.write(" ");
836
//writer.write(value);
837
writer.write('>');
838             writer.write(m_lineSep, 0, m_lineSepLen);
839         }
840         catch (IOException JavaDoc e)
841         {
842             throw new SAXException JavaDoc(e);
843         }
844     }
845
846     /**
847      * Get the character stream where the events will be serialized to.
848      *
849      * @return Reference to the result Writer, or null.
850      */

851     public Writer JavaDoc getWriter()
852     {
853         return m_writer;
854     }
855
856     /**
857      * Report a parsed external entity declaration.
858      *
859      * <p>Only the effective (first) declaration for each entity
860      * will be reported.</p>
861      *
862      * @param name The name of the entity. If it is a parameter
863      * entity, the name will begin with '%'.
864      * @param publicId The declared public identifier of the entity, or
865      * null if none was declared.
866      * @param systemId The declared system identifier of the entity.
867      * @exception SAXException The application may raise an exception.
868      * @see #internalEntityDecl
869      * @see org.xml.sax.DTDHandler#unparsedEntityDecl
870      */

871     public void externalEntityDecl(
872         String JavaDoc name,
873         String JavaDoc publicId,
874         String JavaDoc systemId)
875         throws SAXException JavaDoc
876     {
877     }
878
879     /**
880      * Tell if this character can be written without escaping.
881      */

882     protected boolean escapingNotNeeded(char ch)
883     {
884         if (ch < 127)
885         {
886             if (ch >= 0x20 || (0x0A == ch || 0x0D == ch || 0x09 == ch))
887                 return true;
888             else
889                 return false;
890         }
891
892         if (null == m_charToByteConverter && false == m_triedToGetConverter)
893         {
894             m_triedToGetConverter = true;
895             try
896             {
897                 m_charToByteConverter =
898                     Encodings.getCharToByteConverter(getEncoding());
899                 if (null != m_charToByteConverter)
900