Source for org.xml.sax.helpers.ParserAdapter

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