KickJava   Java API By Example, From Geeks To Geeks.

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


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: ToTextStream.java,v 1.15 2004/02/17 04:18:18 minchau Exp $
18  */

19 package com.sun.org.apache.xml.internal.serializer;
20
21 import java.io.IOException JavaDoc;
22
23 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
24 import com.sun.org.apache.xml.internal.res.XMLMessages;
25 import org.xml.sax.Attributes JavaDoc;
26 import org.xml.sax.SAXException JavaDoc;
27
28 /**
29  * @author Santiago Pericas-Geertsen
30  */

31 public class ToTextStream extends ToStream
32 {
33
34        
35   /**
36    * Default constructor.
37    */

38   public ToTextStream()
39   {
40     super();
41   }
42
43  
44  
45   /**
46    * Receive notification of the beginning of a document.
47    *
48    * <p>The SAX parser will invoke this method only once, before any
49    * other methods in this interface or in DTDHandler (except for
50    * setDocumentLocator).</p>
51    *
52    * @throws org.xml.sax.SAXException Any SAX exception, possibly
53    * wrapping another exception.
54    *
55    * @throws org.xml.sax.SAXException
56    */

57   protected void startDocumentInternal() throws org.xml.sax.SAXException JavaDoc
58   {
59     super.startDocumentInternal();
60
61     m_needToCallStartDocument = false;
62
63     // No action for the moment.
64
}
65
66   /**
67    * Receive notification of the end of a document.
68    *
69    * <p>The SAX parser will invoke this method only once, and it will
70    * be the last method invoked during the parse. The parser shall
71    * not invoke this method until it has either abandoned parsing
72    * (because of an unrecoverable error) or reached the end of
73    * input.</p>
74    *
75    * @throws org.xml.sax.SAXException Any SAX exception, possibly
76    * wrapping another exception.
77    *
78    * @throws org.xml.sax.SAXException
79    */

80   public void endDocument() throws org.xml.sax.SAXException JavaDoc
81   {
82     flushPending();
83     flushWriter();
84     if (m_tracer != null)
85         super.fireEndDoc();
86   }
87
88   /**
89    * Receive notification of the beginning of an element.
90    *
91    * <p>The Parser will invoke this method at the beginning of every
92    * element in the XML document; there will be a corresponding
93    * endElement() event for every startElement() event (even when the
94    * element is empty). All of the element's content will be
95    * reported, in order, before the corresponding endElement()
96    * event.</p>
97    *
98    * <p>If the element name has a namespace prefix, the prefix will
99    * still be attached. Note that the attribute list provided will
100    * contain only attributes with explicit values (specified or
101    * defaulted): #IMPLIED attributes will be omitted.</p>
102    *
103    *
104    * @param namespaceURI The Namespace URI, or the empty string if the
105    * element has no Namespace URI or if Namespace
106    * processing is not being performed.
107    * @param localName The local name (without prefix), or the
108    * empty string if Namespace processing is not being
109    * performed.
110    * @param name The qualified name (with prefix), or the
111    * empty string if qualified names are not available.
112    * @param atts The attributes attached to the element, if any.
113    * @throws org.xml.sax.SAXException Any SAX exception, possibly
114    * wrapping another exception.
115    * @see #endElement
116    * @see org.xml.sax.AttributeList
117    *
118    * @throws org.xml.sax.SAXException
119    */

120   public void startElement(
121           String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc name, Attributes JavaDoc atts)
122             throws org.xml.sax.SAXException JavaDoc
123   {
124     // time to fire off startElement event
125
if (m_tracer != null) {
126         super.fireStartElem(name);
127         this.firePseudoAttributes();
128     }
129     return;
130   }
131
132   /**
133    * Receive notification of the end of an element.
134    *
135    * <p>The SAX parser will invoke this method at the end of every
136    * element in the XML document; there will be a corresponding
137    * startElement() event for every endElement() event (even when the
138    * element is empty).</p>
139    *
140    * <p>If the element name has a namespace prefix, the prefix will
141    * still be attached to the name.</p>
142    *
143    *
144    * @param namespaceURI The Namespace URI, or the empty string if the
145    * element has no Namespace URI or if Namespace
146    * processing is not being performed.
147    * @param localName The local name (without prefix), or the
148    * empty string if Namespace processing is not being
149    * performed.
150    * @param name The qualified name (with prefix), or the
151    * empty string if qualified names are not available.
152    * @param name The element type name
153    * @throws org.xml.sax.SAXException Any SAX exception, possibly
154    * wrapping another exception.
155    *
156    * @throws org.xml.sax.SAXException
157    */

158   public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc name)
159           throws org.xml.sax.SAXException JavaDoc
160   {
161         if (m_tracer != null)
162             super.fireEndElem(name);
163   }
164
165   /**
166    * Receive notification of character data.
167    *
168    * <p>The Parser will call this method to report each chunk of
169    * character data. SAX parsers may return all contiguous character
170    * data in a single chunk, or they may split it into several
171    * chunks; however, all of the characters in any single event
172    * must come from the same external entity, so that the Locator
173    * provides useful information.</p>
174    *
175    * <p>The application must not attempt to read from the array
176    * outside of the specified range.</p>
177    *
178    * <p>Note that some parsers will report whitespace using the
179    * ignorableWhitespace() method rather than this one (validating
180    * parsers must do so).</p>
181    *
182    * @param ch The characters from the XML document.
183    * @param start The start position in the array.
184    * @param length The number of characters to read from the array.
185    * @throws org.xml.sax.SAXException Any SAX exception, possibly
186    * wrapping another exception.
187    * @see #ignorableWhitespace
188    * @see org.xml.sax.Locator
189    */

190   public void characters(char ch[], int start, int length)
191           throws org.xml.sax.SAXException JavaDoc
192   {
193
194     // this.accum(ch, start, length);
195
flushPending();
196     
197     try
198     {
199         writeNormalizedChars(ch, start, length, false, m_lineSepUse);
200         if (m_tracer != null)
201             super.fireCharEvent(ch, start, length);
202     }
203     catch(IOException JavaDoc ioe)
204     {
205       throw new SAXException JavaDoc(ioe);
206     }
207   }
208
209   /**
210    * If available, when the disable-output-escaping attribute is used,
211    * output raw text without escaping.
212    *
213    * @param ch The characters from the XML document.
214    * @param start The start position in the array.
215    * @param length The number of characters to read from the array.
216    *
217    * @throws org.xml.sax.SAXException Any SAX exception, possibly
218    * wrapping another exception.
219    */

220   public void charactersRaw(char ch[], int start, int length)
221           throws org.xml.sax.SAXException JavaDoc
222   {
223
224     try
225     {
226       writeNormalizedChars(ch, start, length, false, m_lineSepUse);
227     }
228     catch(IOException JavaDoc ioe)
229     {
230       throw new SAXException JavaDoc(ioe);
231     }
232   }
233   
234 /**
235  * Normalize the characters, but don't escape. Different from
236  * SerializerToXML#writeNormalizedChars because it does not attempt to do
237  * XML escaping at all.
238  *
239  * @param ch The characters from the XML document.
240  * @param start The start position in the array.
241  * @param length The number of characters to read from the array.
242  * @param isCData true if a CDATA block should be built around the characters.
243  * @param useLineSep true if the operating systems
244  * end-of-line separator should be output rather than a new-line character.
245  *
246  * @throws IOException
247  * @throws org.xml.sax.SAXException
248  */

249 void writeNormalizedChars(
250     final char ch[],
251     final int start,
252     final int length,
253     final boolean isCData,
254     final boolean useLineSep)
255     throws IOException JavaDoc, org.xml.sax.SAXException JavaDoc
256 {
257     final java.io.Writer JavaDoc writer = m_writer;
258     final int end = start + length;
259
260     /* copy a few "constants" before the loop for performance */
261     final char S_LINEFEED = CharInfo.S_LINEFEED;
262     final int M_MAXCHARACTER = this.m_maxCharacter;
263
264     if (isCData)
265     {
266         // This for() loop always increments i by one at the end
267
// of the loop. Additional increments of i adjust for when
268
// two input characters are processed.
269
for (int i = start; i < end; i++)
270         {
271             final char c = ch[i];
272
273             if (S_LINEFEED == c && useLineSep)
274             {
275                 writer.write(m_lineSep, 0, m_lineSepLen);
276             }
277             else if (c > M_MAXCHARACTER)
278             {
279                 if (i != 0)
280                     closeCDATA();
281
282                 // This needs to go into a function...
283
if (isUTF16Surrogate(c))
284                 {
285                     writeUTF16Surrogate(c, ch, i, end);
286                     i++; // two input characters processed
287
}
288                 else
289                 {
290                     writer.write(c);
291                 }
292
293                 if ((i != 0) && (i < (end - 1)))
294                 {
295                     writer.write(CDATA_DELIMITER_OPEN);
296                     m_cdataTagOpen = true;
297                 }
298             }
299             else if (
300                 ((i < (end - 2))
301                     && (']' == c)
302                     && (']' == ch[i + 1])
303                     && ('>' == ch[i + 2])))
304             {
305                 writer.write(CDATA_CONTINUE);
306                 i += 2;
307             }
308             else
309             {
310                 if (c <= M_MAXCHARACTER)
311                 {
312                     writer.write(c);
313                 }
314
315                 else if (isUTF16Surrogate(c))
316                 {
317                     writeUTF16Surrogate(c, ch, i, end);
318                     i++; // two input characters processed
319
}
320                 else
321                 {
322                     /* The character is greater than the allowed
323                      * maximum value and it is not part of a UTF-16
324                      * pair that would be put out as a character reference.
325                      */

326                     String JavaDoc encoding = getEncoding();
327                     if (encoding != null)
328                     {
329                         /* The output encoding is known,
330                          * so somthing is wrong.
331                          */

332                         String JavaDoc integralValue = Integer.toString(c);
333                         throw new SAXException JavaDoc(XMLMessages.createXMLMessage(
334                             XMLErrorResources.ER_ILLEGAL_CHARACTER,
335                             new Object JavaDoc[]{ integralValue, encoding}));
336                     }
337                     else
338                     {
339                         /* The output encoding is not known,
340                          * so just write it out as-is.
341                          */

342                         writer.write(c);
343                     }
344                 }
345             }
346         }
347     }
348     else
349     {
350         // not in CDATA section
351
for (int i = start; i < end; i++)
352         {
353             final char c = ch[i];
354
355             if (S_LINEFEED == c && useLineSep)
356             {
357                 writer.write(m_lineSep, 0, m_lineSepLen);
358             }
359             else if (c <= M_MAXCHARACTER)
360             {
361                 writer.write(c);
362             }
363             else if (isUTF16Surrogate(c))
364             {
365                 writeUTF16Surrogate(c, ch, i, end);
366                 i++; // two input characters processed
367
}
368             else
369             {
370                 /* The character is greater than the allowed
371                  * maximum value and it is not part of a UTF-16
372                  * pair that would be put out as a character reference.
373                  */

374                 String JavaDoc encoding = getEncoding();
375                 if (encoding != null)
376                 {
377                     /* The output encoding is known,
378                      * so somthing is wrong.
379                      */

380                     String JavaDoc integralValue = Integer.toString(c);
381                     throw new SAXException JavaDoc(XMLMessages.createXMLMessage(
382                         XMLErrorResources.ER_ILLEGAL_CHARACTER,
383                         new Object JavaDoc[]{ integralValue, encoding}));
384                 }
385                 else
386                 {
387                     /* The output encoding is not known,
388                      * so just write it out as-is.
389                      */

390                     writer.write(c);
391                 }
392             }
393         }
394     }
395 }
396
397   /**
398    * Receive notification of cdata.
399    *
400    * <p>The Parser will call this method to report each chunk of
401    * character data. SAX parsers may return all contiguous character
402    * data in a single chunk, or they may split it into several
403    * chunks; however, all of the characters in any single event
404    * must come from the same external entity, so that the Locator
405    * provides useful information.</p>
406    *
407    * <p>The application must not attempt to read from the array
408    * outside of the specified range.</p>
409    *
410    * <p>Note that some parsers will report whitespace using the
411    * ignorableWhitespace() method rather than this one (validating
412    * parsers must do so).</p>
413    *
414    * @param ch The characters from the XML document.
415    * @param start The start position in the array.
416    * @param length The number of characters to read from the array.
417    * @throws org.xml.sax.SAXException Any SAX exception, possibly
418    * wrapping another exception.
419    * @see #ignorableWhitespace
420    * @see org.xml.sax.Locator
421    */

422   public void cdata(char ch[], int start, int length)
423           throws org.xml.sax.SAXException JavaDoc
424   {
425     try
426     {
427         writeNormalizedChars(ch, start, length, false, m_lineSepUse);
428         if (m_tracer != null)
429             super.fireCDATAEvent(ch, start, length);
430     }
431     catch(IOException JavaDoc ioe)
432     {
433       throw new SAXException JavaDoc(ioe);
434     }
435   }
436
437   /**
438    * Receive notification of ignorable whitespace in element content.
439    *
440    * <p>Validating Parsers must use this method to report each chunk
441    * of ignorable whitespace (see the W3C XML 1.0 recommendation,
442    * section 2.10): non-validating parsers may also use this method
443    * if they are capable of parsing and using content models.</p>
444    *
445    * <p>SAX parsers may return all contiguous whitespace in a single
446    * chunk, or they may split it into several chunks; however, all of
447    * the characters in any single event must come from the same
448    * external entity, so that the Locator provides useful
449    * information.</p>
450    *
451    * <p>The application must not attempt to read from the array
452    * outside of the specified range.</p>
453    *
454    * @param ch The characters from the XML document.
455    * @param start The start position in the array.
456    * @param length The number of characters to read from the array.
457    * @throws org.xml.sax.SAXException Any SAX exception, possibly
458    * wrapping another exception.
459    * @see #characters
460    *
461    * @throws org.xml.sax.SAXException
462    */

463   public void ignorableWhitespace(char ch[], int start, int length)
464           throws org.xml.sax.SAXException JavaDoc
465   {
466
467     try
468     {
469       writeNormalizedChars(ch, start, length, false, m_lineSepUse);
470     }
471     catch(IOException JavaDoc ioe)
472     {
473       throw new SAXException JavaDoc(ioe);
474     }
475   }
476
477   /**
478    * Receive notification of a processing instruction.
479    *
480    * <p>The Parser will invoke this method once for each processing
481    * instruction found: note that processing instructions may occur
482    * before or after the main document element.</p>
483    *
484    * <p>A SAX parser should never report an XML declaration (XML 1.0,
485    * section 2.8) or a text declaration (XML 1.0, section 4.3.1)
486    * using this method.</p>
487    *
488    * @param target The processing instruction target.
489    * @param data The processing instruction data, or null if
490    * none was supplied.
491    * @throws org.xml.sax.SAXException Any SAX exception, possibly
492    * wrapping another exception.
493    *
494    * @throws org.xml.sax.SAXException
495    */

496   public void processingInstruction(String JavaDoc target, String JavaDoc data)
497           throws org.xml.sax.SAXException JavaDoc
498   {
499     // flush anything pending first
500
flushPending();
501     
502     if (m_tracer != null)
503         super.fireEscapingEvent(target, data);
504   }
505
506   /**
507    * Called when a Comment is to be constructed.
508    * Note that Xalan will normally invoke the other version of this method.
509    * %REVIEW% In fact, is this one ever needed, or was it a mistake?
510    *
511    * @param data The comment data.
512    * @throws org.xml.sax.SAXException Any SAX exception, possibly
513    * wrapping another exception.
514    */

515   public void comment(String JavaDoc data) throws org.xml.sax.SAXException JavaDoc
516   {
517       final int length = data.length();
518       if (length > m_charsBuff.length)
519       {
520           m_charsBuff = new char[length*2 + 1];
521       }
522       data.getChars(0, length, m_charsBuff, 0);
523       comment(m_charsBuff, 0, length);
524   }
525
526   /**
527    * Report an XML comment anywhere in the document.
528    *
529    * This callback will be used for comments inside or outside the
530    * document element, including comments in the external DTD
531    * subset (if read).
532    *
533    * @param ch An array holding the characters in the comment.
534    * @param start The starting position in the array.
535    * @param length The number of characters to use from the array.
536    * @throws org.xml.sax.SAXException The application may raise an exception.
537    */

538   public void comment(char ch[], int start, int length)
539           throws org.xml.sax.SAXException JavaDoc
540   {
541
542     flushPending();
543     if (m_tracer != null)
544         super.fireCommentEvent(ch, start, length);
545   }
546
547   /**
548    * Receive notivication of a entityReference.
549    *
550    * @param name non-null reference to the name of the entity.
551    *
552    * @throws org.xml.sax.SAXException
553    */

554   public void entityReference(String JavaDoc name) throws org.xml.sax.SAXException JavaDoc
555   {
556         if (m_tracer != null)
557             super.fireEntityReference(name);
558   }
559   
560     /**
561      * @see com.sun.org.apache.xml.internal.serializer.ExtendedContentHandler#addAttribute(String, String, String, String, String)
562      */

563     public void addAttribute(
564         String JavaDoc uri,
565         String JavaDoc localName,
566         String JavaDoc rawName,
567         String JavaDoc type,
568         String JavaDoc value)
569     {
570         // do nothing, just forget all about the attribute
571
}
572  
573     /**
574      * @see org.xml.sax.ext.LexicalHandler#endCDATA()
575      */

576     public void endCDATA() throws SAXException JavaDoc
577     {
578         // do nothing
579
}
580
581     /**
582      * @see com.sun.org.apache.xml.internal.serializer.ExtendedContentHandler#endElement(String)
583      */

584     public void endElement(String JavaDoc elemName) throws SAXException JavaDoc
585     {
586         if (m_tracer != null)
587             super.fireEndElem(elemName);
588     }
589  
590     /**
591      * From XSLTC
592      */

593     public void startElement(
594     String JavaDoc elementNamespaceURI,
595     String JavaDoc elementLocalName,
596     String JavaDoc elementName)
597     throws SAXException JavaDoc
598     {
599         if (m_needToCallStartDocument)
600             startDocumentInternal();
601         // time to fire off startlement event.
602
if (m_tracer != null) {
603             super.fireStartElem(elementName);
604             this.firePseudoAttributes();
605         }
606         
607         return;
608     }
609
610
611     /**
612      * From XSLTC
613      */

614     public void characters(String JavaDoc characters)
615     throws SAXException JavaDoc
616     {
617         final int length = characters.length();
618         if (length > m_charsBuff.length)
619         {
620             m_charsBuff = new char[length*2 + 1];
621         }
622         characters.getChars(0, length, m_charsBuff, 0);
623         characters(m_charsBuff, 0, length);
624     }
625
626
627     /**
628      * From XSLTC
629      */

630     public void addAttribute(String JavaDoc name, String JavaDoc value)
631     {
632         // do nothing, forget about the attribute
633
}
634     
635     /**
636      * Add a unique attribute
637      */

638     public void addUniqueAttribute(String JavaDoc qName, String JavaDoc value, int flags)
639         throws SAXException JavaDoc
640     {
641         // do nothing, forget about the attribute
642
}
643
644     public boolean startPrefixMapping(
645         String JavaDoc prefix,
646         String JavaDoc uri,
647         boolean shouldFlush)
648         throws SAXException JavaDoc
649     {
650         // no namespace support for HTML
651
return false;
652     }
653
654
655     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
656         throws org.xml.sax.SAXException JavaDoc
657     {
658         // no namespace support for HTML
659
}
660
661
662     public void namespaceAfterStartElement(
663         final String JavaDoc prefix,
664         final String JavaDoc uri)
665         throws SAXException JavaDoc
666     {
667         // no namespace support for HTML
668
}
669
670     public void flushPending() throws org.xml.sax.SAXException JavaDoc
671     {
672             if (m_needToCallStartDocument)
673             {
674                 startDocumentInternal();
675                 m_needToCallStartDocument = false;
676             }
677     }
678 }
679
Popular Tags