Home | History | Annotate | Download | only in helpers
      1 // ParserAdapter.java - adapt a SAX1 Parser to a SAX2 XMLReader.
      2 // http://www.saxproject.org
      3 // Written by David Megginson
      4 // NO WARRANTY!  This class is in the public domain.
      5 // $Id: ParserAdapter.java,v 1.16 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.ArrayList;
     11 import java.util.Enumeration;
     12 import org.xml.sax.AttributeList;
     13 import org.xml.sax.Attributes;
     14 import org.xml.sax.ContentHandler;
     15 import org.xml.sax.DTDHandler;
     16 import org.xml.sax.DocumentHandler;
     17 import org.xml.sax.EntityResolver;
     18 import org.xml.sax.ErrorHandler;
     19 import org.xml.sax.InputSource;
     20 import org.xml.sax.Locator;
     21 import org.xml.sax.Parser;
     22 import org.xml.sax.SAXException;
     23 import org.xml.sax.SAXNotRecognizedException;
     24 import org.xml.sax.SAXNotSupportedException;
     25 import org.xml.sax.SAXParseException;
     26 import org.xml.sax.XMLReader;
     27 
     28 
     29 /**
     30  * Adapt a SAX1 Parser as a SAX2 XMLReader.
     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 SAX1 {@link org.xml.sax.Parser Parser}
     40  * and makes it act as a SAX2 {@link org.xml.sax.XMLReader XMLReader},
     41  * with feature, property, and Namespace support.  Note
     42  * that it is not possible to report {@link org.xml.sax.ContentHandler#skippedEntity
     43  * skippedEntity} events, since SAX1 does not make that information available.</p>
     44  *
     45  * <p>This adapter does not test for duplicate Namespace-qualified
     46  * attribute names.</p>
     47  *
     48  * @since SAX 2.0
     49  * @author David Megginson
     50  * @version 2.0.1 (sax2r2)
     51  * @see org.xml.sax.helpers.XMLReaderAdapter
     52  * @see org.xml.sax.XMLReader
     53  * @see org.xml.sax.Parser
     54  */
     55 public class ParserAdapter implements XMLReader, DocumentHandler
     56 {
     57 
     58 
     59     ////////////////////////////////////////////////////////////////////
     61     // Constructors.
     62     ////////////////////////////////////////////////////////////////////
     63 
     64 
     65     /**
     66      * Construct a new parser adapter.
     67      *
     68      * <p>Use the "org.xml.sax.parser" property to locate the
     69      * embedded SAX1 driver.</p>
     70      *
     71      * @exception SAXException If the embedded driver
     72      *            cannot be instantiated or if the
     73      *            org.xml.sax.parser property is not specified.
     74      */
     75     public ParserAdapter ()
     76       throws SAXException
     77     {
     78 
     79     String driver = System.getProperty("org.xml.sax.parser");
     80 
     81     try {
     82         setup(ParserFactory.makeParser());
     83     } catch (ClassNotFoundException e1) {
     84         throw new
     85         SAXException("Cannot find SAX1 driver class " +
     86                  driver, e1);
     87     } catch (IllegalAccessException e2) {
     88         throw new
     89         SAXException("SAX1 driver class " +
     90                  driver +
     91                  " found but cannot be loaded", e2);
     92     } catch (InstantiationException e3) {
     93         throw new
     94         SAXException("SAX1 driver class " +
     95                  driver +
     96                  " loaded but cannot be instantiated", e3);
     97     } catch (ClassCastException e4) {
     98         throw new
     99         SAXException("SAX1 driver class " +
    100                  driver +
    101                  " does not implement org.xml.sax.Parser");
    102     } catch (NullPointerException e5) {
    103         throw new
    104         SAXException("System property org.xml.sax.parser not specified");
    105     }
    106     }
    107 
    108 
    109     /**
    110      * Construct a new parser adapter.
    111      *
    112      * <p>Note that the embedded parser cannot be changed once the
    113      * adapter is created; to embed a different parser, allocate
    114      * a new ParserAdapter.</p>
    115      *
    116      * @param parser The SAX1 parser to embed.
    117      * @exception java.lang.NullPointerException If the parser parameter
    118      *            is null.
    119      */
    120     public ParserAdapter (Parser parser)
    121     {
    122     setup(parser);
    123     }
    124 
    125 
    126     /**
    127      * Internal setup method.
    128      *
    129      * @param parser The embedded parser.
    130      * @exception java.lang.NullPointerException If the parser parameter
    131      *            is null.
    132      */
    133     private void setup (Parser parser)
    134     {
    135     if (parser == null) {
    136         throw new
    137         NullPointerException("Parser argument must not be null");
    138     }
    139     this.parser = parser;
    140     atts = new AttributesImpl();
    141     nsSupport = new NamespaceSupport();
    142     attAdapter = new AttributeListAdapter();
    143     }
    144 
    145 
    146 
    147     ////////////////////////////////////////////////////////////////////
    149     // Implementation of org.xml.sax.XMLReader.
    150     ////////////////////////////////////////////////////////////////////
    151 
    152 
    153     //
    154     // Internal constants for the sake of convenience.
    155     //
    156     private static final String FEATURES = "http://xml.org/sax/features/";
    157     private static final String NAMESPACES = FEATURES + "namespaces";
    158     private static final String NAMESPACE_PREFIXES = FEATURES + "namespace-prefixes";
    159     private static final String XMLNS_URIs = FEATURES + "xmlns-uris";
    160 
    161 
    162     /**
    163      * Set a feature flag for the parser.
    164      *
    165      * <p>The only features recognized are namespaces and
    166      * namespace-prefixes.</p>
    167      *
    168      * @param name The feature name, as a complete URI.
    169      * @param value The requested feature value.
    170      * @exception SAXNotRecognizedException If the feature
    171      *            can't be assigned or retrieved.
    172      * @exception SAXNotSupportedException If the feature
    173      *            can't be assigned that value.
    174      * @see org.xml.sax.XMLReader#setFeature
    175      */
    176     public void setFeature (String name, boolean value)
    177     throws SAXNotRecognizedException, SAXNotSupportedException
    178     {
    179     if (name.equals(NAMESPACES)) {
    180         checkNotParsing("feature", name);
    181         namespaces = value;
    182         if (!namespaces && !prefixes) {
    183         prefixes = true;
    184         }
    185     } else if (name.equals(NAMESPACE_PREFIXES)) {
    186         checkNotParsing("feature", name);
    187         prefixes = value;
    188         if (!prefixes && !namespaces) {
    189         namespaces = true;
    190         }
    191     } else if (name.equals(XMLNS_URIs)) {
    192         checkNotParsing("feature", name);
    193         uris = value;
    194     } else {
    195         throw new SAXNotRecognizedException("Feature: " + name);
    196     }
    197     }
    198 
    199 
    200     /**
    201      * Check a parser feature flag.
    202      *
    203      * <p>The only features recognized are namespaces and
    204      * namespace-prefixes.</p>
    205      *
    206      * @param name The feature name, as a complete URI.
    207      * @return The current feature value.
    208      * @exception SAXNotRecognizedException If the feature
    209      *            value can't be assigned or retrieved.
    210      * @exception SAXNotSupportedException If the
    211      *            feature is not currently readable.
    212      * @see org.xml.sax.XMLReader#setFeature
    213      */
    214     public boolean getFeature (String name)
    215     throws SAXNotRecognizedException, SAXNotSupportedException
    216     {
    217     if (name.equals(NAMESPACES)) {
    218         return namespaces;
    219     } else if (name.equals(NAMESPACE_PREFIXES)) {
    220         return prefixes;
    221     } else if (name.equals(XMLNS_URIs)) {
    222         return uris;
    223     } else {
    224         throw new SAXNotRecognizedException("Feature: " + name);
    225     }
    226     }
    227 
    228 
    229     /**
    230      * Set a parser property.
    231      *
    232      * <p>No properties are currently recognized.</p>
    233      *
    234      * @param name The property name.
    235      * @param value The property value.
    236      * @exception SAXNotRecognizedException If the property
    237      *            value can't be assigned or retrieved.
    238      * @exception SAXNotSupportedException If the property
    239      *            can't be assigned that value.
    240      * @see org.xml.sax.XMLReader#setProperty
    241      */
    242     public void setProperty (String name, Object value)
    243     throws SAXNotRecognizedException, SAXNotSupportedException
    244     {
    245     throw new SAXNotRecognizedException("Property: " + name);
    246     }
    247 
    248 
    249     /**
    250      * Get a parser property.
    251      *
    252      * <p>No properties are currently recognized.</p>
    253      *
    254      * @param name The property name.
    255      * @return The property value.
    256      * @exception SAXNotRecognizedException If the property
    257      *            value can't be assigned or retrieved.
    258      * @exception SAXNotSupportedException If the property
    259      *            value is not currently readable.
    260      * @see org.xml.sax.XMLReader#getProperty
    261      */
    262     public Object getProperty (String name)
    263     throws SAXNotRecognizedException, SAXNotSupportedException
    264     {
    265     throw new SAXNotRecognizedException("Property: " + name);
    266     }
    267 
    268 
    269     /**
    270      * Set the entity resolver.
    271      *
    272      * @param resolver The new entity resolver.
    273      * @see org.xml.sax.XMLReader#setEntityResolver
    274      */
    275     public void setEntityResolver (EntityResolver resolver)
    276     {
    277     entityResolver = resolver;
    278     }
    279 
    280 
    281     /**
    282      * Return the current entity resolver.
    283      *
    284      * @return The current entity resolver, or null if none was supplied.
    285      * @see org.xml.sax.XMLReader#getEntityResolver
    286      */
    287     public EntityResolver getEntityResolver ()
    288     {
    289     return entityResolver;
    290     }
    291 
    292 
    293     /**
    294      * Set the DTD handler.
    295      *
    296      * @param handler the new DTD handler
    297      * @see org.xml.sax.XMLReader#setEntityResolver
    298      */
    299     public void setDTDHandler (DTDHandler handler)
    300     {
    301     dtdHandler = handler;
    302     }
    303 
    304 
    305     /**
    306      * Return the current DTD handler.
    307      *
    308      * @return the current DTD handler, or null if none was supplied
    309      * @see org.xml.sax.XMLReader#getEntityResolver
    310      */
    311     public DTDHandler getDTDHandler ()
    312     {
    313     return dtdHandler;
    314     }
    315 
    316 
    317     /**
    318      * Set the content handler.
    319      *
    320      * @param handler the new content handler
    321      * @see org.xml.sax.XMLReader#setEntityResolver
    322      */
    323     public void setContentHandler (ContentHandler handler)
    324     {
    325     contentHandler = handler;
    326     }
    327 
    328 
    329     /**
    330      * Return the current content handler.
    331      *
    332      * @return The current content handler, or null if none was supplied.
    333      * @see org.xml.sax.XMLReader#getEntityResolver
    334      */
    335     public ContentHandler getContentHandler ()
    336     {
    337     return contentHandler;
    338     }
    339 
    340 
    341     /**
    342      * Set the error handler.
    343      *
    344      * @param handler The new error handler.
    345      * @see org.xml.sax.XMLReader#setEntityResolver
    346      */
    347     public void setErrorHandler (ErrorHandler handler)
    348     {
    349     errorHandler = handler;
    350     }
    351 
    352 
    353     /**
    354      * Return the current error handler.
    355      *
    356      * @return The current error handler, or null if none was supplied.
    357      * @see org.xml.sax.XMLReader#getEntityResolver
    358      */
    359     public ErrorHandler getErrorHandler ()
    360     {
    361     return errorHandler;
    362     }
    363 
    364 
    365     /**
    366      * Parse an XML document.
    367      *
    368      * @param systemId The absolute URL of the document.
    369      * @exception java.io.IOException If there is a problem reading
    370      *            the raw content of the document.
    371      * @exception SAXException If there is a problem
    372      *            processing the document.
    373      * @see #parse(org.xml.sax.InputSource)
    374      * @see org.xml.sax.Parser#parse(java.lang.String)
    375      */
    376     public void parse (String systemId)
    377     throws IOException, SAXException
    378     {
    379     parse(new InputSource(systemId));
    380     }
    381 
    382 
    383     /**
    384      * Parse an XML document.
    385      *
    386      * @param input An input source for the document.
    387      * @exception java.io.IOException If there is a problem reading
    388      *            the raw content of the document.
    389      * @exception SAXException If there is a problem
    390      *            processing the document.
    391      * @see #parse(java.lang.String)
    392      * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
    393      */
    394     public void parse (InputSource input)
    395     throws IOException, SAXException
    396     {
    397     if (parsing) {
    398         throw new SAXException("Parser is already in use");
    399     }
    400     setupParser();
    401     parsing = true;
    402     try {
    403         parser.parse(input);
    404     } finally {
    405         parsing = false;
    406     }
    407     parsing = false;
    408     }
    409 
    410 
    411 
    412     ////////////////////////////////////////////////////////////////////
    413     // Implementation of org.xml.sax.DocumentHandler.
    414     ////////////////////////////////////////////////////////////////////
    415 
    416 
    417     /**
    418      * Adapter implementation method; do not call.
    419      * Adapt a SAX1 document locator event.
    420      *
    421      * @param locator A document locator.
    422      * @see org.xml.sax.ContentHandler#setDocumentLocator
    423      */
    424     public void setDocumentLocator (Locator locator)
    425     {
    426     this.locator = locator;
    427     if (contentHandler != null) {
    428         contentHandler.setDocumentLocator(locator);
    429     }
    430     }
    431 
    432 
    433     /**
    434      * Adapter implementation method; do not call.
    435      * Adapt a SAX1 start document event.
    436      *
    437      * @exception SAXException The client may raise a
    438      *            processing exception.
    439      * @see org.xml.sax.DocumentHandler#startDocument
    440      */
    441     public void startDocument ()
    442     throws SAXException
    443     {
    444     if (contentHandler != null) {
    445         contentHandler.startDocument();
    446     }
    447     }
    448 
    449 
    450     /**
    451      * Adapter implementation method; do not call.
    452      * Adapt a SAX1 end document event.
    453      *
    454      * @exception SAXException The client may raise a
    455      *            processing exception.
    456      * @see org.xml.sax.DocumentHandler#endDocument
    457      */
    458     public void endDocument ()
    459     throws SAXException
    460     {
    461     if (contentHandler != null) {
    462         contentHandler.endDocument();
    463     }
    464     }
    465 
    466 
    467     /**
    468      * Adapter implementation method; do not call.
    469      * Adapt a SAX1 startElement event.
    470      *
    471      * <p>If necessary, perform Namespace processing.</p>
    472      *
    473      * @param qName The qualified (prefixed) name.
    474      * @param qAtts The XML attribute list (with qnames).
    475      * @exception SAXException The client may raise a
    476      *            processing exception.
    477      */
    478     public void startElement (String qName, AttributeList qAtts) throws SAXException {
    479         // These are exceptions from the
    480         // first pass; they should be
    481         // ignored if there's a second pass,
    482         // but reported otherwise.
    483         ArrayList<SAXParseException> exceptions = null;
    484 
    485                 // If we're not doing Namespace
    486                 // processing, dispatch this quickly.
    487     if (!namespaces) {
    488         if (contentHandler != null) {
    489         attAdapter.setAttributeList(qAtts);
    490         contentHandler.startElement("", "", qName.intern(),
    491                         attAdapter);
    492         }
    493         return;
    494     }
    495 
    496 
    497                 // OK, we're doing Namespace processing.
    498     nsSupport.pushContext();
    499     int length = qAtts.getLength();
    500 
    501                 // First pass:  handle NS decls
    502     for (int i = 0; i < length; i++) {
    503         String attQName = qAtts.getName(i);
    504 
    505         if (!attQName.startsWith("xmlns"))
    506         continue;
    507                 // Could be a declaration...
    508         String prefix;
    509         int n = attQName.indexOf(':');
    510 
    511                     // xmlns=...
    512         if (n == -1 && attQName.length () == 5) {
    513         prefix = "";
    514         } else if (n != 5) {
    515         // XML namespaces spec doesn't discuss "xmlnsf:oo"
    516         // (and similarly named) attributes ... at most, warn
    517         continue;
    518         } else         // xmlns:foo=...
    519         prefix = attQName.substring(n+1);
    520 
    521         String value = qAtts.getValue(i);
    522         if (!nsSupport.declarePrefix(prefix, value)) {
    523         reportError("Illegal Namespace prefix: " + prefix);
    524         continue;
    525         }
    526         if (contentHandler != null)
    527         contentHandler.startPrefixMapping(prefix, value);
    528     }
    529 
    530                 // Second pass: copy all relevant
    531                 // attributes into the SAX2 AttributeList
    532                 // using updated prefix bindings
    533     atts.clear();
    534     for (int i = 0; i < length; i++) {
    535         String attQName = qAtts.getName(i);
    536         String type = qAtts.getType(i);
    537         String value = qAtts.getValue(i);
    538 
    539                 // Declaration?
    540         if (attQName.startsWith("xmlns")) {
    541         String prefix;
    542         int n = attQName.indexOf(':');
    543 
    544         if (n == -1 && attQName.length () == 5) {
    545             prefix = "";
    546         } else if (n != 5) {
    547             // XML namespaces spec doesn't discuss "xmlnsf:oo"
    548             // (and similarly named) attributes ... ignore
    549             prefix = null;
    550         } else {
    551             prefix = attQName.substring(6);
    552         }
    553                 // Yes, decl:  report or prune
    554         if (prefix != null) {
    555             if (prefixes) {
    556             if (uris)
    557                 // note funky case:  localname can be null
    558                 // when declaring the default prefix, and
    559                 // yet the uri isn't null.
    560                 atts.addAttribute (nsSupport.XMLNS, prefix,
    561                     attQName.intern(), type, value);
    562             else
    563                 atts.addAttribute ("", "",
    564                     attQName.intern(), type, value);
    565             }
    566             continue;
    567         }
    568         }
    569 
    570                 // Not a declaration -- report
    571         try {
    572         String attName[] = processName(attQName, true, true);
    573         atts.addAttribute(attName[0], attName[1], attName[2],
    574                   type, value);
    575         } catch (SAXException e) {
    576             if (exceptions == null) {
    577                 exceptions = new ArrayList<SAXParseException>();
    578             }
    579             exceptions.add((SAXParseException) e);
    580             atts.addAttribute("", attQName, attQName, type, value);
    581         }
    582     }
    583 
    584     // now handle the deferred exception reports
    585     if (exceptions != null && errorHandler != null) {
    586         for (SAXParseException ex : exceptions) {
    587             errorHandler.error(ex);
    588         }
    589     }
    590 
    591                 // OK, finally report the event.
    592     if (contentHandler != null) {
    593         String name[] = processName(qName, false, false);
    594         contentHandler.startElement(name[0], name[1], name[2], atts);
    595     }
    596     }
    597 
    598 
    599     /**
    600      * Adapter implementation method; do not call.
    601      * Adapt a SAX1 end element event.
    602      *
    603      * @param qName The qualified (prefixed) name.
    604      * @exception SAXException The client may raise a
    605      *            processing exception.
    606      * @see org.xml.sax.DocumentHandler#endElement
    607      */
    608     public void endElement (String qName)
    609     throws SAXException
    610     {
    611                 // If we're not doing Namespace
    612                 // processing, dispatch this quickly.
    613     if (!namespaces) {
    614         if (contentHandler != null) {
    615         contentHandler.endElement("", "", qName.intern());
    616         }
    617         return;
    618     }
    619 
    620                 // Split the name.
    621     String names[] = processName(qName, false, false);
    622     if (contentHandler != null) {
    623         contentHandler.endElement(names[0], names[1], names[2]);
    624         Enumeration prefixes = nsSupport.getDeclaredPrefixes();
    625         while (prefixes.hasMoreElements()) {
    626         String prefix = (String)prefixes.nextElement();
    627         contentHandler.endPrefixMapping(prefix);
    628         }
    629     }
    630     nsSupport.popContext();
    631     }
    632 
    633 
    634     /**
    635      * Adapter implementation method; do not call.
    636      * Adapt a SAX1 characters event.
    637      *
    638      * @param ch An array of characters.
    639      * @param start The starting position in the array.
    640      * @param length The number of characters to use.
    641      * @exception SAXException The client may raise a
    642      *            processing exception.
    643      * @see org.xml.sax.DocumentHandler#characters
    644      */
    645     public void characters (char ch[], int start, int length)
    646     throws SAXException
    647     {
    648     if (contentHandler != null) {
    649         contentHandler.characters(ch, start, length);
    650     }
    651     }
    652 
    653 
    654     /**
    655      * Adapter implementation method; do not call.
    656      * Adapt a SAX1 ignorable whitespace event.
    657      *
    658      * @param ch An array of characters.
    659      * @param start The starting position in the array.
    660      * @param length The number of characters to use.
    661      * @exception SAXException The client may raise a
    662      *            processing exception.
    663      * @see org.xml.sax.DocumentHandler#ignorableWhitespace
    664      */
    665     public void ignorableWhitespace (char ch[], int start, int length)
    666     throws SAXException
    667     {
    668     if (contentHandler != null) {
    669         contentHandler.ignorableWhitespace(ch, start, length);
    670     }
    671     }
    672 
    673 
    674     /**
    675      * Adapter implementation method; do not call.
    676      * Adapt a SAX1 processing instruction event.
    677      *
    678      * @param target The processing instruction target.
    679      * @param data The remainder of the processing instruction
    680      * @exception SAXException The client may raise a
    681      *            processing exception.
    682      * @see org.xml.sax.DocumentHandler#processingInstruction
    683      */
    684     public void processingInstruction (String target, String data)
    685     throws SAXException
    686     {
    687     if (contentHandler != null) {
    688         contentHandler.processingInstruction(target, data);
    689     }
    690     }
    691 
    692 
    693 
    694     ////////////////////////////////////////////////////////////////////
    696     // Internal utility methods.
    697     ////////////////////////////////////////////////////////////////////
    698 
    699 
    700     /**
    701      * Initialize the parser before each run.
    702      */
    703     private void setupParser ()
    704     {
    705     // catch an illegal "nonsense" state.
    706     if (!prefixes && !namespaces)
    707         throw new IllegalStateException ();
    708 
    709     nsSupport.reset();
    710     if (uris)
    711         nsSupport.setNamespaceDeclUris (true);
    712 
    713     if (entityResolver != null) {
    714         parser.setEntityResolver(entityResolver);
    715     }
    716     if (dtdHandler != null) {
    717         parser.setDTDHandler(dtdHandler);
    718     }
    719     if (errorHandler != null) {
    720         parser.setErrorHandler(errorHandler);
    721     }
    722     parser.setDocumentHandler(this);
    723     locator = null;
    724     }
    725 
    726 
    727     /**
    728      * Process a qualified (prefixed) name.
    729      *
    730      * <p>If the name has an undeclared prefix, use only the qname
    731      * and make an ErrorHandler.error callback in case the app is
    732      * interested.</p>
    733      *
    734      * @param qName The qualified (prefixed) name.
    735      * @param isAttribute true if this is an attribute name.
    736      * @return The name split into three parts.
    737      * @exception SAXException The client may throw
    738      *            an exception if there is an error callback.
    739      */
    740     private String [] processName (String qName, boolean isAttribute,
    741                    boolean useException)
    742     throws SAXException
    743     {
    744     String parts[] = nsSupport.processName(qName, nameParts,
    745                            isAttribute);
    746     if (parts == null) {
    747         if (useException)
    748         throw makeException("Undeclared prefix: " + qName);
    749         reportError("Undeclared prefix: " + qName);
    750         parts = new String[3];
    751         parts[0] = parts[1] = "";
    752         parts[2] = qName.intern();
    753     }
    754     return parts;
    755     }
    756 
    757 
    758     /**
    759      * Report a non-fatal error.
    760      *
    761      * @param message The error message.
    762      * @exception SAXException The client may throw
    763      *            an exception.
    764      */
    765     void reportError (String message)
    766     throws SAXException
    767     {
    768     if (errorHandler != null)
    769         errorHandler.error(makeException(message));
    770     }
    771 
    772 
    773     /**
    774      * Construct an exception for the current context.
    775      *
    776      * @param message The error message.
    777      */
    778     private SAXParseException makeException (String message)
    779     {
    780     if (locator != null) {
    781         return new SAXParseException(message, locator);
    782     } else {
    783         return new SAXParseException(message, null, null, -1, -1);
    784     }
    785     }
    786 
    787 
    788     /**
    789      * Throw an exception if we are parsing.
    790      *
    791      * <p>Use this method to detect illegal feature or
    792      * property changes.</p>
    793      *
    794      * @param type The type of thing (feature or property).
    795      * @param name The feature or property name.
    796      * @exception SAXNotSupportedException If a
    797      *            document is currently being parsed.
    798      */
    799     private void checkNotParsing (String type, String name)
    800     throws SAXNotSupportedException
    801     {
    802     if (parsing) {
    803         throw new SAXNotSupportedException("Cannot change " +
    804                            type + ' ' +
    805                            name + " while parsing");
    806 
    807     }
    808     }
    809 
    810 
    811 
    812     ////////////////////////////////////////////////////////////////////
    814     // Internal state.
    815     ////////////////////////////////////////////////////////////////////
    816 
    817     private NamespaceSupport nsSupport;
    818     private AttributeListAdapter attAdapter;
    819 
    820     private boolean parsing = false;
    821     private String nameParts[] = new String[3];
    822 
    823     private Parser parser = null;
    824 
    825     private AttributesImpl atts = null;
    826 
    827                 // Features
    828     private boolean namespaces = true;
    829     private boolean prefixes = false;
    830     private boolean uris = false;
    831 
    832                 // Properties
    833 
    834                 // Handlers
    835     Locator locator;
    836 
    837     EntityResolver entityResolver = null;
    838     DTDHandler dtdHandler = null;
    839     ContentHandler contentHandler = null;
    840     ErrorHandler errorHandler = null;
    841 
    842 
    843 
    844     ////////////////////////////////////////////////////////////////////
    846     // Inner class to wrap an AttributeList when not doing NS proc.
    847     ////////////////////////////////////////////////////////////////////
    848 
    849 
    850     /**
    851      * Adapt a SAX1 AttributeList as a SAX2 Attributes object.
    852      *
    853      * <p>This class is in the Public Domain, and comes with NO
    854      * WARRANTY of any kind.</p>
    855      *
    856      * <p>This wrapper class is used only when Namespace support
    857      * is disabled -- it provides pretty much a direct mapping
    858      * from SAX1 to SAX2, except that names and types are
    859      * interned whenever requested.</p>
    860      */
    861     final class AttributeListAdapter implements Attributes
    862     {
    863 
    864     /**
    865      * Construct a new adapter.
    866      */
    867     AttributeListAdapter ()
    868     {
    869     }
    870 
    871 
    872     /**
    873      * Set the embedded AttributeList.
    874      *
    875      * <p>This method must be invoked before any of the others
    876      * can be used.</p>
    877      *
    878      * @param The SAX1 attribute list (with qnames).
    879      */
    880     void setAttributeList (AttributeList qAtts)
    881     {
    882         this.qAtts = qAtts;
    883     }
    884 
    885 
    886     /**
    887      * Return the length of the attribute list.
    888      *
    889      * @return The number of attributes in the list.
    890      * @see org.xml.sax.Attributes#getLength
    891      */
    892     public int getLength ()
    893     {
    894         return qAtts.getLength();
    895     }
    896 
    897 
    898     /**
    899      * Return the Namespace URI of the specified attribute.
    900      *
    901      * @param The attribute's index.
    902      * @return Always the empty string.
    903      * @see org.xml.sax.Attributes#getURI
    904      */
    905     public String getURI (int i)
    906     {
    907         return "";
    908     }
    909 
    910 
    911     /**
    912      * Return the local name of the specified attribute.
    913      *
    914      * @param The attribute's index.
    915      * @return Always the empty string.
    916      * @see org.xml.sax.Attributes#getLocalName
    917      */
    918     public String getLocalName (int i)
    919     {
    920         return "";
    921     }
    922 
    923 
    924     /**
    925      * Return the qualified (prefixed) name of the specified attribute.
    926      *
    927      * @param The attribute's index.
    928      * @return The attribute's qualified name, internalized.
    929      */
    930     public String getQName (int i)
    931     {
    932         return qAtts.getName(i).intern();
    933     }
    934 
    935 
    936     /**
    937      * Return the type of the specified attribute.
    938      *
    939      * @param The attribute's index.
    940      * @return The attribute's type as an internalized string.
    941      */
    942     public String getType (int i)
    943     {
    944         return qAtts.getType(i).intern();
    945     }
    946 
    947 
    948     /**
    949      * Return the value of the specified attribute.
    950      *
    951      * @param The attribute's index.
    952      * @return The attribute's value.
    953      */
    954     public String getValue (int i)
    955     {
    956         return qAtts.getValue(i);
    957     }
    958 
    959 
    960     /**
    961      * Look up an attribute index by Namespace name.
    962      *
    963      * @param uri The Namespace URI or the empty string.
    964      * @param localName The local name.
    965      * @return The attributes index, or -1 if none was found.
    966      * @see org.xml.sax.Attributes#getIndex(java.lang.String,java.lang.String)
    967      */
    968     public int getIndex (String uri, String localName)
    969     {
    970         return -1;
    971     }
    972 
    973 
    974     /**
    975      * Look up an attribute index by qualified (prefixed) name.
    976      *
    977      * @param qName The qualified name.
    978      * @return The attributes index, or -1 if none was found.
    979      * @see org.xml.sax.Attributes#getIndex(java.lang.String)
    980      */
    981     public int getIndex (String qName)
    982     {
    983         int max = atts.getLength();
    984         for (int i = 0; i < max; i++) {
    985         if (qAtts.getName(i).equals(qName)) {
    986             return i;
    987         }
    988         }
    989         return -1;
    990     }
    991 
    992 
    993     /**
    994      * Look up the type of an attribute by Namespace name.
    995      *
    996      * @param uri The Namespace URI
    997      * @param localName The local name.
    998      * @return The attribute's type as an internalized string.
    999      */
   1000     public String getType (String uri, String localName)
   1001     {
   1002         return null;
   1003     }
   1004 
   1005 
   1006     /**
   1007      * Look up the type of an attribute by qualified (prefixed) name.
   1008      *
   1009      * @param qName The qualified name.
   1010      * @return The attribute's type as an internalized string.
   1011      */
   1012     public String getType (String qName)
   1013     {
   1014         return qAtts.getType(qName).intern();
   1015     }
   1016 
   1017 
   1018     /**
   1019      * Look up the value of an attribute by Namespace name.
   1020      *
   1021      * @param uri The Namespace URI
   1022      * @param localName The local name.
   1023      * @return The attribute's value.
   1024      */
   1025     public String getValue (String uri, String localName)
   1026     {
   1027         return null;
   1028     }
   1029 
   1030 
   1031     /**
   1032      * Look up the value of an attribute by qualified (prefixed) name.
   1033      *
   1034      * @param qName The qualified name.
   1035      * @return The attribute's value.
   1036      */
   1037     public String getValue (String qName)
   1038     {
   1039         return qAtts.getValue(qName);
   1040     }
   1041 
   1042     private AttributeList qAtts;
   1043     }
   1044 }
   1045 
   1046 // end of ParserAdapter.java
   1047