KickJava   Java API By Example, From Geeks To Geeks.

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


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 j2me.lang.CharSequence;
12 import j2me.nio.ByteBuffer;
13
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.Reader;
17
18 import javolution.lang.Reusable;
19 import javolution.xml.pull.XmlPullParser;
20 import javolution.xml.pull.XmlPullParserException;
21 import javolution.xml.pull.XmlPullParserImpl;
22
23 import org.xml.sax.DTDHandler;
24 import org.xml.sax.EntityResolver;
25 import org.xml.sax.ErrorHandler;
26 import org.xml.sax.Locator;
27 import org.xml.sax.SAXException;
28 import org.xml.sax.SAXNotRecognizedException;
29 import org.xml.sax.SAXNotSupportedException;
30 import org.xml.sax.SAXParseException;
31
32 /**
33  * <p> This class provides a real-time SAX2-like XML parser; this parser is
34  * <i>extremely</i> fast and <b>does not create temporary objects</b>
35  * (no garbage generated and no GC interruption).</p>
36  *
37  * <p> The parser input source can be either a {@link #parse(Reader) Reader},
38  * an {@link #parse(InputStream) InputStream} or even a {@link
39  * #parse(ByteBuffer) ByteBuffer} (e.g. <code>MappedByteBuffer</code>).</p>
40  *
41  * <p> The parser is implemented as a SAX2 wrapper around the real-time
42  * {@link XmlPullParserImpl} and share the same characteristics.</p>
43  *
44  * <p><i> Note: This parser is a <b>SAX2-like</b> parser with the
45  * <code>java.lang.String</code> type replaced by the more generic
46  * <code>j2me.lang.CharSequence</code> in the {@link ContentHandler},
47  * {@link Attributes} interfaces and {@link DefaultHandler} base class.
48  * If a standard SAX2 or JAXP parser is required, you may consider using
49  * the wrapping class {@link XMLReaderImpl}. Fast but not as fast as
50  * <code>java.lang.String</code> instances are dynamically allocated
51  * while parsing.</i></p>
52  *
53  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
54  * @version 3.2, April 2, 2005
55  */

56 public class XmlSaxParserImpl implements Reusable {
57
58     /**
59      * Holds the default handler instance.
60      */

61     private static DefaultHandler DEFAULT_HANDLER = new DefaultHandler();
62
63     /**
64      * Holds the content handler.
65      */

66     private ContentHandler _contentHandler;
67
68     /**
69      * Holds the error handler.
70      */

71     private ErrorHandler _errorHandler;
72
73     /**
74      * Holds the pull parser used for parsing.
75      */

76     private final XmlPullParserImpl _pullParser = new XmlPullParserImpl();
77
78     /**
79      * Holds the document locator.
80      */

81     private final LocatorImpl _locator = new LocatorImpl();
82
83     /**
84      * Default constructor.
85      */

86     public XmlSaxParserImpl() {
87         // Sets default handlers.
88
setContentHandler(DEFAULT_HANDLER);
89         setErrorHandler(DEFAULT_HANDLER);
90     }
91
92     /**
93      * Allows an application to register a real-time content event handler.
94      *
95      * <p> If the application does not register a content handler, all
96      * content events reported by the SAX parser will be silently
97      * ignored.</p>
98      *
99      * <p> Applications may register a new or different handler in the
100      * middle of a parse, and the SAX parser must begin using the new
101      * handler immediately.</p>
102      *
103      * @param handler the real-time content handler.
104      * @throws NullPointerException if the handler argument is null.
105      * @see #getContentHandler
106      */

107     public void setContentHandler(ContentHandler handler) {
108         if (handler != null) {
109             _contentHandler = handler;
110         } else {
111             throw new NullPointerException();
112         }
113     }
114
115     /**
116      * Returns the current real-time content handler.
117      *
118      * @return the current real-time content handler, or <code>null</code>
119      * if none has been registered.
120      * @see #setContentHandler
121      */

122     public ContentHandler getContentHandler() {
123         return (_contentHandler == DEFAULT_HANDLER) ? null : _contentHandler;
124     }
125
126     /**
127      * Allows an application to register an error event handler.
128      *
129      * <p> If the application does not register an error handler, all
130      * error events reported by the SAX parser will be silently
131      * ignored; however, normal processing may not continue. It is
132      * highly recommended that all SAX applications implement an
133      * error handler to avoid unexpected bugs.</p>
134      *
135      * <p> Applications may register a new or different handler in the
136      * middle of a parse, and the SAX parser must begin using the new
137      * handler immediately.</p>
138      *
139      * @param handler the error handler.
140      * @throws NullPointerException if the handler argument is null.
141      * @see #getErrorHandler
142      */

143     public void setErrorHandler(ErrorHandler handler) {
144         if (handler != null) {
145             _errorHandler = handler;
146         } else {
147             throw new NullPointerException();
148         }
149     }
150
151     /**
152      * Returns the current error handler.
153      *
154      * @return the current error handler, or <code>null</code> if none
155      * has been registered.
156      * @see #setErrorHandler
157      */

158     public ErrorHandler getErrorHandler() {
159         return (_errorHandler == DEFAULT_HANDLER) ? null : _errorHandler;
160     }
161
162     /**
163      * Parses an XML document from the specified input stream (UTF-8 encoding).
164      *
165      * @param in the input stream with UTF-8 encoding.
166      * @throws org.xml.sax.SAXException any SAX exception, possibly
167      * wrapping another exception.
168      * @throws IOException an IO exception from the parser,
169      * possibly from a byte stream or character stream
170      * supplied by the application.
171      * @see javolution.io.Utf8StreamReader
172      */

173     public void parse(InputStream in) throws IOException, SAXException {
174         _pullParser.setInput(in);
175         parseAll();
176     }
177
178     /**
179      * Parses an XML document from the specified <code>ByteBuffer</code>
180      * (UTF-8 encoding).
181      *
182      * @param byteBuffer the byte buffer with UTF-8 encoding.
183      * @throws org.xml.sax.SAXException any SAX exception, possibly
184      * wrapping another exception.
185      * @throws IOException an IO exception from the parser,
186      * possibly from a byte stream or character stream
187      * supplied by the application.
188      * @see javolution.io.Utf8ByteBufferReader
189      */

190     public void parse(ByteBuffer byteBuffer) throws IOException, SAXException {
191         _pullParser.setInput(byteBuffer);
192         parseAll();
193     }
194
195     /**
196      * Parses an XML document using the specified reader.
197      *
198      * @param reader the document reader.
199      * @throws SAXException any SAX exception, possibly wrapping another
200      * exception.
201      * @throws IOException an IO exception from the parser, possibly from
202      * a byte stream or character stream supplied by the application.
203      */

204     public void parse(Reader reader) throws IOException, SAXException {
205         _pullParser.setInput(reader);
206         parseAll();
207     }
208
209     /**
210      * Looks up the value of a feature.
211      *
212      * <p> Recognizes <code>http://xml.org/sax/features/namespaces</code>
213      * and the <code>http://xml.org/sax/features/namespace-prefixes</code>
214      * feature names.</p>
215      *
216      * @param name the feature name, which is a fully-qualified URI.
217      * @return the current state of the feature (true or false).
218      * @throws org.xml.sax.SAXNotRecognizedException when the XMLReader does
219      * not recognize the feature name.
220      * @throws org.xml.sax.SAXNotSupportedException when the XMLReader
221      * recognizes the feature name but cannot determine its value
222      * at this time.
223      * @see #setFeature
224      */

225     public boolean getFeature(String name) throws SAXNotRecognizedException,
226             SAXNotSupportedException {
227         if (name.equals("http://xml.org/sax/features/namespaces")) {
228             return true;
229         } else if (name
230                 .equals("http://xml.org/sax/features/namespace-prefixes")) {
231             return true;
232         } else {
233             throw new SAXNotRecognizedException("Feature " + name
234                     + " not recognized");
235         }
236     }
237
238     /**
239      * Sets the state of a feature.
240      *
241      * <p> Recognizes <code>http://xml.org/sax/features/namespaces</code>
242      * and the <code>http://xml.org/sax/features/namespace-prefixes</code>
243      * feature names.</p>
244      *
245      * @param name the feature name, which is a fully-qualified URI.
246      * @param value the requested state of the feature (true or false).
247      * @throws org.xml.sax.SAXNotRecognizedException when the XMLReader does not
248      * recognize the feature name.
249      * @throws org.xml.sax.SAXNotSupportedException when the XMLReader
250      * recognizes the feature name but cannot set the requested value.
251      * @see #getFeature
252      */

253     public void setFeature(String name, boolean value)
254             throws SAXNotRecognizedException, SAXNotSupportedException {
255         if (name.equals("http://xml.org/sax/features/namespaces")
256                 || name
257                         .equals("http://xml.org/sax/features/namespace-prefixes")) {
258             return; // Ignores, these features are always set.
259
} else {
260             throw new SAXNotRecognizedException("Feature " + name
261                     + " not recognized");
262         }
263     }
264
265     /**
266      * Looks up the value of a property.
267      *
268      * @param name the property name, which is a fully-qualified URI.
269      * @return the current value of the property.
270      * @throws org.xml.sax.SAXNotRecognizedException when the
271      * XMLReader does not recognize the property name.
272      * @throws org.xml.sax.SAXNotSupportedException when the
273      * XMLReader recognizes the property name but
274      * cannot determine its value at this time.
275      * @see #setProperty
276      */

277     public Object getProperty(String name) throws SAXNotRecognizedException,
278             SAXNotSupportedException {
279         throw new SAXNotRecognizedException("Property " + name
280                 + " not recognized");
281     }
282
283     /**
284      * Sets the value of a property.
285      *
286      * @param name the property name, which is a fully-qualified URI.
287      * @param value the requested value for the property.
288      * @throws org.xml.sax.SAXNotRecognizedException when the
289      * XMLReader does not recognize the property name.
290      * @throws org.xml.sax.SAXNotSupportedException when the
291      * XMLReader recognizes the property name but
292      * cannot set the requested value.
293      */

294     public void setProperty(String name, Object value)
295             throws SAXNotRecognizedException, SAXNotSupportedException {
296         throw new SAXNotRecognizedException("Property " + name
297                 + " not recognized");
298     }
299
300     /**
301      * Allows an application to register an entity resolver (ignored by this
302      * parser).
303      *
304      * @param resolver the entity resolver.
305      */

306     public void setEntityResolver(EntityResolver resolver) {
307         _entityResolver = resolver;
308     }
309
310     private EntityResolver _entityResolver;
311
312     /**
313      * Returns the current entity resolver.
314      *
315      * @return the current entity resolver, or <code>null</code> if none
316      * has been registered.
317      * @see #setEntityResolver
318      */

319     public EntityResolver getEntityResolver() {
320         return _entityResolver;
321     }
322
323     /**
324      * Allows an application to register a DTD handler (ignored by this parser).
325      *
326      * @param handler the DTD handler.
327      */

328     public void setDTDHandler(DTDHandler handler) {
329         _dtdHandler = handler;
330     }
331
332     private DTDHandler _dtdHandler;
333
334     /**
335      * Returns the current DTD handler.
336      *
337      * @return the current DTD handler, or <code>null</code> if none
338      * has been registered.
339      * @see #setDTDHandler
340      */

341     public DTDHandler getDTDHandler() {
342         return _dtdHandler;
343     }
344
345     // Implements Reusable.
346
public void reset() {
347         setContentHandler(DEFAULT_HANDLER);
348         setErrorHandler(DEFAULT_HANDLER);
349         _pullParser.reset();
350     }
351
352     /**
353      * Parses the whole document using the real-time pull parser.
354      *
355      * @throws SAXException any SAX exception, possibly wrapping another
356      * exception.
357      * @throws IOException an IO exception from the parser, possibly from
358      * a byte stream or character stream supplied by the application.
359      */

360     private void parseAll() throws IOException, SAXException {
361         try {
362             int eventType = _pullParser.getEventType();
363             if (eventType != XmlPullParser.START_DOCUMENT)
364                 throw new SAXException("Currently parsing");
365             _contentHandler.startDocument();
366             int namespaceCount = 0;
367
368             while (true) {
369                 eventType = _pullParser.nextToken();
370                 if (eventType == XmlPullParser.START_TAG) {
371
372                     // Start prefix mapping.
373
final int depth = _pullParser.getDepth();
374                     final int nsStart = _pullParser
375                             .getNamespaceCount(depth - 1);
376                     final int nsEnd = _pullParser.getNamespaceCount(depth);
377                     for (int i = nsStart; i < nsEnd; i++) {
378                         CharSequence prefix = _pullParser.getNamespacePrefix(i);
379                         CharSequence uri = _pullParser.getNamespaceUri(i);
380                         _contentHandler.startPrefixMapping(prefix, uri);
381                     }
382
383                     // Start element.
384
CharSequence localName = _pullParser.getName();
385                     CharSequence uri = _pullParser.getNamespace();
386                     CharSequence qName = _pullParser.getQName();
387                     Attributes atts = _pullParser.getSaxAttributes();
388                     _contentHandler.startElement(uri, localName, qName, atts);
389
390                 } else if (eventType == XmlPullParser.END_TAG) {
391
392                     // End element.
393
CharSequence localName = _pullParser.getName();
394                     CharSequence uri = _pullParser.getNamespace();
395                     CharSequence qName = _pullParser.getQName();
396                     _contentHandler.endElement(uri, localName, qName);
397
398                     // Prefix unmapping.
399
final int depth = _pullParser.getDepth();
400                     final int nsStart = _pullParser.getNamespaceCount(depth);
401                     final int nsEnd = _pullParser.getNamespaceCount(depth + 1);
402                     for (int i = nsStart; i < nsEnd; i++) {
403                         CharSequence prefix = _pullParser.getNamespacePrefix(i);
404                         _contentHandler.endPrefixMapping(prefix);
405                     }
406
407                 } else if ((eventType == XmlPullParser.TEXT)
408                         || (eventType == XmlPullParser.CDSECT)) {
409                     char ch[] = _pullParser.getTextCharacters(_startLength);
410                     _contentHandler.characters(ch, _startLength[0],
411                             _startLength[1]);
412
413                 } else if (eventType == XmlPullParser.END_DOCUMENT) {
414                     break;
415
416                 } else {
417                     // Ignores.
418
}
419             }
420         } catch (XmlPullParserException e) {
421             SAXParseException error = new SAXParseException(e.getMessage(),
422                     _locator);
423             _errorHandler.fatalError(error);
424
425         } finally { // Always executed.
426
_contentHandler.endDocument();
427             reset();
428         }
429     }
430
431     int[] _startLength = new int[2];
432
433     /**
434      * Inner class implements Locator interface.
435      */

436     private class LocatorImpl implements Locator {
437         public String getPublicId() {
438             return null;
439         }
440
441         public String getSystemId() {
442             return null;
443         }
444
445         public int getLineNumber() {
446             return _pullParser.getLineNumber();
447         }
448
449         public int getColumnNumber() {
450             return _pullParser.getColumnNumber();
451         }
452     }
453 }
Popular Tags