001    // XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser
002    // http://www.saxproject.org
003    // Written by David Megginson
004    // NO WARRANTY!  This class is in the public domain.
005    // $Id: XMLReaderAdapter.java,v 1.2 2006/12/10 20:25:41 gnu_andrew Exp $
006    
007    package org.xml.sax.helpers;
008    
009    import java.io.IOException;
010    import java.util.Locale;
011    
012    import org.xml.sax.Parser;      // deprecated
013    import org.xml.sax.Locator;
014    import org.xml.sax.InputSource;
015    import org.xml.sax.AttributeList; // deprecated
016    import org.xml.sax.EntityResolver;
017    import org.xml.sax.DTDHandler;
018    import org.xml.sax.DocumentHandler; // deprecated
019    import org.xml.sax.ErrorHandler;
020    import org.xml.sax.SAXException;
021    
022    import org.xml.sax.XMLReader;
023    import org.xml.sax.Attributes;
024    import org.xml.sax.ContentHandler;
025    import org.xml.sax.SAXNotSupportedException;
026    
027    
028    /**
029     * Adapt a SAX2 XMLReader as a SAX1 Parser.
030     *
031     * <blockquote>
032     * <em>This module, both source code and documentation, is in the
033     * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
034     * See <a href='http://www.saxproject.org'>http://www.saxproject.org</a>
035     * for further information.
036     * </blockquote>
037     *
038     * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader}
039     * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}.  The XMLReader 
040     * must support a true value for the 
041     * http://xml.org/sax/features/namespace-prefixes property or parsing will fail
042     * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader 
043     * supports a false value for the http://xml.org/sax/features/namespaces 
044     * property, that will also be used to improve efficiency.</p>
045     *
046     * @since SAX 2.0
047     * @author David Megginson
048     * @version 2.0.1 (sax2r2)
049     * @see org.xml.sax.Parser
050     * @see org.xml.sax.XMLReader
051     */
052    public class XMLReaderAdapter implements Parser, ContentHandler
053    {
054    
055    
056        ////////////////////////////////////////////////////////////////////
057        // Constructor.
058        ////////////////////////////////////////////////////////////////////
059    
060    
061        /**
062         * Create a new adapter.
063         *
064         * <p>Use the "org.xml.sax.driver" property to locate the SAX2
065         * driver to embed.</p>
066         *
067         * @exception org.xml.sax.SAXException If the embedded driver
068         *            cannot be instantiated or if the
069         *            org.xml.sax.driver property is not specified.
070         */
071        public XMLReaderAdapter ()
072          throws SAXException
073        {
074            setup(XMLReaderFactory.createXMLReader());
075        }
076    
077    
078        /**
079         * Create a new adapter.
080         *
081         * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
082         * The adapter will make the XMLReader act like a SAX1
083         * Parser.</p>
084         *
085         * @param xmlReader The SAX2 XMLReader to wrap.
086         * @exception java.lang.NullPointerException If the argument is null.
087         */
088        public XMLReaderAdapter (XMLReader xmlReader)
089        {
090            setup(xmlReader);
091        }
092    
093    
094    
095        /**
096         * Internal setup.
097         *
098         * @param xmlReader The embedded XMLReader.
099         */
100        private void setup (XMLReader xmlReader)
101        {
102            if (xmlReader == null) {
103                throw new NullPointerException("XMLReader must not be null");
104            }
105            this.xmlReader = xmlReader;
106            qAtts = new AttributesAdapter();
107        }
108    
109    
110    
111        ////////////////////////////////////////////////////////////////////
112        // Implementation of org.xml.sax.Parser.
113        ////////////////////////////////////////////////////////////////////
114    
115    
116        /**
117         * Set the locale for error reporting.
118         *
119         * <p>This is not supported in SAX2, and will always throw
120         * an exception.</p>
121         *
122         * @param locale the locale for error reporting.
123         * @see org.xml.sax.Parser#setLocale
124         * @exception org.xml.sax.SAXException Thrown unless overridden.
125         */
126        public void setLocale (Locale locale)
127            throws SAXException
128        {
129            throw new SAXNotSupportedException("setLocale not supported");
130        }
131    
132    
133        /**
134         * Register the entity resolver.
135         *
136         * @param resolver The new resolver.
137         * @see org.xml.sax.Parser#setEntityResolver
138         */
139        public void setEntityResolver (EntityResolver resolver)
140        {
141            xmlReader.setEntityResolver(resolver);
142        }
143    
144    
145        /**
146         * Register the DTD event handler.
147         *
148         * @param handler The new DTD event handler.
149         * @see org.xml.sax.Parser#setDTDHandler
150         */
151        public void setDTDHandler (DTDHandler handler)
152        {
153            xmlReader.setDTDHandler(handler);
154        }
155    
156    
157        /**
158         * Register the SAX1 document event handler.
159         *
160         * <p>Note that the SAX1 document handler has no Namespace
161         * support.</p>
162         *
163         * @param handler The new SAX1 document event handler.
164         * @see org.xml.sax.Parser#setDocumentHandler
165         */
166        public void setDocumentHandler (DocumentHandler handler)
167        {
168            documentHandler = handler;
169        }
170    
171    
172        /**
173         * Register the error event handler.
174         *
175         * @param handler The new error event handler.
176         * @see org.xml.sax.Parser#setErrorHandler
177         */
178        public void setErrorHandler (ErrorHandler handler)
179        {
180            xmlReader.setErrorHandler(handler);
181        }
182    
183    
184        /**
185         * Parse the document.
186         *
187         * <p>This method will throw an exception if the embedded
188         * XMLReader does not support the 
189         * http://xml.org/sax/features/namespace-prefixes property.</p>
190         *
191         * @param systemId The absolute URL of the document.
192         * @exception java.io.IOException If there is a problem reading
193         *            the raw content of the document.
194         * @exception org.xml.sax.SAXException If there is a problem
195         *            processing the document.
196         * @see #parse(org.xml.sax.InputSource)
197         * @see org.xml.sax.Parser#parse(java.lang.String)
198         */
199        public void parse (String systemId)
200            throws IOException, SAXException
201        {
202            parse(new InputSource(systemId));
203        }
204    
205    
206        /**
207         * Parse the document.
208         *
209         * <p>This method will throw an exception if the embedded
210         * XMLReader does not support the 
211         * http://xml.org/sax/features/namespace-prefixes property.</p>
212         *
213         * @param input An input source for the document.
214         * @exception java.io.IOException If there is a problem reading
215         *            the raw content of the document.
216         * @exception org.xml.sax.SAXException If there is a problem
217         *            processing the document.
218         * @see #parse(java.lang.String)
219         * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
220         */
221        public void parse (InputSource input)
222            throws IOException, SAXException
223        {
224            setupXMLReader();
225            xmlReader.parse(input);
226        }
227    
228    
229        /**
230         * Set up the XML reader.
231         */
232        private void setupXMLReader ()
233            throws SAXException
234        {
235            xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
236            try {
237                xmlReader.setFeature("http://xml.org/sax/features/namespaces",
238                                     false);
239            } catch (SAXException e) {
240                // NO OP: it's just extra information, and we can ignore it
241            }
242            xmlReader.setContentHandler(this);
243        }
244    
245    
246    
247        ////////////////////////////////////////////////////////////////////
248        // Implementation of org.xml.sax.ContentHandler.
249        ////////////////////////////////////////////////////////////////////
250    
251    
252        /**
253         * Set a document locator.
254         *
255         * @param locator The document locator.
256         * @see org.xml.sax.ContentHandler#setDocumentLocator
257         */
258        public void setDocumentLocator (Locator locator)
259        {
260            if (documentHandler != null)
261                documentHandler.setDocumentLocator(locator);
262        }
263    
264    
265        /**
266         * Start document event.
267         *
268         * @exception org.xml.sax.SAXException The client may raise a
269         *            processing exception.
270         * @see org.xml.sax.ContentHandler#startDocument
271         */
272        public void startDocument ()
273            throws SAXException
274        {
275            if (documentHandler != null)
276                documentHandler.startDocument();
277        }
278    
279    
280        /**
281         * End document event.
282         *
283         * @exception org.xml.sax.SAXException The client may raise a
284         *            processing exception.
285         * @see org.xml.sax.ContentHandler#endDocument
286         */
287        public void endDocument ()
288            throws SAXException
289        {
290            if (documentHandler != null)
291                documentHandler.endDocument();
292        }
293    
294    
295        /**
296         * Adapt a SAX2 start prefix mapping event.
297         *
298         * @param prefix The prefix being mapped.
299         * @param uri The Namespace URI being mapped to.
300         * @see org.xml.sax.ContentHandler#startPrefixMapping
301         */
302        public void startPrefixMapping (String prefix, String uri)
303        {
304        }
305    
306    
307        /**
308         * Adapt a SAX2 end prefix mapping event.
309         *
310         * @param prefix The prefix being mapped.
311         * @see org.xml.sax.ContentHandler#endPrefixMapping
312         */
313        public void endPrefixMapping (String prefix)
314        {
315        }
316    
317    
318        /**
319         * Adapt a SAX2 start element event.
320         *
321         * @param uri The Namespace URI.
322         * @param localName The Namespace local name.
323         * @param qName The qualified (prefixed) name.
324         * @param atts The SAX2 attributes.
325         * @exception org.xml.sax.SAXException The client may raise a
326         *            processing exception.
327         * @see org.xml.sax.ContentHandler#endDocument
328         */
329        public void startElement (String uri, String localName,
330                                  String qName, Attributes atts)
331            throws SAXException
332        {
333            if (documentHandler != null) {
334                qAtts.setAttributes(atts);
335                documentHandler.startElement(qName, qAtts);
336            }
337        }
338    
339    
340        /**
341         * Adapt a SAX2 end element event.
342         *
343         * @param uri The Namespace URI.
344         * @param localName The Namespace local name.
345         * @param qName The qualified (prefixed) name.
346         * @exception org.xml.sax.SAXException The client may raise a
347         *            processing exception.
348         * @see org.xml.sax.ContentHandler#endElement
349         */
350        public void endElement (String uri, String localName,
351                                String qName)
352            throws SAXException
353        {
354            if (documentHandler != null)
355                documentHandler.endElement(qName);
356        }
357    
358    
359        /**
360         * Adapt a SAX2 characters event.
361         *
362         * @param ch An array of characters.
363         * @param start The starting position in the array.
364         * @param length The number of characters to use.
365         * @exception org.xml.sax.SAXException The client may raise a
366         *            processing exception.
367         * @see org.xml.sax.ContentHandler#characters
368         */
369        public void characters (char ch[], int start, int length)
370            throws SAXException
371        {
372            if (documentHandler != null)
373                documentHandler.characters(ch, start, length);
374        }
375    
376    
377        /**
378         * Adapt a SAX2 ignorable whitespace event.
379         *
380         * @param ch An array of characters.
381         * @param start The starting position in the array.
382         * @param length The number of characters to use.
383         * @exception org.xml.sax.SAXException The client may raise a
384         *            processing exception.
385         * @see org.xml.sax.ContentHandler#ignorableWhitespace
386         */
387        public void ignorableWhitespace (char ch[], int start, int length)
388            throws SAXException
389        {
390            if (documentHandler != null)
391                documentHandler.ignorableWhitespace(ch, start, length);
392        }
393    
394    
395        /**
396         * Adapt a SAX2 processing instruction event.
397         *
398         * @param target The processing instruction target.
399         * @param data The remainder of the processing instruction
400         * @exception org.xml.sax.SAXException The client may raise a
401         *            processing exception.
402         * @see org.xml.sax.ContentHandler#processingInstruction
403         */
404        public void processingInstruction (String target, String data)
405            throws SAXException
406        {
407            if (documentHandler != null)
408                documentHandler.processingInstruction(target, data);
409        }
410    
411    
412        /**
413         * Adapt a SAX2 skipped entity event.
414         *
415         * @param name The name of the skipped entity.
416         * @see org.xml.sax.ContentHandler#skippedEntity
417         * @exception org.xml.sax.SAXException Throwable by subclasses.
418         */
419        public void skippedEntity (String name)
420            throws SAXException
421        {
422        }
423    
424    
425    
426        ////////////////////////////////////////////////////////////////////
427        // Internal state.
428        ////////////////////////////////////////////////////////////////////
429    
430        XMLReader xmlReader;
431        DocumentHandler documentHandler;
432        AttributesAdapter qAtts;
433    
434    
435    
436        ////////////////////////////////////////////////////////////////////
437        // Internal class.
438        ////////////////////////////////////////////////////////////////////
439    
440    
441        /**
442         * Internal class to wrap a SAX2 Attributes object for SAX1.
443         */
444        final class AttributesAdapter implements AttributeList
445        {
446            AttributesAdapter ()
447            {
448            }
449    
450    
451            /**
452             * Set the embedded Attributes object.
453             *
454             * @param The embedded SAX2 Attributes.
455             */ 
456            void setAttributes (Attributes attributes)
457            {
458                this.attributes = attributes;
459            }
460    
461    
462            /**
463             * Return the number of attributes.
464             *
465             * @return The length of the attribute list.
466             * @see org.xml.sax.AttributeList#getLength
467             */
468            public int getLength ()
469            {
470                return attributes.getLength();
471            }
472    
473    
474            /**
475             * Return the qualified (prefixed) name of an attribute by position.
476             *
477             * @return The qualified name.
478             * @see org.xml.sax.AttributeList#getName
479             */
480            public String getName (int i)
481            {
482                return attributes.getQName(i);
483            }
484    
485    
486            /**
487             * Return the type of an attribute by position.
488             *
489             * @return The type.
490             * @see org.xml.sax.AttributeList#getType(int)
491             */
492            public String getType (int i)
493            {
494                return attributes.getType(i);
495            }
496    
497    
498            /**
499             * Return the value of an attribute by position.
500             *
501             * @return The value.
502             * @see org.xml.sax.AttributeList#getValue(int)
503             */
504            public String getValue (int i)
505            {
506                return attributes.getValue(i);
507            }
508    
509    
510            /**
511             * Return the type of an attribute by qualified (prefixed) name.
512             *
513             * @return The type.
514             * @see org.xml.sax.AttributeList#getType(java.lang.String)
515             */
516            public String getType (String qName)
517            {
518                return attributes.getType(qName);
519            }
520    
521    
522            /**
523             * Return the value of an attribute by qualified (prefixed) name.
524             *
525             * @return The value.
526             * @see org.xml.sax.AttributeList#getValue(java.lang.String)
527             */
528            public String getValue (String qName)
529            {
530                return attributes.getValue(qName);
531            }
532    
533            private Attributes attributes;
534        }
535    
536    }
537    
538    // end of XMLReaderAdapter.java