1 // XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser
2 // http://www.saxproject.org
3 // Written by David Megginson
4 // NO WARRANTY!  This class is in the public domain.
5 // $Id: XMLReaderAdapter.java,v 1.9 2004/04/26 17:34:35 dmegginson Exp $
6 
7 package org.xml.sax.helpers;
8 
9 import org.xml.sax.AttributeList;
10 import org.xml.sax.Attributes;
11 import org.xml.sax.ContentHandler;
12 import org.xml.sax.DTDHandler;
13 import org.xml.sax.DocumentHandler;
14 import org.xml.sax.EntityResolver;
15 import org.xml.sax.ErrorHandler;
16 import org.xml.sax.InputSource;
17 import org.xml.sax.Locator;
18 import org.xml.sax.Parser;
19 import org.xml.sax.SAXException;
20 import org.xml.sax.SAXNotSupportedException;
21 import org.xml.sax.XMLReader;
22 
23 import android.compat.annotation.UnsupportedAppUsage;
24 
25 import java.io.IOException;
26 import java.util.Locale;
27 
28 
29 /**
30  * Adapt a SAX2 XMLReader as a SAX1 Parser.
31  *
32  * <blockquote>
33  * <em>This module, both source code and documentation, is in the
34  * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
35  * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
36  * for further information.
37  * </blockquote>
38  *
39  * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader}
40  * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}.  The XMLReader
41  * must support a true value for the
42  * http://xml.org/sax/features/namespace-prefixes property or parsing will fail
43  * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader
44  * supports a false value for the http://xml.org/sax/features/namespaces
45  * property, that will also be used to improve efficiency.</p>
46  *
47  * @since SAX 2.0
48  * @author David Megginson
49  * @version 2.0.1 (sax2r2)
50  * @see org.xml.sax.Parser
51  * @see org.xml.sax.XMLReader
52  */
53 public class XMLReaderAdapter implements Parser, ContentHandler
54 {
55 
56 
57     ////////////////////////////////////////////////////////////////////
58     // Constructor.
59     ////////////////////////////////////////////////////////////////////
60 
61 
62     /**
63      * Create a new adapter.
64      *
65      * <p>Use the "org.xml.sax.driver" property to locate the SAX2
66      * driver to embed.</p>
67      *
68      * @exception org.xml.sax.SAXException If the embedded driver
69      *            cannot be instantiated or if the
70      *            org.xml.sax.driver property is not specified.
71      */
XMLReaderAdapter()72     public XMLReaderAdapter ()
73       throws SAXException
74     {
75     setup(XMLReaderFactory.createXMLReader());
76     }
77 
78 
79     /**
80      * Create a new adapter.
81      *
82      * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
83      * The adapter will make the XMLReader act like a SAX1
84      * Parser.</p>
85      *
86      * @param xmlReader The SAX2 XMLReader to wrap.
87      * @exception java.lang.NullPointerException If the argument is null.
88      */
XMLReaderAdapter(XMLReader xmlReader)89     public XMLReaderAdapter (XMLReader xmlReader)
90     {
91     setup(xmlReader);
92     }
93 
94 
95 
96     /**
97      * Internal setup.
98      *
99      * @param xmlReader The embedded XMLReader.
100      */
101     @UnsupportedAppUsage
setup(XMLReader xmlReader)102     private void setup (XMLReader xmlReader)
103     {
104     if (xmlReader == null) {
105         throw new NullPointerException("XMLReader must not be null");
106     }
107     this.xmlReader = xmlReader;
108     qAtts = new AttributesAdapter();
109     }
110 
111 
112 
113     ////////////////////////////////////////////////////////////////////
114     // Implementation of org.xml.sax.Parser.
115     ////////////////////////////////////////////////////////////////////
116 
117 
118     /**
119      * Set the locale for error reporting.
120      *
121      * <p>This is not supported in SAX2, and will always throw
122      * an exception.</p>
123      *
124      * @param locale the locale for error reporting.
125      * @see org.xml.sax.Parser#setLocale
126      * @exception org.xml.sax.SAXException Thrown unless overridden.
127      */
setLocale(Locale locale)128     public void setLocale (Locale locale)
129     throws SAXException
130     {
131     throw new SAXNotSupportedException("setLocale not supported");
132     }
133 
134 
135     /**
136      * Register the entity resolver.
137      *
138      * @param resolver The new resolver.
139      * @see org.xml.sax.Parser#setEntityResolver
140      */
setEntityResolver(EntityResolver resolver)141     public void setEntityResolver (EntityResolver resolver)
142     {
143     xmlReader.setEntityResolver(resolver);
144     }
145 
146 
147     /**
148      * Register the DTD event handler.
149      *
150      * @param handler The new DTD event handler.
151      * @see org.xml.sax.Parser#setDTDHandler
152      */
setDTDHandler(DTDHandler handler)153     public void setDTDHandler (DTDHandler handler)
154     {
155     xmlReader.setDTDHandler(handler);
156     }
157 
158 
159     /**
160      * Register the SAX1 document event handler.
161      *
162      * <p>Note that the SAX1 document handler has no Namespace
163      * support.</p>
164      *
165      * @param handler The new SAX1 document event handler.
166      * @see org.xml.sax.Parser#setDocumentHandler
167      */
setDocumentHandler(DocumentHandler handler)168     public void setDocumentHandler (DocumentHandler handler)
169     {
170     documentHandler = handler;
171     }
172 
173 
174     /**
175      * Register the error event handler.
176      *
177      * @param handler The new error event handler.
178      * @see org.xml.sax.Parser#setErrorHandler
179      */
setErrorHandler(ErrorHandler handler)180     public void setErrorHandler (ErrorHandler handler)
181     {
182     xmlReader.setErrorHandler(handler);
183     }
184 
185 
186     /**
187      * Parse the document.
188      *
189      * <p>This method will throw an exception if the embedded
190      * XMLReader does not support the
191      * http://xml.org/sax/features/namespace-prefixes property.</p>
192      *
193      * @param systemId The absolute URL of the document.
194      * @exception java.io.IOException If there is a problem reading
195      *            the raw content of the document.
196      * @exception org.xml.sax.SAXException If there is a problem
197      *            processing the document.
198      * @see #parse(org.xml.sax.InputSource)
199      * @see org.xml.sax.Parser#parse(java.lang.String)
200      */
parse(String systemId)201     public void parse (String systemId)
202     throws IOException, SAXException
203     {
204     parse(new InputSource(systemId));
205     }
206 
207 
208     /**
209      * Parse the document.
210      *
211      * <p>This method will throw an exception if the embedded
212      * XMLReader does not support the
213      * http://xml.org/sax/features/namespace-prefixes property.</p>
214      *
215      * @param input An input source for the document.
216      * @exception java.io.IOException If there is a problem reading
217      *            the raw content of the document.
218      * @exception org.xml.sax.SAXException If there is a problem
219      *            processing the document.
220      * @see #parse(java.lang.String)
221      * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
222      */
parse(InputSource input)223     public void parse (InputSource input)
224     throws IOException, SAXException
225     {
226     setupXMLReader();
227     xmlReader.parse(input);
228     }
229 
230 
231     /**
232      * Set up the XML reader.
233      */
234     @UnsupportedAppUsage
setupXMLReader()235     private void setupXMLReader ()
236     throws SAXException
237     {
238     xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
239     try {
240         xmlReader.setFeature("http://xml.org/sax/features/namespaces",
241                              false);
242     } catch (SAXException e) {
243         // NO OP: it's just extra information, and we can ignore it
244     }
245     xmlReader.setContentHandler(this);
246     }
247 
248 
249 
250     ////////////////////////////////////////////////////////////////////
251     // Implementation of org.xml.sax.ContentHandler.
252     ////////////////////////////////////////////////////////////////////
253 
254 
255     /**
256      * Set a document locator.
257      *
258      * @param locator The document locator.
259      * @see org.xml.sax.ContentHandler#setDocumentLocator
260      */
setDocumentLocator(Locator locator)261     public void setDocumentLocator (Locator locator)
262     {
263     if (documentHandler != null)
264         documentHandler.setDocumentLocator(locator);
265     }
266 
267 
268     /**
269      * Start document event.
270      *
271      * @exception org.xml.sax.SAXException The client may raise a
272      *            processing exception.
273      * @see org.xml.sax.ContentHandler#startDocument
274      */
startDocument()275     public void startDocument ()
276     throws SAXException
277     {
278     if (documentHandler != null)
279         documentHandler.startDocument();
280     }
281 
282 
283     /**
284      * End document event.
285      *
286      * @exception org.xml.sax.SAXException The client may raise a
287      *            processing exception.
288      * @see org.xml.sax.ContentHandler#endDocument
289      */
endDocument()290     public void endDocument ()
291     throws SAXException
292     {
293     if (documentHandler != null)
294         documentHandler.endDocument();
295     }
296 
297 
298     /**
299      * Adapt a SAX2 start prefix mapping event.
300      *
301      * @param prefix The prefix being mapped.
302      * @param uri The Namespace URI being mapped to.
303      * @see org.xml.sax.ContentHandler#startPrefixMapping
304      */
startPrefixMapping(String prefix, String uri)305     public void startPrefixMapping (String prefix, String uri)
306     {
307     }
308 
309 
310     /**
311      * Adapt a SAX2 end prefix mapping event.
312      *
313      * @param prefix The prefix being mapped.
314      * @see org.xml.sax.ContentHandler#endPrefixMapping
315      */
endPrefixMapping(String prefix)316     public void endPrefixMapping (String prefix)
317     {
318     }
319 
320 
321     /**
322      * Adapt a SAX2 start element event.
323      *
324      * @param uri The Namespace URI.
325      * @param localName The Namespace local name.
326      * @param qName The qualified (prefixed) name.
327      * @param atts The SAX2 attributes.
328      * @exception org.xml.sax.SAXException The client may raise a
329      *            processing exception.
330      * @see org.xml.sax.ContentHandler#endDocument
331      */
startElement(String uri, String localName, String qName, Attributes atts)332     public void startElement (String uri, String localName,
333                   String qName, Attributes atts)
334     throws SAXException
335     {
336     if (documentHandler != null) {
337         qAtts.setAttributes(atts);
338         documentHandler.startElement(qName, qAtts);
339     }
340     }
341 
342 
343     /**
344      * Adapt a SAX2 end element event.
345      *
346      * @param uri The Namespace URI.
347      * @param localName The Namespace local name.
348      * @param qName The qualified (prefixed) name.
349      * @exception org.xml.sax.SAXException The client may raise a
350      *            processing exception.
351      * @see org.xml.sax.ContentHandler#endElement
352      */
endElement(String uri, String localName, String qName)353     public void endElement (String uri, String localName,
354                 String qName)
355     throws SAXException
356     {
357     if (documentHandler != null)
358         documentHandler.endElement(qName);
359     }
360 
361 
362     /**
363      * Adapt a SAX2 characters event.
364      *
365      * @param ch An array of characters.
366      * @param start The starting position in the array.
367      * @param length The number of characters to use.
368      * @exception org.xml.sax.SAXException The client may raise a
369      *            processing exception.
370      * @see org.xml.sax.ContentHandler#characters
371      */
characters(char ch[], int start, int length)372     public void characters (char ch[], int start, int length)
373     throws SAXException
374     {
375     if (documentHandler != null)
376         documentHandler.characters(ch, start, length);
377     }
378 
379 
380     /**
381      * Adapt a SAX2 ignorable whitespace event.
382      *
383      * @param ch An array of characters.
384      * @param start The starting position in the array.
385      * @param length The number of characters to use.
386      * @exception org.xml.sax.SAXException The client may raise a
387      *            processing exception.
388      * @see org.xml.sax.ContentHandler#ignorableWhitespace
389      */
ignorableWhitespace(char ch[], int start, int length)390     public void ignorableWhitespace (char ch[], int start, int length)
391     throws SAXException
392     {
393     if (documentHandler != null)
394         documentHandler.ignorableWhitespace(ch, start, length);
395     }
396 
397 
398     /**
399      * Adapt a SAX2 processing instruction event.
400      *
401      * @param target The processing instruction target.
402      * @param data The remainder of the processing instruction
403      * @exception org.xml.sax.SAXException The client may raise a
404      *            processing exception.
405      * @see org.xml.sax.ContentHandler#processingInstruction
406      */
processingInstruction(String target, String data)407     public void processingInstruction (String target, String data)
408     throws SAXException
409     {
410     if (documentHandler != null)
411         documentHandler.processingInstruction(target, data);
412     }
413 
414 
415     /**
416      * Adapt a SAX2 skipped entity event.
417      *
418      * @param name The name of the skipped entity.
419      * @see org.xml.sax.ContentHandler#skippedEntity
420      * @exception org.xml.sax.SAXException Throwable by subclasses.
421      */
skippedEntity(String name)422     public void skippedEntity (String name)
423     throws SAXException
424     {
425     }
426 
427 
428 
429     ////////////////////////////////////////////////////////////////////
430     // Internal state.
431     ////////////////////////////////////////////////////////////////////
432 
433     @UnsupportedAppUsage
434     XMLReader xmlReader;
435     @UnsupportedAppUsage
436     DocumentHandler documentHandler;
437     @UnsupportedAppUsage
438     AttributesAdapter qAtts;
439 
440 
441 
442     ////////////////////////////////////////////////////////////////////
443     // Internal class.
444     ////////////////////////////////////////////////////////////////////
445 
446 
447     /**
448      * Internal class to wrap a SAX2 Attributes object for SAX1.
449      */
450     static final class AttributesAdapter implements AttributeList
451     {
AttributesAdapter()452     AttributesAdapter ()
453     {
454     }
455 
456 
457     /**
458      * Set the embedded Attributes object.
459      *
460      * @param The embedded SAX2 Attributes.
461      */
setAttributes(Attributes attributes)462     void setAttributes (Attributes attributes)
463     {
464         this.attributes = attributes;
465     }
466 
467 
468     /**
469      * Return the number of attributes.
470      *
471      * @return The length of the attribute list.
472      * @see org.xml.sax.AttributeList#getLength
473      */
getLength()474     public int getLength ()
475     {
476         return attributes.getLength();
477     }
478 
479 
480     /**
481      * Return the qualified (prefixed) name of an attribute by position.
482      *
483      * @return The qualified name.
484      * @see org.xml.sax.AttributeList#getName
485      */
getName(int i)486     public String getName (int i)
487     {
488         return attributes.getQName(i);
489     }
490 
491 
492     /**
493      * Return the type of an attribute by position.
494      *
495      * @return The type.
496      * @see org.xml.sax.AttributeList#getType(int)
497      */
getType(int i)498     public String getType (int i)
499     {
500         return attributes.getType(i);
501     }
502 
503 
504     /**
505      * Return the value of an attribute by position.
506      *
507      * @return The value.
508      * @see org.xml.sax.AttributeList#getValue(int)
509      */
getValue(int i)510     public String getValue (int i)
511     {
512         return attributes.getValue(i);
513     }
514 
515 
516     /**
517      * Return the type of an attribute by qualified (prefixed) name.
518      *
519      * @return The type.
520      * @see org.xml.sax.AttributeList#getType(java.lang.String)
521      */
getType(String qName)522     public String getType (String qName)
523     {
524         return attributes.getType(qName);
525     }
526 
527 
528     /**
529      * Return the value of an attribute by qualified (prefixed) name.
530      *
531      * @return The value.
532      * @see org.xml.sax.AttributeList#getValue(java.lang.String)
533      */
getValue(String qName)534     public String getValue (String qName)
535     {
536         return attributes.getValue(qName);
537     }
538 
539     private Attributes attributes;
540     }
541 
542 }
543 
544 // end of XMLReaderAdapter.java
545