KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > xml > sax > WriterHandler


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2005 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.xml.sax;
10
11 import java.io.IOException;
12 import java.io.Writer;
13
14 import j2me.lang.CharSequence;
15 import javolution.lang.Reusable;
16 import javolution.lang.Text;
17 import javolution.util.FastList;
18
19 import org.xml.sax.Locator;
20 import org.xml.sax.SAXException;
21
22 /**
23  * <p> This class generates xml documents from SAX2 events.</p>
24  *
25  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
26  * @version 3.1, March 11, 2005
27  */

28 public class WriterHandler implements ContentHandler, Reusable {
29
30     /**
31      * Holds the length of intermediate buffer.
32      */

33     private static final int BUFFER_LENGTH = 2048;
34
35     /**
36      * Holds the writer destination.
37      */

38     private Writer _writer;
39
40     /**
41      * Holds the prolog.
42      */

43     private CharSequence _prolog = Text.EMPTY;
44
45     /**
46      * Holds the indentation string.
47      */

48     private CharSequence _indent = Text.EMPTY;
49
50     /**
51      * Holds the current prefix mapping (prefix followed by uri).
52      */

53     private FastList _prefixMappings = new FastList();
54
55     /**
56      * Holds the current nesting level.
57      */

58     private int _nesting = -1;
59
60     /**
61      * Indicates if the current element tag is still open (to be closed
62      * with ">" or "/>" whether it is empty or not).
63      */

64     private boolean _isTagOpen;
65
66     /**
67      * Holds intermediate buffer.
68      */

69     private final char[] _buffer = new char[BUFFER_LENGTH];
70
71     /**
72      * Holds the buffer current index.
73      */

74     private int _index;
75
76     /**
77      * Default constructor.
78      */

79     public WriterHandler() {
80     }
81
82     /**
83      * Sets the xml document writer.
84      *
85      * @param writer the document writer.
86      * @return <code>this</code>
87      */

88     public WriterHandler setWriter(Writer writer) {
89         _writer = writer;
90         return this;
91     }
92
93     /**
94      * Sets the indentation sequence (default none).
95      *
96      * @param indent a character sequence containing spaces or a tabulation character.
97      */

98     public void setIndent(CharSequence indent) {
99         _indent = indent;
100     }
101
102     /**
103      * Sets the prolog to write at the beginning of the xml document
104      * (default none).
105      *
106      * @param prolog the character sequence to be written at the beginning
107      * of the document.
108      */

109     public void setProlog(CharSequence prolog) {
110         _prolog = prolog;
111     }
112
113     // Implements reusable.
114
public void reset() {
115         _writer = null;
116         _indent = Text.EMPTY;
117         _prolog = Text.EMPTY;
118         _prefixMappings.clear();
119         _nesting = -1;
120         _isTagOpen = false;
121         _index = 0;
122     }
123
124     // Implements ContentHandler
125
public void setDocumentLocator(Locator locator) {
126         // Do nothing.
127
}
128
129     // Implements ContentHandler
130
public void startDocument() throws SAXException {
131         if (_writer == null)
132             throw new SAXException("Writer not set");
133         try {
134             writeNoEscape(_prolog);
135         } catch (IOException e) {
136             throw new SAXException(e);
137         }
138     }
139
140     // Implements ContentHandler
141
public void endDocument() throws SAXException {
142         try {
143             flushBuffer();
144             _writer.close();
145         } catch (IOException e) {
146             throw new SAXException(e);
147         }
148     }
149
150     // Implements ContentHandler
151
public void startPrefixMapping(CharSequence prefix, CharSequence uri)
152             throws SAXException {
153         _prefixMappings.addLast(prefix);
154         _prefixMappings.addLast(uri);
155     }
156
157     // Implements ContentHandler
158
public void endPrefixMapping(CharSequence prefix) throws SAXException {
159         // Do nothing.
160
}
161
162     // Implements ContentHandler
163
public void startElement(CharSequence uri, CharSequence localName,
164             CharSequence qName, Attributes atts) throws SAXException {
165         try {
166             if (_isTagOpen) { // The openned tag is not empty, close with ">"
167
writeNoEscape(">\n");
168                 _isTagOpen = false;
169             }
170
171             // Indents.
172
_nesting++;
173             indent();
174
175             // Writes start tag.
176
writeNoEscape('<');
177             writeNoEscape(qName);
178
179             // Writes namespaces if any.
180
if (_prefixMappings.size() > 0) {
181                 writeNamespaces();
182             }
183
184             // Writes attributes
185
final int attsLength = atts.getLength();
186             for (int i = 0; i < attsLength; i++) {
187                 CharSequence attName = atts.getQName(i);
188                 CharSequence attValue = atts.getValue(i);
189                 writeNoEscape(' ');
190                 writeNoEscape(attName);
191                 writeNoEscape('=');
192                 writeNoEscape('"');
193                 write(attValue);
194                 writeNoEscape('"');
195             }
196             _isTagOpen = true;
197         } catch (IOException e) {
198             throw new SAXException(e);
199         }
200     }
201
202     private void indent() throws IOException {
203         final int length = _indent.length();
204         if (length > 0) {
205             for (int i = 0; i < _nesting; i++) {
206                 writeNoEscape(_indent);
207             }
208         }
209     }
210     
211     private void writeNamespaces() throws IOException {
212         // Writes namespace declaration.
213
for (FastList.Node n = _prefixMappings.headNode(), end = _prefixMappings
214                 .tailNode(); (n = n.getNextNode()) != end;) {
215             CharSequence prefix = (CharSequence) n.getValue();
216             CharSequence prefixUri = (CharSequence) (n = n.getNextNode())
217                     .getValue();
218             if (prefix.length() == 0) { // Default namespace.
219
writeNoEscape(" xmlns=\"");
220                 write(prefixUri);
221                 writeNoEscape('"');
222             } else {
223                 writeNoEscape(" xmlns:");
224                 writeNoEscape(prefix);
225                 writeNoEscape('=');
226                 writeNoEscape('"');
227                 write(prefixUri);
228                 writeNoEscape('"');
229             }
230         }
231         _prefixMappings.clear();
232     }
233
234     // Implements ContentHandler
235
public void endElement(CharSequence uri, CharSequence localName,
236             CharSequence qName) throws SAXException {
237         try {
238             if (_isTagOpen) { // The openned tag is empty, close with "/>"
239
writeNoEscape("/>\n");
240                 _isTagOpen = false;
241             } else {
242                 indent();
243                 writeNoEscape('<');
244                 writeNoEscape('/');
245                 writeNoEscape(qName);
246                 writeNoEscape('>');
247                 writeNoEscape('\n');
248             }
249             _nesting--;
250         } catch (IOException e) {
251             throw new SAXException(e);
252         }
253     }
254
255     // Implements ContentHandler
256
public void characters(char[] ch, int start, int length)
257             throws SAXException {
258         try {
259             if (_isTagOpen) { // The openned tag is not empty, close with ">"
260
writeNoEscape('>');
261                 _isTagOpen = false;
262             }
263             writeNoEscape("<![CDATA[");
264             flushBuffer();
265             _writer.write(ch, start, length);
266             writeNoEscape("]]>\n");
267         } catch (IOException e) {
268             throw new SAXException(e);
269         }
270     }
271
272     // Implements ContentHandler
273
public void ignorableWhitespace(char[] ch, int start, int length)
274             throws SAXException {
275         // Do nothing.
276
}
277
278     // Implements ContentHandler
279
public void processingInstruction(CharSequence target, CharSequence data)
280             throws SAXException {
281         // Do nothing.
282
}
283
284     // Implements ContentHandler
285
public void skippedEntity(CharSequence name) throws SAXException {
286         // Do nothing.
287
}
288
289     // Writes the specified characters. Use escape sequence when necessary.
290
private void write(CharSequence csq) throws IOException {
291         final int length = csq.length();
292         for (int i = 0; i < length;) {
293             char c = csq.charAt(i++);
294             if ((c >= '@') || (c == ' ')) { // Most common case.
295
_buffer[_index] = c;
296                 if (++_index == BUFFER_LENGTH) {
297                     flushBuffer();
298                 }
299             } else { // Potential escape sequence.
300
switch (c) {
301                 case '<':
302                     writeNoEscape("&lt;");
303                     break;
304                 case '>':
305                     writeNoEscape("&gt;");
306                     break;
307                 case '\'':
308                     writeNoEscape("&apos;");
309                     break;
310                 case '\"':
311                     writeNoEscape("&quot;");
312                     break;
313                 case '&':
314                     writeNoEscape("&amp;");
315                     break;
316                 default:
317                     if (c >= ' ') {
318                         writeNoEscape(c);
319                     } else {
320                         writeNoEscape("&#");
321                         writeNoEscape((char) ('0' + c / 10));
322                         writeNoEscape((char) ('0' + c % 10));
323                         writeNoEscape(';');
324                     }
325                 }
326             }
327         }
328     }
329
330     private void writeNoEscape(CharSequence csq) throws IOException {
331         for (int i = 0, n = csq.length(); i < n;) {
332             _buffer[_index] = csq.charAt(i++);
333             if (++_index == BUFFER_LENGTH) {
334                 flushBuffer();
335             }
336         }
337     }
338
339     private void writeNoEscape(String csq) throws IOException {
340         for (int i = 0, n = csq.length(); i < n;) {
341             _buffer[_index] = csq.charAt(i++);
342             if (++_index == BUFFER_LENGTH) {
343                 flushBuffer();
344             }
345         }
346     }
347
348     private final void writeNoEscape(char c) throws IOException {
349         _buffer[_index] = c;
350         if (++_index == BUFFER_LENGTH) {
351             flushBuffer();
352         }
353     }
354
355     private void flushBuffer() throws IOException {
356         _writer.write(_buffer, 0, _index);
357         _index = 0;
358     }
359
360 }
Popular Tags