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