Home | History | Annotate | Download | only in helpers
      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     ////////////////////////////////////////////////////////////////////
     56     // Constructor.
     57     ////////////////////////////////////////////////////////////////////
     58 
     59 
     60     /**
     61      * Create a new adapter.
     62      *
     63      * <p>Use the "org.xml.sax.driver" property to locate the SAX2
     64      * driver to embed.</p>
     65      *
     66      * @exception org.xml.sax.SAXException If the embedded driver
     67      *            cannot be instantiated or if the
     68      *            org.xml.sax.driver property is not specified.
     69      */
     70     public XMLReaderAdapter ()
     71       throws SAXException
     72     {
     73     setup(XMLReaderFactory.createXMLReader());
     74     }
     75 
     76 
     77     /**
     78      * Create a new adapter.
     79      *
     80      * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
     81      * The adapter will make the XMLReader act like a SAX1
     82      * Parser.</p>
     83      *
     84      * @param xmlReader The SAX2 XMLReader to wrap.
     85      * @exception java.lang.NullPointerException If the argument is null.
     86      */
     87     public XMLReaderAdapter (XMLReader xmlReader)
     88     {
     89     setup(xmlReader);
     90     }
     91 
     92 
     93 
     94     /**
     95      * Internal setup.
     96      *
     97      * @param xmlReader The embedded XMLReader.
     98      */
     99     private void setup (XMLReader xmlReader)
    100     {
    101     if (xmlReader == null) {
    102         throw new NullPointerException("XMLReader must not be null");
    103     }
    104     this.xmlReader = xmlReader;
    105     qAtts = new AttributesAdapter();
    106     }
    107 
    108 
    109 
    110     ////////////////////////////////////////////////////////////////////
    111     // Implementation of org.xml.sax.Parser.
    112     ////////////////////////////////////////////////////////////////////
    113 
    114 
    115     /**
    116      * Set the locale for error reporting.
    117      *
    118      * <p>This is not supported in SAX2, and will always throw
    119      * an exception.</p>
    120      *
    121      * @param locale the locale for error reporting.
    122      * @see org.xml.sax.Parser#setLocale
    123      * @exception org.xml.sax.SAXException Thrown unless overridden.
    124      */
    125     public void setLocale (Locale locale)
    126     throws SAXException
    127     {
    128     throw new SAXNotSupportedException("setLocale not supported");
    129     }
    130 
    131 
    132     /**
    133      * Register the entity resolver.
    134      *
    135      * @param resolver The new resolver.
    136      * @see org.xml.sax.Parser#setEntityResolver
    137      */
    138     public void setEntityResolver (EntityResolver resolver)
    139     {
    140     xmlReader.setEntityResolver(resolver);
    141     }
    142 
    143 
    144     /**
    145      * Register the DTD event handler.
    146      *
    147      * @param handler The new DTD event handler.
    148      * @see org.xml.sax.Parser#setDTDHandler
    149      */
    150     public void setDTDHandler (DTDHandler handler)
    151     {
    152     xmlReader.setDTDHandler(handler);
    153     }
    154 
    155 
    156     /**
    157      * Register the SAX1 document event handler.
    158      *
    159      * <p>Note that the SAX1 document handler has no Namespace
    160      * support.</p>
    161      *
    162      * @param handler The new SAX1 document event handler.
    163      * @see org.xml.sax.Parser#setDocumentHandler
    164      */
    165     public void setDocumentHandler (DocumentHandler handler)
    166     {
    167     documentHandler = handler;
    168     }
    169 
    170 
    171     /**
    172      * Register the error event handler.
    173      *
    174      * @param handler The new error event handler.
    175      * @see org.xml.sax.Parser#setErrorHandler
    176      */
    177     public void setErrorHandler (ErrorHandler handler)
    178     {
    179     xmlReader.setErrorHandler(handler);
    180     }
    181 
    182 
    183     /**
    184      * Parse the document.
    185      *
    186      * <p>This method will throw an exception if the embedded
    187      * XMLReader does not support the
    188      * http://xml.org/sax/features/namespace-prefixes property.</p>
    189      *
    190      * @param systemId The absolute URL of the document.
    191      * @exception java.io.IOException If there is a problem reading
    192      *            the raw content of the document.
    193      * @exception org.xml.sax.SAXException If there is a problem
    194      *            processing the document.
    195      * @see #parse(org.xml.sax.InputSource)
    196      * @see org.xml.sax.Parser#parse(java.lang.String)
    197      */
    198     public void parse (String systemId)
    199     throws IOException, SAXException
    200     {
    201     parse(new InputSource(systemId));
    202     }
    203 
    204 
    205     /**
    206      * Parse the document.
    207      *
    208      * <p>This method will throw an exception if the embedded
    209      * XMLReader does not support the
    210      * http://xml.org/sax/features/namespace-prefixes property.</p>
    211      *
    212      * @param input An input source for the document.
    213      * @exception java.io.IOException If there is a problem reading
    214      *            the raw content of the document.
    215      * @exception org.xml.sax.SAXException If there is a problem
    216      *            processing the document.
    217      * @see #parse(java.lang.String)
    218      * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
    219      */
    220     public void parse (InputSource input)
    221     throws IOException, SAXException
    222     {
    223     setupXMLReader();
    224     xmlReader.parse(input);
    225     }
    226 
    227 
    228     /**
    229      * Set up the XML reader.
    230      */
    231     private void setupXMLReader ()
    232     throws SAXException
    233     {
    234     xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
    235     try {
    236         xmlReader.setFeature("http://xml.org/sax/features/namespaces",
    237                              false);
    238     } catch (SAXException e) {
    239         // NO OP: it's just extra information, and we can ignore it
    240     }
    241     xmlReader.setContentHandler(this);
    242     }
    243 
    244 
    245 
    246     ////////////////////////////////////////////////////////////////////
    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     ////////////////////////////////////////////////////////////////////
    428     // Internal state.
    429     ////////////////////////////////////////////////////////////////////
    430 
    431     XMLReader xmlReader;
    432     DocumentHandler documentHandler;
    433     AttributesAdapter qAtts;
    434 
    435 
    436 
    437     ////////////////////////////////////////////////////////////////////
    439     // Internal class.
    440     ////////////////////////////////////////////////////////////////////
    441 
    442 
    443     /**
    444      * Internal class to wrap a SAX2 Attributes object for SAX1.
    445      */
    446     static final class AttributesAdapter implements AttributeList
    447     {
    448     AttributesAdapter ()
    449     {
    450     }
    451 
    452 
    453     /**
    454      * Set the embedded Attributes object.
    455      *
    456      * @param The embedded SAX2 Attributes.
    457      */
    458     void setAttributes (Attributes attributes)
    459     {
    460         this.attributes = attributes;
    461     }
    462 
    463 
    464     /**
    465      * Return the number of attributes.
    466      *
    467      * @return The length of the attribute list.
    468      * @see org.xml.sax.AttributeList#getLength
    469      */
    470     public int getLength ()
    471     {
    472         return attributes.getLength();
    473     }
    474 
    475 
    476     /**
    477      * Return the qualified (prefixed) name of an attribute by position.
    478      *
    479      * @return The qualified name.
    480      * @see org.xml.sax.AttributeList#getName
    481      */
    482     public String getName (int i)
    483     {
    484         return attributes.getQName(i);
    485     }
    486 
    487 
    488     /**
    489      * Return the type of an attribute by position.
    490      *
    491      * @return The type.
    492      * @see org.xml.sax.AttributeList#getType(int)
    493      */
    494     public String getType (int i)
    495     {
    496         return attributes.getType(i);
    497     }
    498 
    499 
    500     /**
    501      * Return the value of an attribute by position.
    502      *
    503      * @return The value.
    504      * @see org.xml.sax.AttributeList#getValue(int)
    505      */
    506     public String getValue (int i)
    507     {
    508         return attributes.getValue(i);
    509     }
    510 
    511 
    512     /**
    513      * Return the type of an attribute by qualified (prefixed) name.
    514      *
    515      * @return The type.
    516      * @see org.xml.sax.AttributeList#getType(java.lang.String)
    517      */
    518     public String getType (String qName)
    519     {
    520         return attributes.getType(qName);
    521     }
    522 
    523 
    524     /**
    525      * Return the value of an attribute by qualified (prefixed) name.
    526      *
    527      * @return The value.
    528      * @see org.xml.sax.AttributeList#getValue(java.lang.String)
    529      */
    530     public String getValue (String qName)
    531     {
    532         return attributes.getValue(qName);
    533     }
    534 
    535     private Attributes attributes;
    536     }
    537 
    538 }
    539 
    540 // end of XMLReaderAdapter.java
    541