KickJava   Java API By Example, From Geeks To Geeks.

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


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: ToXMLStream.java,v 1.13 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
23 import javax.xml.transform.ErrorListener JavaDoc;
24 import javax.xml.transform.Result JavaDoc;
25 import javax.xml.transform.Transformer JavaDoc;
26 import javax.xml.transform.TransformerException JavaDoc;
27
28 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
29 import com.sun.org.apache.xml.internal.res.XMLMessages;
30 import org.xml.sax.SAXException JavaDoc;
31
32 /**
33  * @author Santiago Pericas-Geertsen
34  * @author G. Todd Miller
35  */

36 public class ToXMLStream extends ToStream
37 {
38
39     /**
40      * remembers if we need to write out "]]>" to close the CDATA
41      */

42     boolean m_cdataTagOpen = false;
43
44
45     /**
46      * Map that tells which XML characters should have special treatment, and it
47      * provides character to entity name lookup.
48      */

49     protected static CharInfo m_xmlcharInfo =
50 // new CharInfo(CharInfo.XML_ENTITIES_RESOURCE);
51
CharInfo.getCharInfo(CharInfo.XML_ENTITIES_RESOURCE, Method.XML);
52
53     /**
54      * Default constructor.
55      */

56     public ToXMLStream()
57     {
58         m_charInfo = m_xmlcharInfo;
59
60         initCDATA();
61         // initialize namespaces
62
m_prefixMap = new NamespaceMappings();
63
64     }
65
66     /**
67      * Copy properties from another SerializerToXML.
68      *
69      * @param xmlListener non-null reference to a SerializerToXML object.
70      */

71     public void CopyFrom(ToXMLStream xmlListener)
72     {
73
74         m_writer = xmlListener.m_writer;
75
76
77         // m_outputStream = xmlListener.m_outputStream;
78
String JavaDoc encoding = xmlListener.getEncoding();
79         setEncoding(encoding);
80
81         setOmitXMLDeclaration(xmlListener.getOmitXMLDeclaration());
82
83         m_ispreserve = xmlListener.m_ispreserve;
84         m_preserves = xmlListener.m_preserves;
85         m_isprevtext = xmlListener.m_isprevtext;
86         m_doIndent = xmlListener.m_doIndent;
87         setIndentAmount(xmlListener.getIndentAmount());
88         m_startNewLine = xmlListener.m_startNewLine;
89         m_needToOutputDocTypeDecl = xmlListener.m_needToOutputDocTypeDecl;
90         setDoctypeSystem(xmlListener.getDoctypeSystem());
91         setDoctypePublic(xmlListener.getDoctypePublic());
92         setStandalone(xmlListener.getStandalone());
93         setMediaType(xmlListener.getMediaType());
94         m_maxCharacter = xmlListener.m_maxCharacter;
95         m_spaceBeforeClose = xmlListener.m_spaceBeforeClose;
96         m_cdataStartCalled = xmlListener.m_cdataStartCalled;
97
98     }
99
100     /**
101      * Receive notification of the beginning of a document.
102      *
103      * @throws org.xml.sax.SAXException Any SAX exception, possibly
104      * wrapping another exception.
105      *
106      * @throws org.xml.sax.SAXException
107      */

108     public void startDocumentInternal() throws org.xml.sax.SAXException JavaDoc
109     {
110
111         if (m_needToCallStartDocument)
112         {
113             super.startDocumentInternal();
114             m_needToCallStartDocument = false;
115
116             if (m_inEntityRef)
117                 return;
118
119             m_needToOutputDocTypeDecl = true;
120             m_startNewLine = false;
121
122             if (getOmitXMLDeclaration() == false)
123             {
124                 String JavaDoc encoding = Encodings.getMimeEncoding(getEncoding());
125                 String JavaDoc version = getVersion();
126                 if (version == null)
127                     version = "1.0";
128                 String JavaDoc standalone;
129
130                 if (m_standaloneWasSpecified)
131                 {
132                     standalone = " standalone=\"" + getStandalone() + "\"";
133                 }
134                 else
135                 {
136                     standalone = "";
137                 }
138
139                 try
140                 {
141                     final java.io.Writer JavaDoc writer = m_writer;
142                     writer.write("<?xml version=\"");
143                     writer.write(version);
144                     writer.write("\" encoding=\"");
145                     writer.write(encoding);
146                     writer.write('\"');
147                     writer.write(standalone);
148                     writer.write("?>");
149                     if (m_doIndent)
150                         writer.write(m_lineSep, 0, m_lineSepLen);
151                 }
152                 catch(IOException JavaDoc e)
153                 {
154                     throw new SAXException JavaDoc(e);
155                 }
156
157             }
158         }
159     }
160
161     /**
162      * Receive notification of the end of a document.
163      *
164      * @throws org.xml.sax.SAXException Any SAX exception, possibly
165      * wrapping another exception.
166      *
167      * @throws org.xml.sax.SAXException
168      */

169     public void endDocument() throws org.xml.sax.SAXException JavaDoc
170     {
171         flushPending();
172         if (m_doIndent && !m_isprevtext)
173         {
174             try
175             {
176             outputLineSep();
177             }
178             catch(IOException JavaDoc e)
179             {
180                 throw new SAXException JavaDoc(e);
181             }
182         }
183
184         flushWriter();
185         
186         if (m_tracer != null)
187             super.fireEndDoc();
188     }
189
190     /**
191      * Starts a whitespace preserving section. All characters printed
192      * within a preserving section are printed without indentation and
193      * without consolidating multiple spaces. This is equivalent to
194      * the <tt>xml:space=&quot;preserve&quot;</tt> attribute. Only XML
195      * and HTML serializers need to support this method.
196      * <p>
197      * The contents of the whitespace preserving section will be delivered
198      * through the regular <tt>characters</tt> event.
199      *
200      * @throws org.xml.sax.SAXException
201      */

202     public void startPreserving() throws org.xml.sax.SAXException JavaDoc
203     {
204
205         // Not sure this is really what we want. -sb
206
m_preserves.push(true);
207
208         m_ispreserve = true;
209     }
210
211     /**
212      * Ends a whitespace preserving section.
213      *
214      * @see #startPreserving
215      *
216      * @throws org.xml.sax.SAXException
217      */

218     public void endPreserving() throws org.xml.sax.SAXException JavaDoc
219     {
220
221         // Not sure this is really what we want. -sb
222
m_ispreserve = m_preserves.isEmpty() ? false : m_preserves.pop();
223     }
224
225     /**
226      * Receive notification of a processing instruction.
227      *
228      * @param target The processing instruction target.
229      * @param data The processing instruction data, or null if
230      * none was supplied.
231      * @throws org.xml.sax.SAXException Any SAX exception, possibly
232      * wrapping another exception.
233      *
234      * @throws org.xml.sax.SAXException
235      */

236     public void processingInstruction(String JavaDoc target, String JavaDoc data)
237         throws org.xml.sax.SAXException JavaDoc
238     {
239         if (m_inEntityRef)
240             return;
241         
242         flushPending();
243
244         if (target.equals(Result.PI_DISABLE_OUTPUT_ESCAPING))
245         {
246             startNonEscaping();
247         }
248         else if (target.equals(Result.PI_ENABLE_OUTPUT_ESCAPING))
249         {
250             endNonEscaping();
251         }
252         else
253         {
254             try
255             {
256                 if (m_elemContext.m_startTagOpen)
257                 {
258                     closeStartTag();
259                     m_elemContext.m_startTagOpen = false;
260                 }
261
262                 if (shouldIndent())
263                     indent();
264
265                 final java.io.Writer JavaDoc writer = m_writer;
266                 writer.write("<?");
267                 writer.write(target);
268
269                 if (data.length() > 0
270                     && !Character.isSpaceChar(data.charAt(0)))
271                     writer.write(' ');
272
273                 int indexOfQLT = data.indexOf("?>");
274
275                 if (indexOfQLT >= 0)
276                 {
277
278                     // See XSLT spec on error recovery of "?>" in PIs.
279
if (indexOfQLT > 0)
280                     {
281                         writer.write(data.substring(0, indexOfQLT));
282                     }
283
284                     writer.write("? >"); // add space between.
285

286                     if ((indexOfQLT + 2) < data.length())
287                     {
288                         writer.write(data.substring(indexOfQLT + 2));
289                     }
290                 }
291                 else
292                 {
293                     writer.write(data);
294                 }
295
296                 writer.write('?');
297                 writer.write('>');
298
299                 // Always output a newline char if not inside of an
300
// element. The whitespace is not significant in that
301
// case.
302
if (m_elemContext.m_currentElemDepth <= 0)
303                     writer.write(m_lineSep, 0, m_lineSepLen);
304
305                 m_startNewLine = true;
306             }
307             catch(IOException JavaDoc e)
308             {
309                 throw new SAXException JavaDoc(e);
310             }
311         }
312         
313         if (m_tracer != null)
314             super.fireEscapingEvent(target, data);
315     }
316
317     /**
318      * Receive notivication of a entityReference.
319      *
320      * @param name The name of the entity.
321      *
322      * @throws org.xml.sax.SAXException
323      */

324     public void entityReference(String JavaDoc name) throws org.xml.sax.SAXException JavaDoc
325     {
326         if (m_elemContext.m_startTagOpen)
327         {
328             closeStartTag();
329             m_elemContext.m_startTagOpen = false;
330         }
331
332         try
333         {
334             if (shouldIndent())
335                 indent();
336
337             final java.io.Writer JavaDoc writer = m_writer;
338             writer.write('&');
339             writer.write(name);
340             writer.write(';');
341         }
342         catch(IOException JavaDoc e)
343         {
344             throw new SAXException JavaDoc(e);
345         }
346         
347         if (m_tracer != null)
348             super.fireEntityReference(name);
349     }
350
351     /**
352      * This method is used to add an attribute to the currently open element.
353      * The caller has guaranted that this attribute is unique, which means that it
354      * not been seen before and will not be seen again.
355      *
356      * @param name the qualified name of the attribute
357      * @param value the value of the attribute which can contain only
358      * ASCII printable characters characters in the range 32 to 127 inclusive.
359      * @param flags the bit values of this integer give optimization information.
360      */

361     public void addUniqueAttribute(String JavaDoc name, String JavaDoc value, int flags)
362         throws SAXException JavaDoc
363     {
364         if (m_elemContext.m_startTagOpen)
365         {
366            
367             try
368             {
369                 final String JavaDoc patchedName = patchName(name);
370                 final java.io.Writer JavaDoc writer = m_writer;
371                 if ((flags & NO_BAD_CHARS) > 0 && m_xmlcharInfo.onlyQuotAmpLtGt)
372                 {
373                     // "flags" has indicated that the characters
374
// '>' '<' '&' and '"' are not in the value and
375
// m_htmlcharInfo has recorded that there are no other
376
// entities in the range 32 to 127 so we write out the
377
// value directly
378

379                     writer.write(' ');
380                     writer.write(patchedName);
381                     writer.write("=\"");
382                     writer.write(value);
383                     writer.write('"');
384                 }
385                 else
386                 {
387                     writer.write(' ');
388                     writer.write(patchedName);
389                     writer.write("=\"");
390                     writeAttrString(writer, value, this.getEncoding());
391                     writer.write('"');
392                 }
393             } catch (IOException JavaDoc e) {
394                 throw new SAXException JavaDoc(e);
395             }
396         }
397     }
398
399     public void addAttribute(
400         String JavaDoc uri,
401         String JavaDoc localName,
402         String JavaDoc rawName,
403         String JavaDoc type,
404         String JavaDoc value)
405         throws SAXException JavaDoc
406     {
407         if (m_elemContext.m_startTagOpen)
408         {
409             if (!rawName.startsWith("xmlns"))
410             {
411                 String JavaDoc prefixUsed =
412                     ensureAttributesNamespaceIsDeclared(
413                         uri,
414                         localName,
415                         rawName);
416                 if (prefixUsed != null
417                     && rawName != null
418                     && !rawName.startsWith(prefixUsed))
419                 {
420                     // use a different raw name, with the prefix used in the
421
// generated namespace declaration
422
rawName = prefixUsed + ":" + localName;
423
424                 }
425             }
426             addAttributeAlways(uri, localName, rawName, type, value);
427         }
428         else
429         {
430             /*
431              * The startTag is closed, yet we are adding an attribute?
432              *
433              * Section: 7.1.3 Creating Attributes Adding an attribute to an
434              * element after a PI (for example) has been added to it is an
435              * error. The attributes can be ignored. The spec doesn't explicitly
436              * say this is disallowed, as it does for child elements, but it
437              * makes sense to have the same treatment.
438              *
439              * We choose to ignore the attribute which is added too late.
440              */

441             // Generate a warning of the ignored attributes
442

443             // Create the warning message
444
String JavaDoc msg = XMLMessages.createXMLMessage(
445                     XMLErrorResources.ER_ILLEGAL_ATTRIBUTE_POSITION,new Object JavaDoc[]{ localName });
446
447             try {
448                 // Prepare to issue the warning message
449
Transformer JavaDoc tran = super.getTransformer();
450                 ErrorListener JavaDoc errHandler = tran.getErrorListener();
451
452
453                 // Issue the warning message
454
if (null != errHandler && m_sourceLocator != null)
455                   errHandler.warning(new TransformerException JavaDoc(msg, m_sourceLocator));
456                 else
457                   System.out.println(msg);
458                 }
459             catch (Exception JavaDoc e){}
460         }
461     }
462
463     /**
464      * @see com.sun.org.apache.xml.internal.serializer.ExtendedContentHandler#endElement(String)
465      */

466     public void endElement(String JavaDoc elemName) throws SAXException JavaDoc
467     {
468         endElement(null, null, elemName);
469     }
470
471     /**
472      * From XSLTC
473      * Related to startPrefixMapping ???
474      */

475     public void namespaceAfterStartElement(
476         final String JavaDoc prefix,
477         final String JavaDoc uri)
478         throws SAXException JavaDoc
479     {
480
481         // hack for XSLTC with finding URI for default namespace
482
if (m_elemContext.m_elementURI == null)
483         {
484             String JavaDoc prefix1 = getPrefixPart(m_elemContext.m_elementName);
485             if (prefix1 == null && EMPTYSTRING.equals(prefix))
486             {
487                 // the elements URI is not known yet, and it
488
// doesn't have a prefix, and we are currently
489
// setting the uri for prefix "", so we have
490
// the uri for the element... lets remember it
491
m_elemContext.m_elementURI = uri;
492             }
493         }
494         startPrefixMapping(prefix,uri,false);
495         return;
496
497     }
498
499     /**
500      * From XSLTC
501      * Declare a prefix to point to a namespace URI. Inform SAX handler
502      * if this is a new prefix mapping.
503      */

504     protected boolean pushNamespace(String JavaDoc prefix, String JavaDoc uri)
505     {
506         try
507         {
508             if (m_prefixMap.pushNamespace(
509                 prefix, uri, m_elemContext.m_currentElemDepth))
510             {
511                 startPrefixMapping(prefix, uri);
512                 return true;
513             }
514         }
515         catch (SAXException JavaDoc e)
516         {
517             // falls through
518
}
519         return false;
520     }
521     /**
522      * Try's to reset the super class and reset this class for
523      * re-use, so that you don't need to create a new serializer
524      * (mostly for performance reasons).
525      *
526      * @return true if the class was successfuly reset.
527      */

528     public boolean reset()
529     {
530         boolean wasReset = false;
531         if (super.reset())
532         {
533             resetToXMLStream();
534             wasReset = true;
535         }
536         return wasReset;
537     }
538     
539     /**
540      * Reset all of the fields owned by ToStream class
541      *
542      */

543     private void resetToXMLStream()
544     {
545         this.m_cdataTagOpen = false;
546
547     }
548
549 }
550
Popular Tags