KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > util > CmsXmlSaxWriter


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/util/CmsXmlSaxWriter.java,v $
3  * Date : $Date: 2006/03/27 14:52:41 $
4  * Version: $Revision: 1.13 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.util;
33
34 import org.opencms.i18n.CmsEncoder;
35 import org.opencms.main.OpenCms;
36
37 import java.io.IOException JavaDoc;
38 import java.io.StringWriter JavaDoc;
39 import java.io.Writer JavaDoc;
40
41 import org.xml.sax.Attributes JavaDoc;
42 import org.xml.sax.SAXException JavaDoc;
43 import org.xml.sax.ext.LexicalHandler JavaDoc;
44 import org.xml.sax.helpers.DefaultHandler JavaDoc;
45
46 /**
47  * Simple SAX event handler that generates a XML (or HTML) file from the events caught.<p>
48  *
49  * This can be used for writing large XML files where keeping a DOM structure
50  * in memory might cause out-of-memory issues, like e.g. when writing the
51  * OpenCms export files.<p>
52  *
53  * It can also be used if a <code>{@link org.xml.sax.ContentHandler}</code> is needed that should
54  * generate a XML / HTML file from a series of SAX events.<p>
55  *
56  * @author Alexander Kandzior
57  *
58  * @version $Revision: 1.13 $
59  *
60  * @since 6.0.0
61  */

62 public class CmsXmlSaxWriter extends DefaultHandler JavaDoc implements LexicalHandler JavaDoc {
63
64     /** The indentation to use. */
65     private static final String JavaDoc INDENT_STR = "\t";
66
67     /** The file encoding to use. */
68     private String JavaDoc m_encoding;
69
70     /**
71      * Indicates if characters that are not part of the selected encoding
72      * are to be replaced with the XML <code>&amp;#123;</code> entity representation
73      * in the generated output (not in CDATA elements).
74      */

75     private boolean m_escapeUnknownChars;
76
77     /** Indicates if XML entities are to be encoded in the generated output (not in CDATA elements). */
78     private boolean m_escapeXml;
79
80     /** The indentation level. */
81     private int m_indentLevel;
82
83     /** Indicates if a CDATA node is still open. */
84     private boolean m_isCdata;
85
86     /** The last element name written to the output. */
87     private String JavaDoc m_lastElementName;
88
89     /** Indicates if a CDATA node needs to be opened. */
90     private boolean m_openCdata;
91
92     /** Indicates if an element tag is still open. */
93     private boolean m_openElement;
94
95     /** The Writer to write the output to. */
96     private Writer JavaDoc m_writer;
97
98     /**
99      * Creates a SAX event handler that generates XML / HTML Strings from the events caught
100      * using a new <code>{@link StringWriter}</code> and the OpenCms default encoding.<p>
101      */

102     public CmsXmlSaxWriter() {
103
104         this(new StringWriter JavaDoc(), OpenCms.getSystemInfo().getDefaultEncoding());
105     }
106
107     /**
108      * Creates a SAX event handler that generates XML / HTML Strings from the events caught
109      * using a new <code>{@link StringWriter}</code> and the given encoding.<p>
110      *
111      * @param encoding the encoding for the XML file
112      */

113     public CmsXmlSaxWriter(String JavaDoc encoding) {
114
115         this(new StringWriter JavaDoc(), encoding);
116     }
117
118     /**
119      * Creates a SAX event handler that generates XML / HTML Strings from the events caught
120      * using a new <code>{@link StringWriter}</code> and the given encoding.<p>
121      *
122      * @param writer the Writer to write to output to
123      */

124     public CmsXmlSaxWriter(Writer JavaDoc writer) {
125
126         this(writer, OpenCms.getSystemInfo().getDefaultEncoding());
127     }
128
129     /**
130      * A SAX event handler that generates XML / HTML Strings from the events caught and writes them
131      * to the given Writer.<p>
132      *
133      * @param writer the Writer to write to output to
134      * @param encoding the encoding for the XML file
135      */

136     public CmsXmlSaxWriter(Writer JavaDoc writer, String JavaDoc encoding) {
137
138         m_writer = writer;
139         m_encoding = encoding;
140         m_indentLevel = 0;
141         m_escapeXml = true;
142         m_escapeUnknownChars = false;
143     }
144
145     /**
146      * @see org.xml.sax.ContentHandler#characters(char[], int, int)
147      */

148     public void characters(char[] buf, int offset, int len) throws SAXException JavaDoc {
149
150         if (len == 0) {
151             return;
152         }
153         if (m_openElement) {
154             write(">");
155             m_openElement = false;
156         }
157         if (m_openCdata) {
158             write("<![CDATA[");
159             m_openCdata = false;
160         }
161         if (m_escapeXml && !m_isCdata) {
162             // XML should be escaped and we are not in a CDATA node
163
String JavaDoc escaped = new String JavaDoc(buf, offset, len);
164             // escape HTML entities ('<' becomes '&lt;')
165
escaped = CmsEncoder.escapeXml(escaped, true);
166             if (m_escapeUnknownChars) {
167                 // escape all chars that can not be displayed in the selected encoding (using '&#123;' entities)
168
escaped = CmsEncoder.adjustHtmlEncoding(escaped, getEncoding());
169             }
170             write(escaped);
171         } else {
172             // no escaping or in CDATA node
173
write(new String JavaDoc(buf, offset, len));
174         }
175     }
176
177     /**
178      * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
179      */

180     public void comment(char[] ch, int start, int length) {
181
182         // ignore
183
}
184
185     /**
186      * @see org.xml.sax.ext.LexicalHandler#endCDATA()
187      */

188     public void endCDATA() throws SAXException JavaDoc {
189
190         if (!m_openCdata) {
191             write("]]>");
192         }
193         m_openCdata = false;
194         m_isCdata = false;
195     }
196
197     /**
198      * @see org.xml.sax.ContentHandler#endDocument()
199      */

200     public void endDocument() throws SAXException JavaDoc {
201
202         try {
203             if (m_openElement) {
204                 write("/>");
205                 m_openElement = false;
206             }
207             writeNewLine();
208             m_writer.flush();
209         } catch (IOException JavaDoc e) {
210             throw new SAXException JavaDoc(Messages.get().getBundle().key(Messages.ERR_IOERROR_0), e);
211         }
212     }
213
214     /**
215      * @see org.xml.sax.ext.LexicalHandler#endDTD()
216      */

217     public void endDTD() {
218
219         // NOOP
220
}
221
222     /**
223      * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
224      */

225     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qualifiedName) throws SAXException JavaDoc {
226
227         String JavaDoc elementName = resolveName(localName, qualifiedName);
228         if (m_openElement) {
229             write("/>");
230         } else {
231             if (!elementName.equals(m_lastElementName)) {
232                 writeNewLine();
233             }
234             write("</");
235             write(elementName);
236             write(">");
237         }
238         m_openElement = false;
239         m_indentLevel--;
240     }
241
242     /**
243      * @see org.xml.sax.ext.LexicalHandler#endEntity(java.lang.String)
244      */

245     public void endEntity(String JavaDoc name) {
246
247         // NOOP
248
}
249
250     /**
251      * Returns the encoding this XML Sax writer was initialized with.<p>
252      *
253      * @return the encoding this XML Sax writer was initialized with
254      */

255     public String JavaDoc getEncoding() {
256
257         return m_encoding;
258     }
259
260     /**
261      * Returns the Writer where the XML is written to.<p>
262      *
263      * @return the Writer where the XML is written to
264      */

265     public Writer JavaDoc getWriter() {
266
267         return m_writer;
268     }
269
270     /**
271      * Returns <code>true</code> if charactes that are not part of the selected encoding
272      * are to be replaced with the HTML <code>&amp;#123;</code> entity representation
273      * in the generated output (not in CDATA elements).<p>
274      *
275      * @return <code>true</code> if charactes that are not part of the selected encoding
276      * are to be replaced with the HTML entity representation
277      */

278     public boolean isEscapeUnknownChars() {
279
280         return m_escapeUnknownChars;
281     }
282
283     /**
284      * Returns <code>true</code> if XML entities are to be encoded in the generated output (not in CDATA elements).<p>
285      *
286      * @return <code>true</code> if XML entities are to be encoded in the generated output (not in CDATA elements)
287      */

288     public boolean isEscapeXml() {
289
290         return m_escapeXml;
291     }
292
293     /**
294      * Sets the encoding to use for the generated output.<p>
295      *
296      * @param value the encoding to use for the generated output
297      */

298     public void setEncoding(String JavaDoc value) {
299
300         m_encoding = value;
301     }
302
303     /**
304      * If set to <code>true</code>, then charactes that are not part of the selected encoding
305      * are to be replaced with the XML <code>&amp;#123;</code> entity representation
306      * in the generated output (not in CDATA elements).<p>
307      *
308      * @param value indicates to escape unknown characters with XML entities or not
309      */

310     public void setEscapeUnknownChars(boolean value) {
311
312         m_escapeUnknownChars = value;
313     }
314
315     /**
316      * If set to <code>true</code>, then
317      * XML entities are to be encoded in the generated output (not in CDATA elements).<p>
318      *
319      * @param value indicates to to escape characters with XML entities or not
320      */

321     public void setEscapeXml(boolean value) {
322
323         m_escapeXml = value;
324     }
325
326     /**
327      * @see org.xml.sax.ext.LexicalHandler#startCDATA()
328      */

329     public void startCDATA() {
330
331         m_openCdata = true;
332         m_isCdata = true;
333     }
334
335     /**
336      * @see org.xml.sax.ContentHandler#startDocument()
337      */

338     public void startDocument() throws SAXException JavaDoc {
339
340         write("<?xml version=\"1.0\" encoding=\"");
341         write(m_encoding);
342         write("\"?>");
343         writeNewLine();
344     }
345
346     /**
347      * @see org.xml.sax.ext.LexicalHandler#startDTD(java.lang.String, java.lang.String, java.lang.String)
348      */

349     public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId) {
350
351         // NOOP
352
}
353
354     /**
355      * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
356      */

357     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qualifiedName, Attributes JavaDoc attributes)
358     throws SAXException JavaDoc {
359
360         if (m_openElement) {
361             write(">");
362             m_openElement = false;
363         }
364         // increase indent and write linebreak
365
m_indentLevel++;
366         writeNewLine();
367         // get element name and write entry
368
m_lastElementName = resolveName(localName, qualifiedName);
369         write("<");
370         write(m_lastElementName);
371         if (attributes != null) {
372             for (int i = 0; i < attributes.getLength(); i++) {
373                 write(" ");
374                 write(resolveName(attributes.getLocalName(i), attributes.getQName(i)));
375                 write("=\"");
376                 write(attributes.getValue(i));
377                 write("\"");
378             }
379         }
380         m_openElement = true;
381     }
382
383     /**
384      * @see org.xml.sax.ext.LexicalHandler#startEntity(java.lang.String)
385      */

386     public void startEntity(String JavaDoc name) {
387
388         // ignore
389
}
390
391     /**
392      * Resolves the local vs. the qualified name.<p>
393      *
394      * If the local name is the empty String "", the qualified name is used.<p>
395      *
396      * @param localName the local name
397      * @param qualifiedName the qualified XML 1.0 name
398      * @return the resolved name to use
399      */

400     private String JavaDoc resolveName(String JavaDoc localName, String JavaDoc qualifiedName) {
401
402         if ((localName == null) || (localName.length() == 0)) {
403             return qualifiedName;
404         } else {
405             return localName;
406         }
407     }
408
409     /**
410      * Writes s String to the output stream.<p>
411      *
412      * @param s the String to write
413      * @throws SAXException in case of I/O errors
414      */

415     private void write(String JavaDoc s) throws SAXException JavaDoc {
416
417         try {
418             m_writer.write(s);
419         } catch (IOException JavaDoc e) {
420             throw new SAXException JavaDoc(Messages.get().getBundle().key(Messages.ERR_IOERROR_0), e);
421         }
422     }
423
424     /**
425      * Writes a linebreak to the output stream, also handles the indentation.<p>
426      *
427      * @throws SAXException in case of I/O errors
428      */

429     private void writeNewLine() throws SAXException JavaDoc {
430
431         try {
432             // write new line
433
m_writer.write("\r\n");
434             // write indentation
435
for (int i = 1; i < m_indentLevel; i++) {
436                 m_writer.write(INDENT_STR);
437             }
438             // flush the stream
439
m_writer.flush();
440         } catch (IOException JavaDoc e) {
441             throw new SAXException JavaDoc(Messages.get().getBundle().key(Messages.ERR_IOERROR_0), e);
442         }
443     }
444 }
Popular Tags