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