Source for gnu.xml.aelfred2.SAXDriver

   1: /* SAXDriver.java -- 
   2:    Copyright (C) 1999,2000,2001,2004 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.
  37: 
  38: Portions derived from code which carried the following notice:
  39: 
  40:   Copyright (c) 1997, 1998 by Microstar Software Ltd.
  41: 
  42:   AElfred is free for both commercial and non-commercial use and
  43:   redistribution, provided that Microstar's copyright and disclaimer are
  44:   retained intact.  You are free to modify AElfred for your own use and
  45:   to redistribute AElfred with your modifications, provided that the
  46:   modifications are clearly documented.
  47: 
  48:   This program is distributed in the hope that it will be useful, but
  49:   WITHOUT ANY WARRANTY; without even the implied warranty of
  50:   merchantability or fitness for a particular purpose.  Please use it AT
  51:   YOUR OWN RISK.
  52: */
  53: 
  54: package gnu.xml.aelfred2;
  55: 
  56: import java.io.*;
  57: 
  58: import java.net.MalformedURLException;
  59: import java.net.URL;
  60: import java.util.Locale;
  61: import java.util.Stack;
  62: 
  63: import java.util.ArrayList;
  64: import java.util.Collections;
  65: import java.util.Enumeration;
  66: import java.util.Iterator;
  67: import java.util.List;
  68: 
  69: import org.xml.sax.*;
  70: import org.xml.sax.ext.*;
  71: import org.xml.sax.helpers.NamespaceSupport;
  72: 
  73: 
  74: /**
  75:  * An enhanced SAX2 version of Microstar's Ælfred XML parser.
  76:  * The enhancements primarily relate to significant improvements in
  77:  * conformance to the XML specification, and SAX2 support.  Performance
  78:  * has been improved.  See the package level documentation for more
  79:  * information.
  80:  *
  81:  * <table border="1" width='100%' cellpadding='3' cellspacing='0'>
  82:  * <tr bgcolor='#ccccff'>
  83:  *    <th><font size='+1'>Name</font></th>
  84:  *    <th><font size='+1'>Notes</font></th></tr>
  85:  *
  86:  * <tr><td colspan=2><center><em>Features ... URL prefix is
  87:  * <b>http://xml.org/sax/features/</b></em></center></td></tr>
  88:  *
  89:  * <tr><td>(URL)/external-general-entities</td>
  90:  *    <td>Value defaults to <em>true</em></td></tr>
  91:  * <tr><td>(URL)/external-parameter-entities</td>
  92:  *    <td>Value defaults to <em>true</em></td></tr>
  93:  * <tr><td>(URL)/is-standalone</td>
  94:  *    <td>(PRELIMINARY) Returns true iff the document's parsing
  95:  *    has started (some non-error event after <em>startDocument()</em>
  96:  *    was reported) and the document's standalone flag is set.</td></tr>
  97:  * <tr><td>(URL)/namespace-prefixes</td>
  98:  *    <td>Value defaults to <em>false</em> (but XML 1.0 names are
  99:  *        always reported)</td></tr>
 100:  * <tr><td>(URL)/lexical-handler/parameter-entities</td>
 101:  *    <td>Value is fixed at <em>true</em></td></tr>
 102:  * <tr><td>(URL)/namespaces</td>
 103:  *    <td>Value defaults to <em>true</em></td></tr>
 104:  * <tr><td>(URL)/resolve-dtd-uris</td>
 105:  *    <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
 106:  * <tr><td>(URL)/string-interning</td>
 107:  *    <td>Value is fixed at <em>true</em></td></tr>
 108:  * <tr><td>(URL)/use-attributes2</td>
 109:  *    <td>(PRELIMINARY) Value is fixed at <em>true</em></td></tr>
 110:  * <tr><td>(URL)/use-entity-resolver2</td>
 111:  *    <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
 112:  * <tr><td>(URL)/validation</td>
 113:  *    <td>Value is fixed at <em>false</em></td></tr>
 114:  *
 115:  * <tr><td colspan=2><center><em>Handler Properties ... URL prefix is
 116:  * <b>http://xml.org/sax/properties/</b></em></center></td></tr>
 117:  *
 118:  * <tr><td>(URL)/declaration-handler</td>
 119:  *    <td>A declaration handler may be provided.  </td></tr>
 120:  * <tr><td>(URL)/lexical-handler</td>
 121:  *    <td>A lexical handler may be provided.  </td></tr>
 122:  * </table>
 123:  *
 124:  * <p>This parser currently implements the SAX1 Parser API, but
 125:  * it may not continue to do so in the future.
 126:  *
 127:  * @author Written by David Megginson (version 1.2a from Microstar)
 128:  * @author Updated by David Brownell &lt;dbrownell@users.sourceforge.net&gt;
 129:  * @see org.xml.sax.Parser
 130:  */
 131: final public class SAXDriver
 132:   implements Locator, Attributes2, XMLReader, Parser, AttributeList
 133: {
 134:   
 135:   private final DefaultHandler2 base = new DefaultHandler2();
 136:   private XmlParser parser;
 137:   
 138:   private EntityResolver entityResolver = base;
 139:   private EntityResolver2 resolver2 = null;
 140:   private ContentHandler contentHandler = base;
 141:   private DTDHandler dtdHandler = base;
 142:   private ErrorHandler errorHandler = base;
 143:   private DeclHandler declHandler = base;
 144:   private LexicalHandler lexicalHandler = base;
 145:   
 146:   private String elementName;
 147:   private Stack entityStack;
 148:   
 149:   // one vector (of object/struct): faster, smaller
 150:   private List attributesList;
 151:   
 152:   private boolean namespaces = true;
 153:   private boolean xmlNames = false;
 154:   private boolean extGE = true;
 155:   private boolean extPE = true;
 156:   private boolean resolveAll = true;
 157:   private boolean useResolver2 = true;
 158:   
 159:   // package private to allow (read-only) access in XmlParser
 160:   boolean stringInterning = true;
 161:   
 162:   private int attributeCount;
 163:   private boolean attributes;
 164:   private String[] nsTemp;
 165:   private NamespaceSupport prefixStack;
 166:   
 167:   //
 168:   // Constructor.
 169:   //
 170: 
 171:   /**
 172:    * Constructs a SAX Parser.
 173:    */
 174:   public SAXDriver()
 175:   {
 176:     reset();
 177:   }
 178: 
 179:   private void reset()
 180:   {
 181:     elementName = null;
 182:     entityStack = new Stack();
 183:     attributesList = Collections.synchronizedList(new ArrayList());
 184:     attributeCount = 0;
 185:     attributes = false;
 186:     nsTemp = new String[3];
 187:     prefixStack = null;
 188:   }
 189: 
 190: 
 191:   //
 192:   // Implementation of org.xml.sax.Parser.
 193:   //
 194: 
 195:   /**
 196:    * <b>SAX1</b>: Sets the locale used for diagnostics; currently,
 197:    * only locales using the English language are supported.
 198:    * @param locale The locale for which diagnostics will be generated
 199:    */
 200:   public void setLocale(Locale locale)
 201:     throws SAXException
 202:   {
 203:     if ("en".equals(locale.getLanguage()))
 204:       {
 205:         return;
 206:       }
 207:     throw new SAXException ("AElfred2 only supports English locales.");
 208:   }
 209: 
 210:   /**
 211:    * <b>SAX2</b>: Returns the object used when resolving external
 212:    * entities during parsing (both general and parameter entities).
 213:    */
 214:   public EntityResolver getEntityResolver()
 215:   {
 216:     return (entityResolver == base) ? null : entityResolver;
 217:   }
 218: 
 219:   /**
 220:    * <b>SAX1, SAX2</b>: Set the entity resolver for this parser.
 221:    * @param handler The object to receive entity events.
 222:    */
 223:   public void setEntityResolver(EntityResolver resolver)
 224:   {
 225:     if (resolver instanceof EntityResolver2)
 226:       {
 227:         resolver2 = (EntityResolver2) resolver;
 228:       }
 229:     else
 230:       {
 231:         resolver2 = null;
 232:       }
 233:     if (resolver == null)
 234:       {
 235:         resolver = base;
 236:       }
 237:     entityResolver = resolver;
 238:   }
 239: 
 240:   /**
 241:    * <b>SAX2</b>: Returns the object used to process declarations related
 242:    * to notations and unparsed entities.
 243:    */
 244:   public DTDHandler getDTDHandler()
 245:   {
 246:     return (dtdHandler == base) ? null : dtdHandler;
 247:   }
 248: 
 249:   /**
 250:    * <b>SAX1, SAX2</b>: Set the DTD handler for this parser.
 251:    * @param handler The object to receive DTD events.
 252:    */
 253:   public void setDTDHandler(DTDHandler handler)
 254:   {
 255:     if (handler == null)
 256:       {
 257:         handler = base;
 258:       }
 259:     this.dtdHandler = handler;
 260:   }
 261: 
 262: 
 263:   /**
 264:    * <b>SAX1</b>: Set the document handler for this parser.  If a
 265:    * content handler was set, this document handler will supplant it.
 266:    * The parser is set to report all XML 1.0 names rather than to
 267:    * filter out "xmlns" attributes (the "namespace-prefixes" feature
 268:    * is set to true).
 269:    *
 270:    * @deprecated SAX2 programs should use the XMLReader interface
 271:    *  and a ContentHandler.
 272:    *
 273:    * @param handler The object to receive document events.
 274:    */
 275:   public void setDocumentHandler(DocumentHandler handler)
 276:   {
 277:     contentHandler = new Adapter(handler);
 278:     xmlNames = true;
 279:   }
 280: 
 281:   /**
 282:    * <b>SAX2</b>: Returns the object used to report the logical
 283:    * content of an XML document.
 284:    */
 285:   public ContentHandler getContentHandler()
 286:   {
 287:     return (contentHandler == base) ? null : contentHandler;
 288:   }
 289: 
 290:   /**
 291:    * <b>SAX2</b>: Assigns the object used to report the logical
 292:    * content of an XML document.  If a document handler was set,
 293:    * this content handler will supplant it (but XML 1.0 style name
 294:    * reporting may remain enabled).
 295:    */
 296:   public void setContentHandler(ContentHandler handler)
 297:   {
 298:     if (handler == null)
 299:       {
 300:         handler = base;
 301:       }
 302:     contentHandler = handler;
 303:   }
 304: 
 305:   /**
 306:    * <b>SAX1, SAX2</b>: Set the error handler for this parser.
 307:    * @param handler The object to receive error events.
 308:    */
 309:   public void setErrorHandler(ErrorHandler handler)
 310:   {
 311:     if (handler == null)
 312:       {
 313:         handler = base;
 314:       }
 315:     this.errorHandler = handler;
 316:   }
 317: 
 318:   /**
 319:    * <b>SAX2</b>: Returns the object used to receive callbacks for XML
 320:    * errors of all levels (fatal, nonfatal, warning); this is never null;
 321:    */
 322:   public ErrorHandler getErrorHandler()
 323:   {
 324:     return (errorHandler == base) ? null : errorHandler;
 325:   }
 326: 
 327:   /**
 328:    * <b>SAX1, SAX2</b>: Auxiliary API to parse an XML document, used mostly
 329:    * when no URI is available.
 330:    * If you want anything useful to happen, you should set
 331:    * at least one type of handler.
 332:    * @param source The XML input source.  Don't set 'encoding' unless
 333:    *  you know for a fact that it's correct.
 334:    * @see #setEntityResolver
 335:    * @see #setDTDHandler
 336:    * @see #setContentHandler
 337:    * @see #setErrorHandler
 338:    * @exception SAXException The handlers may throw any SAXException,
 339:    *  and the parser normally throws SAXParseException objects.
 340:    * @exception IOException IOExceptions are normally through through
 341:    *  the parser if there are problems reading the source document.
 342:    */
 343:   public void parse(InputSource source)
 344:     throws SAXException, IOException
 345:   {
 346:     synchronized (base)
 347:       {
 348:         parser = new XmlParser();
 349:         if (namespaces)
 350:           {
 351:             prefixStack = new NamespaceSupport();
 352:           }
 353:         else if (!xmlNames)
 354:           {
 355:             throw new IllegalStateException();
 356:           }
 357:         parser.setHandler(this);
 358:         
 359:         try
 360:           {
 361:             Reader r = source.getCharacterStream();
 362:             InputStream in = source.getByteStream();
 363:                         
 364:             parser.doParse(source.getSystemId(),
 365:                            source.getPublicId(),
 366:                            r,
 367:                            in,
 368:                            source.getEncoding());
 369:           }
 370:         catch (SAXException e)
 371:           {
 372:             throw e;
 373:           }
 374:         catch (IOException e)
 375:           {
 376:             throw e;
 377:           }
 378:         catch (RuntimeException e)
 379:           {
 380:             throw e;
 381:           }
 382:         catch (Exception e)
 383:           {
 384:             throw new SAXParseException(e.getMessage(), this, e);
 385:           }
 386:         finally
 387:           {
 388:             contentHandler.endDocument();
 389:             reset();
 390:           }
 391:       }
 392:   }
 393: 
 394:   /**
 395:    * <b>SAX1, SAX2</b>: Preferred API to parse an XML document, using a
 396:    * system identifier (URI).
 397:    */
 398:   public void parse(String systemId)
 399:     throws SAXException, IOException
 400:   {
 401:     parse(new InputSource(systemId));
 402:   }
 403: 
 404:   //
 405:   // Implementation of SAX2 "XMLReader" interface
 406:   //
 407:   static final String FEATURE = "http://xml.org/sax/features/";
 408:   static final String PROPERTY = "http://xml.org/sax/properties/";
 409: 
 410:   /**
 411:    * <b>SAX2</b>: Tells the value of the specified feature flag.
 412:    *
 413:    * @exception SAXNotRecognizedException thrown if the feature flag
 414:    *  is neither built in, nor yet assigned.
 415:    */
 416:   public boolean getFeature(String featureId)
 417:     throws SAXNotRecognizedException, SAXNotSupportedException
 418:   {
 419:     if ((FEATURE + "validation").equals(featureId))
 420:       {
 421:         return false;
 422:       }
 423: 
 424:     // external entities (both types) are optionally included
 425:     if ((FEATURE + "external-general-entities").equals(featureId))
 426:       {
 427:         return extGE;
 428:       }
 429:     if ((FEATURE + "external-parameter-entities").equals(featureId))
 430:       {
 431:         return extPE;
 432:       }
 433:     
 434:     // element/attribute names are as written in document; no mangling
 435:     if ((FEATURE + "namespace-prefixes").equals(featureId))
 436:       {
 437:         return xmlNames;
 438:       }
 439: 
 440:     // report element/attribute namespaces?
 441:     if ((FEATURE + "namespaces").equals(featureId))
 442:       {
 443:         return namespaces;
 444:       }
 445: 
 446:     // all PEs and GEs are reported
 447:     if ((FEATURE + "lexical-handler/parameter-entities").equals(featureId))
 448:       {
 449:         return true;
 450:       }
 451: 
 452:     // default is true
 453:     if ((FEATURE + "string-interning").equals(featureId))
 454:       {
 455:         return stringInterning;
 456:       }
 457:   
 458:     // EXTENSIONS 1.1
 459:     
 460:     // always returns isSpecified info
 461:     if ((FEATURE + "use-attributes2").equals(featureId))
 462:       {
 463:         return true;
 464:       }
 465:   
 466:     // meaningful between startDocument/endDocument
 467:     if ((FEATURE + "is-standalone").equals(featureId))
 468:       {
 469:         if (parser == null)
 470:           {
 471:             throw new SAXNotSupportedException(featureId);
 472:           }
 473:         return parser.isStandalone();
 474:       }
 475: 
 476:     // optionally don't absolutize URIs in declarations
 477:     if ((FEATURE + "resolve-dtd-uris").equals(featureId))
 478:       {
 479:         return resolveAll;
 480:       }
 481: 
 482:     // optionally use resolver2 interface methods, if possible
 483:     if ((FEATURE + "use-entity-resolver2").equals(featureId))
 484:       {
 485:         return useResolver2;
 486:       }
 487:   
 488:     throw new SAXNotRecognizedException(featureId);
 489:   }
 490: 
 491:   // package private
 492:   DeclHandler getDeclHandler()
 493:   {
 494:     return declHandler;
 495:   }
 496: 
 497:   // package private
 498:   boolean resolveURIs()
 499:   {
 500:     return resolveAll;
 501:   }
 502: 
 503:   /**
 504:    * <b>SAX2</b>:  Returns the specified property.
 505:    *
 506:    * @exception SAXNotRecognizedException thrown if the property value
 507:    *  is neither built in, nor yet stored.
 508:    */
 509:   public Object getProperty(String propertyId)
 510:     throws SAXNotRecognizedException
 511:   {
 512:     if ((PROPERTY + "declaration-handler").equals(propertyId))
 513:       {
 514:         return (declHandler == base) ? null : declHandler;
 515:       }
 516: 
 517:     if ((PROPERTY + "lexical-handler").equals(propertyId))
 518:       {
 519:         return (lexicalHandler == base) ? null : lexicalHandler;
 520:       }
 521:     
 522:     // unknown properties
 523:     throw new SAXNotRecognizedException(propertyId);
 524:   }
 525: 
 526:   /**
 527:    * <b>SAX2</b>:  Sets the state of feature flags in this parser.  Some
 528:    * built-in feature flags are mutable.
 529:    */
 530:   public void setFeature(String featureId, boolean value)
 531:     throws SAXNotRecognizedException, SAXNotSupportedException
 532:   {
 533:     boolean state;
 534:   
 535:     // Features with a defined value, we just change it if we can.
 536:     state = getFeature (featureId);
 537:     
 538:     if (state == value)
 539:       {
 540:         return;
 541:       }
 542:     if (parser != null)
 543:       {
 544:         throw new SAXNotSupportedException("not while parsing");
 545:       }
 546: 
 547:     if ((FEATURE + "namespace-prefixes").equals(featureId))
 548:       {
 549:         // in this implementation, this only affects xmlns reporting
 550:         xmlNames = value;
 551:         // forcibly prevent illegal parser state
 552:         if (!xmlNames)
 553:           {
 554:             namespaces = true;
 555:           }
 556:         return;
 557:       }
 558: 
 559:     if ((FEATURE + "namespaces").equals(featureId))
 560:       {
 561:         namespaces = value;
 562:         // forcibly prevent illegal parser state
 563:         if (!namespaces)
 564:           {
 565:             xmlNames = true;
 566:           }
 567:         return;
 568:       }
 569: 
 570:     if ((FEATURE + "external-general-entities").equals(featureId))
 571:       {
 572:         extGE = value;
 573:         return;
 574:       }
 575:     if ((FEATURE + "external-parameter-entities").equals(featureId))
 576:       {
 577:         extPE = value;
 578:         return;
 579:       }
 580:     if ((FEATURE + "resolve-dtd-uris").equals(featureId))
 581:       {
 582:         resolveAll = value;
 583:         return;
 584:       }
 585: 
 586:     if ((FEATURE + "use-entity-resolver2").equals(featureId))
 587:       {
 588:         useResolver2 = value;
 589:         return;
 590:       }
 591: 
 592:     throw new SAXNotRecognizedException(featureId);
 593:   }
 594: 
 595:   /**
 596:    * <b>SAX2</b>:  Assigns the specified property.  Like SAX1 handlers,
 597:    * these may be changed at any time.
 598:    */
 599:   public void setProperty(String propertyId, Object value)
 600:     throws SAXNotRecognizedException, SAXNotSupportedException
 601:   {
 602:     // see if the property is recognized
 603:     getProperty(propertyId);
 604:     
 605:     // Properties with a defined value, we just change it if we can.
 606:     
 607:     if ((PROPERTY + "declaration-handler").equals(propertyId))
 608:       {
 609:         if (value == null)
 610:           {
 611:             declHandler = base;
 612:           }
 613:         else if (!(value instanceof DeclHandler))
 614:           {
 615:             throw new SAXNotSupportedException(propertyId);
 616:           }
 617:         else
 618:           {
 619:             declHandler = (DeclHandler) value;
 620:           }
 621:         return ;
 622:       }
 623:     
 624:     if ((PROPERTY + "lexical-handler").equals(propertyId))
 625:       {
 626:         if (value == null)
 627:           {
 628:             lexicalHandler = base;
 629:           }
 630:         else if (!(value instanceof LexicalHandler))
 631:           {
 632:             throw new SAXNotSupportedException(propertyId);
 633:           }
 634:         else
 635:           {
 636:             lexicalHandler = (LexicalHandler) value;
 637:           }
 638:         return;
 639:       }
 640:     
 641:     throw new SAXNotSupportedException(propertyId);
 642:   }
 643: 
 644:   //
 645:   // This is where the driver receives XmlParser callbacks and translates
 646:   // them into SAX callbacks.  Some more callbacks have been added for
 647:   // SAX2 support.
 648:   //
 649: 
 650:   void startDocument()
 651:     throws SAXException
 652:   {
 653:     contentHandler.setDocumentLocator(this);
 654:     contentHandler.startDocument();
 655:     attributesList.clear();
 656:   }
 657: 
 658:   void xmlDecl(String version,
 659:                String encoding,
 660:                boolean standalone,
 661:                String inputEncoding)
 662:     throws SAXException
 663:   {
 664:     if (contentHandler instanceof ContentHandler2)
 665:       {
 666:         ((ContentHandler2) contentHandler).xmlDecl(version,
 667:                                                    encoding,
 668:                                                    standalone,
 669:                                                    inputEncoding);
 670:       }
 671:   }
 672: 
 673:   void skippedEntity(String name)
 674:     throws SAXException
 675:   {
 676:     contentHandler.skippedEntity(name);
 677:   }
 678: 
 679:   InputSource getExternalSubset(String name, String baseURI)
 680:     throws SAXException, IOException
 681:   {
 682:     if (resolver2 == null || !useResolver2 || !extPE)
 683:       {
 684:         return null;
 685:       }
 686:     return resolver2.getExternalSubset(name, baseURI);
 687:   }
 688: 
 689:   InputSource resolveEntity(boolean isPE, String name,
 690:                             InputSource in, String baseURI)
 691:     throws SAXException, IOException
 692:   {
 693:     InputSource  source;
 694:     
 695:     // external entities might be skipped
 696:     if (isPE && !extPE)
 697:       {
 698:         return null;
 699:       }
 700:     if (!isPE && !extGE)
 701:       {
 702:         return null;
 703:       }
 704: 
 705:     // ... or not
 706:     lexicalHandler.startEntity(name);
 707:     if (resolver2 != null && useResolver2)
 708:       {
 709:         source = resolver2.resolveEntity(name, in.getPublicId(),
 710:                                          baseURI, in.getSystemId());
 711:         if (source == null)
 712:           {
 713:             in.setSystemId(absolutize(baseURI,
 714:                                       in.getSystemId(), false));
 715:             source = in;
 716:           }
 717:       }
 718:     else
 719:       {
 720:         in.setSystemId(absolutize(baseURI,
 721:                                   in.getSystemId(),
 722:                                   entityResolver != base));
 723:         source = entityResolver.resolveEntity(in.getPublicId(),
 724:                                               in.getSystemId());
 725:         if (source == null)
 726:           {
 727:             source = in;
 728:           }
 729:       }
 730:     startExternalEntity(name, source.getSystemId(), true);
 731:     return source;
 732:   }
 733: 
 734:   // absolutize a system ID relative to the specified base URI
 735:   // (temporarily) package-visible for external entity decls
 736:   String absolutize(String baseURI, String systemId, boolean nice)
 737:     throws MalformedURLException, SAXException
 738:   {
 739:     // FIXME normalize system IDs -- when?
 740:     // - Convert to UTF-8
 741:     // - Map reserved and non-ASCII characters to %HH
 742:     
 743:     try
 744:       {
 745:         if (baseURI == null)
 746:           {
 747:             if (XmlParser.uriWarnings)
 748:               {
 749:                 warn ("No base URI; hope this SYSTEM id is absolute: "
 750:                       + systemId);
 751:               }
 752:             return new URL(systemId).toString();
 753:           }
 754:         else
 755:           {
 756:             return new URL(new URL(baseURI), systemId).toString();
 757:           }
 758:       }
 759:     catch (MalformedURLException e)
 760:       {
 761:         // Let unknown URI schemes pass through unless we need
 762:         // the JVM to map them to i/o streams for us...
 763:         if (!nice)
 764:           {
 765:             throw e;
 766:           }
 767:         
 768:         // sometimes sysids for notations or unparsed entities
 769:         // aren't really URIs...
 770:         warn("Can't absolutize SYSTEM id: " + e.getMessage());
 771:         return systemId;
 772:       }
 773:   }
 774: 
 775:   void startExternalEntity(String name, String systemId, boolean stackOnly)
 776:     throws SAXException
 777:   {
 778:     // The following warning was deleted because the application has the
 779:     // option of not setting systemId. Sun's JAXP or Xerces seems to
 780:     // ignore this case.
 781:     /*
 782:        if (systemId == null)
 783:        warn ("URI was not reported to parser for entity " + name);
 784:      */
 785:     if (!stackOnly)  // spliced [dtd] needs startEntity
 786:       {
 787:         lexicalHandler.startEntity(name);
 788:       }
 789:     entityStack.push(systemId);
 790:   }
 791: 
 792:   void endExternalEntity(String name)
 793:     throws SAXException
 794:   {
 795:     if (!"[document]".equals(name))
 796:       {
 797:         lexicalHandler.endEntity(name);
 798:       }
 799:     entityStack.pop();
 800:   }
 801: 
 802:   void startInternalEntity(String name)
 803:     throws SAXException
 804:   {
 805:     lexicalHandler.startEntity(name);
 806:   }
 807: 
 808:   void endInternalEntity(String name)
 809:     throws SAXException
 810:   {
 811:     lexicalHandler.endEntity(name);
 812:   }
 813: 
 814:   void doctypeDecl(String name, String publicId, String systemId)
 815:     throws SAXException
 816:   {
 817:     lexicalHandler.startDTD(name, publicId, systemId);
 818:   
 819:     // ... the "name" is a declaration and should be given
 820:     // to the DeclHandler (but sax2 doesn't).
 821:     
 822:     // the IDs for the external subset are lexical details,
 823:     // as are the contents of the internal subset; but sax2
 824:     // doesn't provide the internal subset "pre-parse"
 825:   }
 826:   
 827:   void notationDecl(String name, String publicId, String systemId,
 828:                     String baseUri)
 829:     throws SAXException
 830:   {
 831:     try
 832:       {
 833:         dtdHandler.notationDecl(name, publicId,
 834:                                 (resolveAll && systemId != null)
 835:                                 ? absolutize(baseUri, systemId, true)
 836:                                 : systemId);
 837:       }
 838:     catch (IOException e)
 839:       {
 840:         // "can't happen"
 841:         throw new SAXParseException(e.getMessage(), this, e);
 842:       }
 843:   }
 844: 
 845:   void unparsedEntityDecl(String name, String publicId, String systemId,
 846:                           String baseUri, String notation)
 847:     throws SAXException
 848:   {
 849:     try
 850:       {
 851:         dtdHandler.unparsedEntityDecl(name, publicId,
 852:                                       resolveAll
 853:                                       ? absolutize(baseUri, systemId, true)
 854:                                       : systemId,
 855:                                       notation);
 856:       }
 857:     catch (IOException e)
 858:       {
 859:         // "can't happen"
 860:         throw new SAXParseException(e.getMessage(), this, e);
 861:       }
 862:   }
 863: 
 864:   void endDoctype()
 865:     throws SAXException
 866:   {
 867:     lexicalHandler.endDTD();
 868:   }
 869: 
 870:   private void declarePrefix(String prefix, String uri)
 871:     throws SAXException
 872:   {
 873:     int index = uri.indexOf(':');
 874: 
 875:     // many versions of nwalsh docbook stylesheets 
 876:     // have bogus URLs; so this can't be an error...
 877:     if (index < 1 && uri.length() != 0)
 878:       {
 879:         warn("relative URI for namespace: " + uri);
 880:       }
 881: 
 882:     // FIXME:  char [0] must be ascii alpha; chars [1..index]
 883:     // must be ascii alphanumeric or in "+-." [RFC 2396]
 884:     
 885:     //Namespace Constraints
 886:     //name for xml prefix must be http://www.w3.org/XML/1998/namespace
 887:     boolean prefixEquality = prefix.equals("xml");
 888:     boolean uriEquality = uri.equals("http://www.w3.org/XML/1998/namespace");
 889:     if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
 890:       {
 891:         fatal("xml is by definition bound to the namespace name " +
 892:               "http://www.w3.org/XML/1998/namespace");
 893:       }
 894:   
 895:     //xmlns prefix declaration is illegal but xml prefix declaration is llegal...
 896:     if (prefixEquality && uriEquality)
 897:       {
 898:         return;
 899:       }
 900:   
 901:     //name for xmlns prefix must be http://www.w3.org/2000/xmlns/
 902:     prefixEquality = prefix.equals("xmlns");
 903:     uriEquality = uri.equals("http://www.w3.org/2000/xmlns/");
 904:     if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality))
 905:       {
 906:         fatal("http://www.w3.org/2000/xmlns/ is by definition bound" +
 907:               " to prefix xmlns");
 908:       }
 909:   
 910:     //even if the uri is http://www.w3.org/2000/xmlns/
 911:     // it is illegal to declare it
 912:     if (prefixEquality && uriEquality)
 913:       {
 914:         fatal ("declaring the xmlns prefix is illegal");
 915:       }
 916:   
 917:     uri = uri.intern();
 918:     prefixStack.declarePrefix(prefix, uri);
 919:     contentHandler.startPrefixMapping(prefix, uri);
 920:   }
 921: 
 922:   void attribute(String qname, String value, boolean isSpecified)
 923:     throws SAXException
 924:   {
 925:     if (!attributes)
 926:       {
 927:         attributes = true;
 928:         if (namespaces)
 929:           {
 930:             prefixStack.pushContext();
 931:           }
 932:       }
 933:     
 934:     // process namespace decls immediately;
 935:     // then maybe forget this as an attribute
 936:     if (namespaces)
 937:       {
 938:         int index;
 939:         
 940:         // default NS declaration?
 941:         if (stringInterning)
 942:           {
 943:             if ("xmlns" == qname)
 944:               {
 945:                 declarePrefix("", value);
 946:                 if (!xmlNames)
 947:                   {
 948:                     return;
 949:                   }
 950:               }
 951:             // NS prefix declaration?
 952:             else if ((index = qname.indexOf(':')) == 5
 953:                      && qname.startsWith("xmlns"))
 954:               {
 955:                 String prefix = qname.substring(6);
 956:               
 957:                 if (prefix.equals(""))
 958:                   {
 959:                     fatal("missing prefix " +
 960:                           "in namespace declaration attribute");  
 961:                   }
 962:                 if (value.length() == 0)
 963:                   {
 964:                     verror("missing URI in namespace declaration attribute: "
 965:                            + qname);
 966:                   }
 967:                 else
 968:                   {
 969:                     declarePrefix(prefix, value);
 970:                   }
 971:                 if (!xmlNames)
 972:                   {
 973:                     return;
 974:                   }
 975:               }
 976:           }
 977:         else
 978:           {
 979:             if ("xmlns".equals(qname))
 980:               {
 981:                 declarePrefix("", value);
 982:                 if (!xmlNames)
 983:                   {
 984:                     return;
 985:                   }
 986:               }
 987:             // NS prefix declaration?
 988:             else if ((index = qname.indexOf(':')) == 5
 989:                      && qname.startsWith("xmlns"))
 990:               {
 991:                 String prefix = qname.substring(6);
 992:                 
 993:                 if (value.length() == 0)
 994:                   {
 995:                     verror("missing URI in namespace decl attribute: "
 996:                            + qname);
 997:                   }
 998:                 else
 999:                   {
1000:                     declarePrefix(prefix, value);
1001:                   }
1002:                 if (!xmlNames)
1003:                   {
1004:                     return;
1005:                   }
1006:               }
1007:           }
1008:       }
1009:     // remember this attribute ...
1010:     attributeCount++;
1011:     
1012:     // attribute type comes from querying parser's DTD records
1013:     attributesList.add(new Attribute(qname, value, isSpecified));
1014:     
1015:   }
1016:   
1017:   void startElement(String elname)
1018:     throws SAXException
1019:   {
1020:     ContentHandler handler = contentHandler;
1021: 
1022:     //
1023:     // NOTE:  this implementation of namespace support adds something
1024:     // like six percent to parsing CPU time, in a large (~50 MB)
1025:     // document that doesn't use namespaces at all.  (Measured by PC
1026:     // sampling, with a bug where endElement processing was omitted.)
1027:     // [Measurement referred to older implementation, older JVM ...]
1028:     //
1029:     // It ought to become notably faster in such cases.  Most
1030:     // costs are the prefix stack calling Hashtable.get() (2%),
1031:     // String.hashCode() (1.5%) and about 1.3% each for pushing
1032:     // the context, and two chunks of name processing.
1033:     //
1034:     
1035:     if (!attributes)
1036:       {
1037:         if (namespaces)
1038:           {
1039:             prefixStack.pushContext();
1040:           }
1041:       }
1042:     else if (namespaces)
1043:       {
1044:       
1045:         // now we can patch up namespace refs; we saw all the
1046:         // declarations, so now we'll do the Right Thing
1047:         Iterator itt = attributesList.iterator();
1048:         while (itt.hasNext())
1049:           {
1050:             Attribute attribute = (Attribute) itt.next();
1051:             String qname = attribute.name;
1052:             int index;
1053:             
1054:             // default NS declaration?
1055:             if (stringInterning)
1056:               {
1057:                 if ("xmlns" == qname)
1058:                   {
1059:                     continue;
1060:                   }
1061:               }
1062:             else
1063:               {
1064:                 if ("xmlns".equals(qname))
1065:                   {
1066:                     continue;
1067:                   }
1068:               }
1069:             //Illegal in the new Namespaces Draft
1070:             //should it be only in 1.1 docs??
1071:             if (qname.equals (":"))
1072:               {
1073:                 fatal("namespace names consisting of a single colon " +
1074:                       "character are invalid");
1075:               }
1076:             index = qname.indexOf(':');
1077:             
1078:             // NS prefix declaration?
1079:             if (index == 5 && qname.startsWith("xmlns"))
1080:               {
1081:                 continue;
1082:               }
1083:             
1084:             // it's not a NS decl; patch namespace info items
1085:             if (prefixStack.processName(qname, nsTemp, true) == null)
1086:               {
1087:                 fatal("undeclared attribute prefix in: " + qname);
1088:               }
1089:             else
1090:               {
1091:                 attribute.nameSpace = nsTemp[0];
1092:                 attribute.localName = nsTemp[1];
1093:               }
1094:           }
1095:       }
1096:     
1097:     // save element name so attribute callbacks work
1098:     elementName = elname;
1099:     if (namespaces)
1100:       {
1101:         if (prefixStack.processName(elname, nsTemp, false) == null)
1102:           {
1103:             fatal("undeclared element prefix in: " + elname);
1104:             nsTemp[0] = nsTemp[1] = "";
1105:           }
1106:         handler.startElement(nsTemp[0], nsTemp[1], elname, this);
1107:       }
1108:     else
1109:       {
1110:         handler.startElement("", "", elname, this);
1111:       }
1112:     // elementName = null;
1113:     
1114:     // elements with no attributes are pretty common!
1115:     if (attributes)
1116:       {
1117:         attributesList.clear();
1118:         attributeCount = 0;
1119:         attributes = false;
1120:       }
1121:   }
1122:   
1123:   void endElement(String elname)
1124:     throws SAXException
1125:   {
1126:     ContentHandler handler = contentHandler;
1127: 
1128:     if (!namespaces)
1129:       {
1130:         handler.endElement("", "", elname);
1131:         return;
1132:       }
1133:     prefixStack.processName(elname, nsTemp, false);
1134:     handler.endElement(nsTemp[0], nsTemp[1], elname);
1135:     
1136:     Enumeration prefixes = prefixStack.getDeclaredPrefixes();
1137:     
1138:     while (prefixes.hasMoreElements())
1139:       {
1140:         handler.endPrefixMapping((String) prefixes.nextElement());
1141:       }
1142:     prefixStack.popContext();
1143:   }
1144: 
1145:   void startCDATA()
1146:     throws SAXException
1147:   {
1148:     lexicalHandler.startCDATA();
1149:   }
1150: 
1151:   void charData(char[] ch, int start, int length)
1152:     throws SAXException
1153:   {
1154:     contentHandler.characters(ch, start, length);
1155:   }
1156: 
1157:   void endCDATA()
1158:     throws SAXException
1159:   {
1160:     lexicalHandler.endCDATA();
1161:   }
1162: 
1163:   void ignorableWhitespace(char[] ch, int start, int length)
1164:     throws SAXException
1165:   {
1166:     contentHandler.ignorableWhitespace(ch, start, length);
1167:   }
1168: 
1169:   void processingInstruction(String target, String data)
1170:     throws SAXException
1171:   {
1172:     contentHandler.processingInstruction(target, data);
1173:   }
1174: 
1175:   void comment(char[] ch, int start, int length)
1176:     throws SAXException
1177:   {
1178:     if (lexicalHandler != base)
1179:       {
1180:         lexicalHandler.comment(ch, start, length);
1181:       }
1182:   }
1183: 
1184:   void fatal(String message)
1185:     throws SAXException
1186:   {
1187:     SAXParseException fatal;
1188:   
1189:     fatal = new SAXParseException(message, this);
1190:     errorHandler.fatalError(fatal);
1191: 
1192:     // Even if the application can continue ... we can't!
1193:     throw fatal;
1194:   }
1195: 
1196:   // We can safely report a few validity errors that
1197:   // make layered SAX2 DTD validation more conformant
1198:   void verror(String message)
1199:     throws SAXException
1200:   {
1201:     SAXParseException err;
1202:     
1203:     err = new SAXParseException(message, this);
1204:     errorHandler.error(err);
1205:   }
1206:   
1207:   void warn(String message)
1208:     throws SAXException
1209:   {
1210:     SAXParseException err;
1211:   
1212:     err = new SAXParseException(message, this);
1213:     errorHandler.warning(err);
1214:   }
1215: 
1216:   //
1217:   // Implementation of org.xml.sax.Attributes.
1218:   //
1219: 
1220:   /**
1221:    * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1222:    * (don't invoke on parser);
1223:    */
1224:   public int getLength()
1225:   {
1226:     return attributesList.size();
1227:   }
1228: 
1229:   /**
1230:    * <b>SAX2 Attributes</b> method (don't invoke on parser);
1231:    */
1232:   public String getURI(int index)
1233:   {
1234:     if (index < 0 || index >= attributesList.size())
1235:       {
1236:         return null;
1237:       }
1238:     return ((Attribute) attributesList.get(index)).nameSpace;
1239:   }
1240: 
1241:   /**
1242:    * <b>SAX2 Attributes</b> method (don't invoke on parser);
1243:    */
1244:   public String getLocalName(int index)
1245:   {
1246:     if (index < 0 || index >= attributesList.size())
1247:       {
1248:         return null;
1249:       }
1250:     Attribute attr = (Attribute) attributesList.get(index);
1251:     // FIXME attr.localName is sometimes null, why?
1252:     if (namespaces && attr.localName == null)
1253:       {
1254:         // XXX fix this here for now
1255:         int ci = attr.name.indexOf(':');
1256:         attr.localName = (ci == -1) ? attr.name :
1257:           attr.name.substring(ci + 1);
1258:       }
1259:     return (attr.localName == null) ? "" : attr.localName;
1260:   }
1261: 
1262:   /**
1263:    * <b>SAX2 Attributes</b> method (don't invoke on parser);
1264:    */
1265:   public String getQName(int index)
1266:   {
1267:     if (index < 0 || index >= attributesList.size())
1268:       {
1269:       return null;
1270:       }
1271:     Attribute attr = (Attribute) attributesList.get(index);
1272:     return (attr.name == null) ? "" : attr.name;
1273:   }
1274: 
1275:   /**
1276:    * <b>SAX1 AttributeList</b> method (don't invoke on parser);
1277:    */
1278:   public String getName(int index)
1279:   {
1280:     return getQName(index);
1281:   }
1282: 
1283:   /**
1284:    * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1285:    * (don't invoke on parser);
1286:    */
1287:   public String getType(int index)
1288:   {
1289:     if (index < 0 || index >= attributesList.size())
1290:       {
1291:         return null;
1292:       }
1293:     String type = parser.getAttributeType(elementName, getQName(index));
1294:     if (type == null)
1295:       {
1296:         return "CDATA";
1297:       }
1298:     // ... use DeclHandler.attributeDecl to see enumerations
1299:     if (type == "ENUMERATION")
1300:       {
1301:         return "NMTOKEN";
1302:       }
1303:     return type;
1304:   }
1305: 
1306:   /**
1307:    * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1308:    * (don't invoke on parser);
1309:    */
1310:   public String getValue(int index)
1311:   {
1312:     if (index < 0 || index >= attributesList.size())
1313:       {
1314:         return null;
1315:       }
1316:     return ((Attribute) attributesList.get(index)).value;
1317:   }
1318: 
1319:   /**
1320:    * <b>SAX2 Attributes</b> method (don't invoke on parser);
1321:    */
1322:   public int getIndex(String uri, String local)
1323:     {
1324:       int length = getLength();
1325:       
1326:       for (int i = 0; i < length; i++)
1327:         {
1328:           if (!getURI(i).equals(uri))
1329:             {
1330:               continue;
1331:             }
1332:           if (getLocalName(i).equals(local))
1333:             {
1334:               return i;
1335:             }
1336:         }
1337:       return -1;
1338:   }
1339: 
1340:   /**
1341:    * <b>SAX2 Attributes</b> method (don't invoke on parser);
1342:    */
1343:   public int getIndex(String xmlName)
1344:   {
1345:     int length = getLength();
1346:     
1347:     for (int i = 0; i < length; i++)
1348:       {
1349:         if (getQName(i).equals(xmlName))
1350:           {
1351:             return i;
1352:           }
1353:       }
1354:     return -1;
1355:   }
1356: 
1357:   /**
1358:    * <b>SAX2 Attributes</b> method (don't invoke on parser);
1359:    */
1360:   public String getType(String uri, String local)
1361:   {
1362:     int index = getIndex(uri, local);
1363:     
1364:     if (index < 0)
1365:       {
1366:         return null;
1367:       }
1368:     return getType(index);
1369:   }
1370: 
1371:   /**
1372:    * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1373:    * (don't invoke on parser);
1374:    */
1375:   public String getType(String xmlName)
1376:   {
1377:     int index = getIndex(xmlName);
1378:     
1379:     if (index < 0)
1380:       {
1381:         return null;
1382:       }
1383:     return getType(index);
1384:   }
1385: 
1386:   /**
1387:    * <b>SAX Attributes</b> method (don't invoke on parser);
1388:    */
1389:   public String getValue(String uri, String local)
1390:   {
1391:     int index = getIndex(uri, local);
1392:     
1393:     if (index < 0)
1394:       {
1395:         return null;
1396:       }
1397:     return getValue(index);
1398:   }
1399: 
1400:   /**
1401:    * <b>SAX1 AttributeList, SAX2 Attributes</b> method
1402:    * (don't invoke on parser);
1403:    */
1404:   public String getValue(String xmlName)
1405:   {
1406:     int index = getIndex(xmlName);
1407:     
1408:     if (index < 0)
1409:       {
1410:         return null;
1411:       }
1412:     return getValue(index);
1413:   }
1414: 
1415:   //
1416:   // Implementation of org.xml.sax.ext.Attributes2
1417:   //
1418: 
1419:   /** @return false unless the attribute was declared in the DTD.
1420:    * @throws java.lang.ArrayIndexOutOfBoundsException
1421:    *   When the supplied index does not identify an attribute.
1422:    */  
1423:   public boolean isDeclared(int index)
1424:   {
1425:     if (index < 0 || index >= attributeCount)
1426:       {
1427:         throw new ArrayIndexOutOfBoundsException();
1428:       }
1429:     String type = parser.getAttributeType(elementName, getQName(index));
1430:     return (type != null);
1431:   }
1432: 
1433:   /** @return false unless the attribute was declared in the DTD.
1434:    * @throws java.lang.IllegalArgumentException
1435:    *   When the supplied names do not identify an attribute.
1436:    */
1437:   public boolean isDeclared(String qName)
1438:   {
1439:     int index = getIndex(qName);
1440:     if (index < 0)
1441:       {
1442:         throw new IllegalArgumentException();
1443:       }
1444:     String type = parser.getAttributeType(elementName, qName);
1445:     return (type != null);
1446:   }
1447: 
1448:   /** @return false unless the attribute was declared in the DTD.
1449:    * @throws java.lang.IllegalArgumentException
1450:    *   When the supplied names do not identify an attribute.
1451:    */
1452:   public boolean isDeclared(String uri, String localName)
1453:   {
1454:     int index = getIndex(uri, localName);
1455:     return isDeclared(index);
1456:   }
1457: 
1458:   /**
1459:    * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1460:    */
1461:   public boolean isSpecified(int index)
1462:   {
1463:     return ((Attribute) attributesList.get(index)).specified;
1464:   }
1465: 
1466:   /**
1467:    * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1468:    */
1469:   public boolean isSpecified(String uri, String local)
1470:   {
1471:     int index = getIndex (uri, local);
1472:     return isSpecified(index);
1473:   }
1474: 
1475:   /**
1476:    * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
1477:    */
1478:   public boolean isSpecified(String xmlName)
1479:   {
1480:     int index = getIndex (xmlName);
1481:     return isSpecified(index);
1482:   }
1483: 
1484:   //
1485:   // Implementation of org.xml.sax.Locator.
1486:   //
1487: 
1488:   /**
1489:    * <b>SAX Locator</b> method (don't invoke on parser);
1490:    */
1491:   public String getPublicId()
1492:   {
1493:     return null;   // FIXME track public IDs too
1494:   }
1495: 
1496:   /**
1497:    * <b>SAX Locator</b> method (don't invoke on parser);
1498:    */
1499:   public String getSystemId()
1500:   {
1501:     if (entityStack.empty())
1502:       {
1503:         return null;
1504:       }
1505:     else
1506:       {
1507:         return (String) entityStack.peek();
1508:       }
1509:   }
1510: 
1511:   /**
1512:    * <b>SAX Locator</b> method (don't invoke on parser);
1513:    */
1514:   public int getLineNumber()
1515:   {
1516:     return parser.getLineNumber();
1517:   }
1518: 
1519:   /**
1520:    * <b>SAX Locator</b> method (don't invoke on parser);
1521:    */
1522:   public int getColumnNumber()
1523:   {
1524:     return parser.getColumnNumber();
1525:   }
1526: 
1527:   // adapter between SAX2 content handler and SAX1 document handler callbacks
1528:   private static class Adapter
1529:     implements ContentHandler
1530:   {
1531:     
1532:     private DocumentHandler docHandler;
1533: 
1534:     Adapter(DocumentHandler dh)
1535:     {
1536:       docHandler = dh;
1537:     }
1538: 
1539:     public void setDocumentLocator(Locator l)
1540:     {
1541:       docHandler.setDocumentLocator(l);
1542:     }
1543:   
1544:     public void startDocument()
1545:       throws SAXException
1546:     {
1547:       docHandler.startDocument();
1548:     }
1549:   
1550:     public void processingInstruction(String target, String data)
1551:       throws SAXException
1552:     {
1553:       docHandler.processingInstruction(target, data);
1554:     }
1555:   
1556:     public void startPrefixMapping(String prefix, String uri)
1557:     {
1558:       /* ignored */
1559:     }
1560: 
1561:     public void startElement(String namespace,
1562:                              String local,
1563:                              String name,
1564:                              Attributes attrs)
1565:       throws SAXException
1566:     {
1567:       docHandler.startElement(name, (AttributeList) attrs);
1568:     }
1569: 
1570:     public void characters(char[] buf, int offset, int len)
1571:       throws SAXException
1572:     {
1573:       docHandler.characters(buf, offset, len);
1574:     }
1575: 
1576:     public void ignorableWhitespace(char[] buf, int offset, int len)
1577:       throws SAXException
1578:     {
1579:       docHandler.ignorableWhitespace(buf, offset, len);
1580:     }
1581: 
1582:     public void skippedEntity(String name)
1583:     {
1584:       /* ignored */
1585:     }
1586: 
1587:     public void endElement(String u, String l, String name)
1588:       throws SAXException
1589:     {
1590:       docHandler.endElement(name);
1591:     }
1592: 
1593:     public void endPrefixMapping(String prefix)
1594:     {
1595:       /* ignored */
1596:     }
1597: 
1598:     public void endDocument()
1599:       throws SAXException
1600:     {
1601:       docHandler.endDocument();
1602:     }
1603:   }
1604: 
1605:   private static class Attribute
1606:   {
1607:     
1608:     String name;
1609:     String value;
1610:     String nameSpace;
1611:     String localName;
1612:     boolean specified;
1613:     
1614:     Attribute(String name, String value, boolean specified)
1615:     {
1616:       this.name = name;
1617:       this.value = value;
1618:       this.nameSpace = "";
1619:       this.specified = specified;
1620:     }
1621:     
1622:   }
1623: 
1624: }