KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > serializers > XMLSerializer


1 /*
2  * Copyright 1999-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 package org.apache.cocoon.components.serializers;
17
18 import java.io.CharArrayWriter JavaDoc;
19
20 import org.apache.cocoon.components.serializers.encoding.XMLEncoder;
21 import org.apache.cocoon.components.serializers.util.DocType;
22 import org.apache.cocoon.components.serializers.util.Namespaces;
23 import org.apache.commons.lang.SystemUtils;
24 import org.xml.sax.SAXException JavaDoc;
25
26 /**
27  *
28  * @author <a HREF="mailto:pier@apache.org">Pier Fumagalli</a>, February 2003
29  * @version CVS $Id: XMLSerializer.java 123623 2004-12-29 10:50:49Z antonio $
30  */

31 public class XMLSerializer extends EncodingSerializer {
32
33     private static final XMLEncoder XML_ENCODER = new XMLEncoder();
34
35     private static final char S_EOL[] = SystemUtils.LINE_SEPARATOR.toCharArray();
36
37     private static final char S_DOCUMENT_1[] = "<?xml version=\"1.0".toCharArray();
38     private static final char S_DOCUMENT_2[] = "\" encoding=\"".toCharArray();
39     private static final char S_DOCUMENT_3[] = "\"?>".toCharArray();
40
41     private static final char S_ELEMENT_1[] = "=\"".toCharArray();
42     private static final char S_ELEMENT_2[] = "</".toCharArray();
43     private static final char S_ELEMENT_3[] = " />".toCharArray();
44     private static final char S_ELEMENT_4[] = " xmlns".toCharArray();
45
46     private static final char S_CDATA_1[] = "<[CDATA[".toCharArray();
47     private static final char S_CDATA_2[] = "]]>".toCharArray();
48
49     private static final char S_COMMENT_1[] = "<!--".toCharArray();
50     private static final char S_COMMENT_2[] = "-->".toCharArray();
51
52     private static final char S_PROCINSTR_1[] = "<?".toCharArray();
53     private static final char S_PROCINSTR_2[] = "?>".toCharArray();
54
55     private static final char C_LT = '<';
56     private static final char C_GT = '>';
57     private static final char C_SPACE = ' ';
58     private static final char C_QUOTE = '"';
59     private static final char C_NSSEP = ':';
60
61     private static final boolean DEBUG = false;
62
63     /* ====================================================================== */
64
65     /** Whether an element is left open like &quot;&lt;name &quot;. */
66     private boolean hanging_element = false;
67
68     /** True if we are processing the prolog. */
69     private boolean processing_prolog = true;
70
71     /** True if we are processing the DTD. */
72     private boolean processing_dtd = false;
73
74     /** A <code>Writer</code> for prolog elements. */
75     private PrologWriter prolog = new PrologWriter();
76
77     /* ====================================================================== */
78
79     /** The <code>DocType</code> instance representing the document. */
80     protected DocType doctype = null;
81
82     /* ====================================================================== */
83
84     /**
85      * Create a new instance of this <code>XMLSerializer</code>
86      */

87     public XMLSerializer() {
88         super(XML_ENCODER);
89     }
90
91     /**
92      * Create a new instance of this <code>XMLSerializer</code>
93      */

94     protected XMLSerializer(XMLEncoder encoder) {
95         super(encoder);
96     }
97     
98     /**
99      * Reset this <code>XMLSerializer</code>.
100      */

101     public void recycle() {
102         super.recycle();
103         this.doctype = null;
104         this.hanging_element = false;
105         this.processing_prolog = true;
106         this.processing_dtd = false;
107         if (this.prolog != null) this.prolog.reset();
108     }
109
110     /**
111      * Return the MIME Content-Type produced by this serializer.
112      */

113     public String JavaDoc getMimeType() {
114         if (this.charset == null) return("text/xml");
115         return("text/xml; charset=" + this.charset.getName());
116     }
117
118     /* ====================================================================== */
119
120     /**
121      * Receive notification of the beginning of a document.
122      */

123     public void startDocument()
124     throws SAXException JavaDoc {
125         super.startDocument();
126         this.head();
127     }
128
129     /**
130      * Receive notification of the end of a document.
131      */

132     public void endDocument()
133     throws SAXException JavaDoc {
134         this.writeln();
135         super.endDocument();
136     }
137
138     /**
139      * Write the XML document header.
140      * <p>
141      * This method will write out the <code>&lt;?xml version=&quot;1.0&quot
142      * ...&gt;</code> header.
143      * </p>
144      */

145     protected void head()
146     throws SAXException JavaDoc {
147         this.write(S_DOCUMENT_1); // [<?xml version="1.0]
148
if (this.charset != null) {
149             this.write(S_DOCUMENT_2); // [" encoding="]
150
this.write(this.charset.getName());
151         }
152         this.write(S_DOCUMENT_3); // ["?>]
153
this.writeln();
154     }
155
156     /**
157      * Report the start of DTD declarations, if any.
158      */

159     public void startDTD(String JavaDoc name, String JavaDoc public_id, String JavaDoc system_id)
160     throws SAXException JavaDoc {
161         this.processing_dtd = true;
162         this.doctype = new DocType(name, public_id, system_id);
163     }
164
165     /**
166      * Report the start of DTD declarations, if any.
167      */

168     public void endDTD()
169     throws SAXException JavaDoc {
170         this.processing_dtd = false;
171     }
172
173     /**
174      * Receive notification of the beginning of the document body.
175      *
176      * @param uri The namespace URI of the root element.
177      * @param local The local name of the root element.
178      * @param qual The fully-qualified name of the root element.
179      */

180     public void body(String JavaDoc uri, String JavaDoc local, String JavaDoc qual)
181     throws SAXException JavaDoc {
182         this.processing_prolog = false;
183         this.writeln();
184
185         /* We have a document type. */
186         if (this.doctype != null) {
187
188             String JavaDoc root_name = this.doctype.getName();
189             /* Check the DTD and the root element */
190             if (!root_name.equals(qual)) {
191                 throw new SAXException JavaDoc("Root element name \"" + root_name
192                         + "\" declared by document type declaration differs "
193                         + "from actual root element name \"" + qual + "\"");
194             }
195             /* Output the <!DOCTYPE ...> declaration. */
196             this.write(this.doctype.toString());
197         }
198
199         /* Output all PIs and comments we cached in the prolog */
200         this.prolog.writeTo(this);
201         this.writeln();
202     }
203
204     /**
205      * Receive notification of the beginning of an element.
206      *
207      * @param uri The namespace URI of the root element.
208      * @param local The local name of the root element.
209      * @param qual The fully-qualified name of the root element.
210      * @param namespaces An array of <code>String</code> objects containing
211      * the namespaces to be declared by this element.
212      * @param attributes An array of <code>String</code> objects containing
213      * all attributes of this element.
214      */

215     public void startElementImpl(String JavaDoc uri, String JavaDoc local, String JavaDoc qual,
216                                  String JavaDoc namespaces[][], String JavaDoc attributes[][])
217     throws SAXException JavaDoc {
218         this.closeElement(false);
219         this.write(C_LT); // [<]
220
if (DEBUG) {
221             this.write('[');
222             this.write(uri);
223             this.write(']');
224         }
225         this.write(qual);
226
227         for (int x = 0; x < namespaces.length; x++) {
228             this.write(S_ELEMENT_4); // [ xmlns]
229
if (namespaces[x][Namespaces.NAMESPACE_PREFIX].length() > 0) {
230                 this.write(C_NSSEP); // [:]
231
this.write(namespaces[x][Namespaces.NAMESPACE_PREFIX]);
232             }
233             this.write(S_ELEMENT_1); // [="]
234
this.encode(namespaces[x][Namespaces.NAMESPACE_URI]);
235             this.write(C_QUOTE); // ["]
236
}
237
238         for (int x = 0; x < attributes.length; x++) {
239             this.write(C_SPACE); // [ ]
240
if (DEBUG) {
241                 this.write('[');
242                 this.write(attributes[x][ATTRIBUTE_NSURI]);
243                 this.write(']');
244             }
245             this.write(attributes[x][ATTRIBUTE_QNAME]);
246             this.write(S_ELEMENT_1); // [="]
247
this.encode(attributes[x][ATTRIBUTE_VALUE]);
248             this.write(C_QUOTE); // ["]
249
}
250
251         this.hanging_element = true;
252     }
253
254     /**
255      * Receive notification of the end of an element.
256      *
257      * @param uri The namespace URI of the root element.
258      * @param local The local name of the root element.
259      * @param qual The fully-qualified name of the root element.
260      */

261     public void endElementImpl(String JavaDoc uri, String JavaDoc local, String JavaDoc qual)
262     throws SAXException JavaDoc {
263         if (closeElement(true)) return;
264         this.write(S_ELEMENT_2); // [</]
265
if (DEBUG) {
266             this.write('[');
267             this.write(uri);
268             this.write(']');
269         }
270         this.write(qual);
271         this.write(C_GT); // [>]
272
}
273
274     /**
275      * Write the end part of a start element (if necessary).
276      *
277      * @param end_element Whether this method was called because an element
278      * is being closed or not.
279      * @return <b>true</b> if this call successfully closed the element (and
280      * no further <code>&lt;/element&gt;</code> is required.
281      */

282     protected boolean closeElement(boolean end_element)
283     throws SAXException JavaDoc {
284         if (!hanging_element) return(false);
285         if (end_element) this.write(S_ELEMENT_3); // [ />]
286
else this.write(C_GT); // [>]
287
this.hanging_element = false;
288         return(true);
289     }
290
291     /**
292      * Report the start of a CDATA section.
293      */

294     public void startCDATA()
295     throws SAXException JavaDoc {
296         if (this.processing_prolog) return;
297         this.closeElement(false);
298         this.write(S_CDATA_1); // [<[CDATA[]
299
}
300
301     /**
302      * Report the end of a CDATA section.
303      */

304     public void endCDATA()
305     throws SAXException JavaDoc {
306         if (this.processing_prolog) return;
307         this.closeElement(false);
308         this.write(S_CDATA_2); // []]>]
309
}
310
311     /**
312      * Receive notification of character data.
313      */

314     public void charactersImpl(char data[], int start, int length)
315     throws SAXException JavaDoc {
316         if (this.processing_prolog) return;
317         this.closeElement(false);
318         this.encode(data, start, length);
319     }
320
321     /**
322      * Receive notification of ignorable whitespace in element content.
323      */

324     public void ignorableWhitespace(char data[], int start, int length)
325     throws SAXException JavaDoc {
326         this.charactersImpl(data, start, length);
327     }
328
329     /**
330      * Report an XML comment anywhere in the document.
331      */

332     public void comment(char data[], int start, int length)
333     throws SAXException JavaDoc {
334         if (this.processing_dtd) return;
335
336         if (this.processing_prolog) {
337             this.prolog.write(S_COMMENT_1); // [<!--]
338
this.prolog.write(data, start, length);
339             this.prolog.write(S_COMMENT_2); // [-->]
340
this.prolog.write(S_EOL);
341             return;
342         }
343
344         this.closeElement(false);
345         this.write(S_COMMENT_1); // [<!--]
346
this.write(data, start, length);
347         this.write(S_COMMENT_2); // [-->]
348
}
349
350     /**
351      * Receive notification of a processing instruction.
352      */

353     public void processingInstruction(String JavaDoc target, String JavaDoc data)
354     throws SAXException JavaDoc {
355         if (this.processing_dtd) return;
356
357         if (this.processing_prolog) {
358             this.prolog.write(S_PROCINSTR_1); // [<?]
359
this.prolog.write(target);
360             if (data != null) {
361                 this.prolog.write(C_SPACE); // [ ]
362
this.prolog.write(data);
363             }
364             this.prolog.write(S_PROCINSTR_2); // [?>]
365
this.prolog.write(S_EOL);
366             return;
367         }
368
369         this.closeElement(false);
370
371         this.write(S_PROCINSTR_1); // [<?]
372
this.write(target);
373         if (data != null) {
374             this.write(C_SPACE); // [ ]
375
this.write(data);
376         }
377         this.write(S_PROCINSTR_2); // [?>]
378
}
379
380     /**
381      * Report the beginning of some internal and external XML entities.
382      */

383     public void startEntity(String JavaDoc name)
384     throws SAXException JavaDoc {
385     }
386
387     /**
388      * Report the end of an entity.
389      */

390     public void endEntity(String JavaDoc name)
391     throws SAXException JavaDoc {
392     }
393
394     /**
395      * Receive notification of a skipped entity.
396      */

397     public void skippedEntity(String JavaDoc name)
398     throws SAXException JavaDoc {
399     }
400
401     /* ====================================================================== */
402
403     /**
404      * The <code>PrologWriter</code> is a simple extension to a
405      * <code>CharArrayWriter</code>.
406      */

407     private static final class PrologWriter extends CharArrayWriter JavaDoc {
408
409         /** Create a new <code>PrologWriter</code> instance. */
410         private PrologWriter() {
411             super();
412         }
413
414         /**
415          * Write an array of characters.
416          * <p>
417          * The <code>CharArrayWriter</code> implementation of this method
418          * throws an unwanted <code>IOException</code>.
419          * </p>
420          */

421         public void write(char c[]) {
422             this.write(c, 0, c.length);
423         }
424
425         /**
426          * Write a <code>String</code>.
427          * <p>
428          * The <code>CharArrayWriter</code> implementation of this method
429          * throws an unwanted <code>IOException</code>.
430          * </p>
431          */

432         public void write(String JavaDoc str) {
433             this.write(str, 0, str.length());
434         }
435
436         /**
437          * Write our contents to a <code>BaseSerializer</code> without
438          * copying the buffer.
439          */

440         public void writeTo(XMLSerializer serializer)
441         throws SAXException JavaDoc {
442             serializer.write(this.buf, 0, this.count);
443         }
444     }
445 }
446
Popular Tags