001// XMLFilterImpl.java - base SAX2 filter implementation. 002// Written by David Megginson, sax@megginson.com 003// NO WARRANTY! This class is in the Public Domain. 004 005// $Id: XMLFilterImpl.java,v 1.1 2001/03/05 21:40:06 jstrachan Exp $ 006 007package org.xml.sax.helpers; 008 009import java.io.IOException; 010 011import org.xml.sax.XMLReader; 012import org.xml.sax.XMLFilter; 013import org.xml.sax.InputSource; 014import org.xml.sax.Locator; 015import org.xml.sax.Attributes; 016import org.xml.sax.EntityResolver; 017import org.xml.sax.DTDHandler; 018import org.xml.sax.ContentHandler; 019import org.xml.sax.ErrorHandler; 020import org.xml.sax.SAXException; 021import org.xml.sax.SAXParseException; 022import org.xml.sax.SAXNotSupportedException; 023import org.xml.sax.SAXNotRecognizedException; 024 025 026/** 027 * Base class for deriving an XML filter. 028 * 029 * <blockquote> 030 * <em>This module, both source code and documentation, is in the 031 * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em> 032 * </blockquote> 033 * 034 * <p>This class is designed to sit between an {@link org.xml.sax.XMLReader 035 * XMLReader} and the client application's event handlers. By default, it 036 * does nothing but pass requests up to the reader and events 037 * on to the handlers unmodified, but subclasses can override 038 * specific methods to modify the event stream or the configuration 039 * requests as they pass through.</p> 040 * 041 * @since SAX 2.0 042 * @author David Megginson, 043 * <a href="mailto:sax@megginson.com">sax@megginson.com</a> 044 * @version 2.0 045 * @see org.xml.sax.XMLFilter 046 * @see org.xml.sax.XMLReader 047 * @see org.xml.sax.EntityResolver 048 * @see org.xml.sax.DTDHandler 049 * @see org.xml.sax.ContentHandler 050 * @see org.xml.sax.ErrorHandler 051 */ 052public class XMLFilterImpl 053 implements XMLFilter, EntityResolver, DTDHandler, ContentHandler, ErrorHandler 054{ 055 056 057 //////////////////////////////////////////////////////////////////// 058 // Constructors. 059 //////////////////////////////////////////////////////////////////// 060 061 062 /** 063 * Construct an empty XML filter, with no parent. 064 * 065 * <p>This filter will have no parent: you must assign a parent 066 * before you start a parse or do any configuration with 067 * setFeature or setProperty.</p> 068 * 069 * @see org.xml.sax.XMLReader#setFeature 070 * @see org.xml.sax.XMLReader#setProperty 071 */ 072 public XMLFilterImpl () 073 { 074 super(); 075 } 076 077 078 /** 079 * Construct an XML filter with the specified parent. 080 * 081 * @see #setParent 082 * @see #getParent 083 */ 084 public XMLFilterImpl (XMLReader parent) 085 { 086 super(); 087 setParent(parent); 088 } 089 090 091 092 //////////////////////////////////////////////////////////////////// 093 // Implementation of org.xml.sax.XMLFilter. 094 //////////////////////////////////////////////////////////////////// 095 096 097 /** 098 * Set the parent reader. 099 * 100 * <p>This is the {@link org.xml.sax.XMLReader XMLReader} from which 101 * this filter will obtain its events and to which it will pass its 102 * configuration requests. The parent may itself be another filter.</p> 103 * 104 * <p>If there is no parent reader set, any attempt to parse 105 * or to set or get a feature or property will fail.</p> 106 * 107 * @param parent The parent XML reader. 108 * @exception java.lang.NullPointerException If the parent is null. 109 * @see #getParent 110 */ 111 public void setParent (XMLReader parent) 112 { 113 if (parent == null) { 114 throw new NullPointerException("Null parent"); 115 } 116 this.parent = parent; 117 } 118 119 120 /** 121 * Get the parent reader. 122 * 123 * @return The parent XML reader, or null if none is set. 124 * @see #setParent 125 */ 126 public XMLReader getParent () 127 { 128 return parent; 129 } 130 131 132 133 //////////////////////////////////////////////////////////////////// 134 // Implementation of org.xml.sax.XMLReader. 135 //////////////////////////////////////////////////////////////////// 136 137 138 /** 139 * Set the state of a feature. 140 * 141 * <p>This will always fail if the parent is null.</p> 142 * 143 * @param name The feature name. 144 * @param state The requested feature state. 145 * @exception org.xml.sax.SAXNotRecognizedException When the 146 * XMLReader does not recognize the feature name. 147 * @exception org.xml.sax.SAXNotSupportedException When the 148 * XMLReader recognizes the feature name but 149 * cannot set the requested value. 150 * @see org.xml.sax.XMLReader#setFeature 151 */ 152 public void setFeature (String name, boolean state) 153 throws SAXNotRecognizedException, SAXNotSupportedException 154 { 155 if (parent != null) { 156 parent.setFeature(name, state); 157 } else { 158 throw new SAXNotRecognizedException("Feature: " + name); 159 } 160 } 161 162 163 /** 164 * Look up the state of a feature. 165 * 166 * <p>This will always fail if the parent is null.</p> 167 * 168 * @param name The feature name. 169 * @return The current state of the feature. 170 * @exception org.xml.sax.SAXNotRecognizedException When the 171 * XMLReader does not recognize the feature name. 172 * @exception org.xml.sax.SAXNotSupportedException When the 173 * XMLReader recognizes the feature name but 174 * cannot determine its state at this time. 175 * @see org.xml.sax.XMLReader#getFeature 176 */ 177 public boolean getFeature (String name) 178 throws SAXNotRecognizedException, SAXNotSupportedException 179 { 180 if (parent != null) { 181 return parent.getFeature(name); 182 } else { 183 throw new SAXNotRecognizedException("Feature: " + name); 184 } 185 } 186 187 188 /** 189 * Set the value of a property. 190 * 191 * <p>This will always fail if the parent is null.</p> 192 * 193 * @param name The property name. 194 * @param state The requested property value. 195 * @exception org.xml.sax.SAXNotRecognizedException When the 196 * XMLReader does not recognize the property name. 197 * @exception org.xml.sax.SAXNotSupportedException When the 198 * XMLReader recognizes the property name but 199 * cannot set the requested value. 200 * @see org.xml.sax.XMLReader#setProperty 201 */ 202 public void setProperty (String name, Object value) 203 throws SAXNotRecognizedException, SAXNotSupportedException 204 { 205 if (parent != null) { 206 parent.setProperty(name, value); 207 } else { 208 throw new SAXNotRecognizedException("Property: " + name); 209 } 210 } 211 212 213 /** 214 * Look up the value of a property. 215 * 216 * @param name The property name. 217 * @return The current value of the property. 218 * @exception org.xml.sax.SAXNotRecognizedException When the 219 * XMLReader does not recognize the feature name. 220 * @exception org.xml.sax.SAXNotSupportedException When the 221 * XMLReader recognizes the property name but 222 * cannot determine its value at this time. 223 * @see org.xml.sax.XMLReader#setFeature 224 */ 225 public Object getProperty (String name) 226 throws SAXNotRecognizedException, SAXNotSupportedException 227 { 228 if (parent != null) { 229 return parent.getProperty(name); 230 } else { 231 throw new SAXNotRecognizedException("Property: " + name); 232 } 233 } 234 235 236 /** 237 * Set the entity resolver. 238 * 239 * @param resolver The new entity resolver. 240 * @exception java.lang.NullPointerException If the resolver 241 * is null. 242 * @see org.xml.sax.XMLReader#setEntityResolver 243 */ 244 public void setEntityResolver (EntityResolver resolver) 245 { 246 if (resolver == null) { 247 throw new NullPointerException("Null entity resolver"); 248 } else { 249 entityResolver = resolver; 250 } 251 } 252 253 254 /** 255 * Get the current entity resolver. 256 * 257 * @return The current entity resolver, or null if none was set. 258 * @see org.xml.sax.XMLReader#getEntityResolver 259 */ 260 public EntityResolver getEntityResolver () 261 { 262 return entityResolver; 263 } 264 265 266 /** 267 * Set the DTD event handler. 268 * 269 * @param resolver The new DTD handler. 270 * @exception java.lang.NullPointerException If the handler 271 * is null. 272 * @see org.xml.sax.XMLReader#setDTDHandler 273 */ 274 public void setDTDHandler (DTDHandler handler) 275 { 276 if (handler == null) { 277 throw new NullPointerException("Null DTD handler"); 278 } else { 279 dtdHandler = handler; 280 } 281 } 282 283 284 /** 285 * Get the current DTD event handler. 286 * 287 * @return The current DTD handler, or null if none was set. 288 * @see org.xml.sax.XMLReader#getDTDHandler 289 */ 290 public DTDHandler getDTDHandler () 291 { 292 return dtdHandler; 293 } 294 295 296 /** 297 * Set the content event handler. 298 * 299 * @param resolver The new content handler. 300 * @exception java.lang.NullPointerException If the handler 301 * is null. 302 * @see org.xml.sax.XMLReader#setContentHandler 303 */ 304 public void setContentHandler (ContentHandler handler) 305 { 306 if (handler == null) { 307 throw new NullPointerException("Null content handler"); 308 } else { 309 contentHandler = handler; 310 } 311 } 312 313 314 /** 315 * Get the content event handler. 316 * 317 * @return The current content handler, or null if none was set. 318 * @see org.xml.sax.XMLReader#getContentHandler 319 */ 320 public ContentHandler getContentHandler () 321 { 322 return contentHandler; 323 } 324 325 326 /** 327 * Set the error event handler. 328 * 329 * @param handle The new error handler. 330 * @exception java.lang.NullPointerException If the handler 331 * is null. 332 * @see org.xml.sax.XMLReader#setErrorHandler 333 */ 334 public void setErrorHandler (ErrorHandler handler) 335 { 336 if (handler == null) { 337 throw new NullPointerException("Null error handler"); 338 } else { 339 errorHandler = handler; 340 } 341 } 342 343 344 /** 345 * Get the current error event handler. 346 * 347 * @return The current error handler, or null if none was set. 348 * @see org.xml.sax.XMLReader#getErrorHandler 349 */ 350 public ErrorHandler getErrorHandler () 351 { 352 return errorHandler; 353 } 354 355 356 /** 357 * Parse a document. 358 * 359 * @param input The input source for the document entity. 360 * @exception org.xml.sax.SAXException Any SAX exception, possibly 361 * wrapping another exception. 362 * @exception java.io.IOException An IO exception from the parser, 363 * possibly from a byte stream or character stream 364 * supplied by the application. 365 * @see org.xml.sax.XMLReader#parse(org.xml.sax.InputSource) 366 */ 367 public void parse (InputSource input) 368 throws SAXException, IOException 369 { 370 setupParse(); 371 parent.parse(input); 372 } 373 374 375 /** 376 * Parse a document. 377 * 378 * @param systemId The system identifier as a fully-qualified URI. 379 * @exception org.xml.sax.SAXException Any SAX exception, possibly 380 * wrapping another exception. 381 * @exception java.io.IOException An IO exception from the parser, 382 * possibly from a byte stream or character stream 383 * supplied by the application. 384 * @see org.xml.sax.XMLReader#parse(java.lang.String) 385 */ 386 public void parse (String systemId) 387 throws SAXException, IOException 388 { 389 parse(new InputSource(systemId)); 390 } 391 392 393 394 //////////////////////////////////////////////////////////////////// 395 // Implementation of org.xml.sax.EntityResolver. 396 //////////////////////////////////////////////////////////////////// 397 398 399 /** 400 * Filter an external entity resolution. 401 * 402 * @param publicId The entity's public identifier, or null. 403 * @param systemId The entity's system identifier. 404 * @return A new InputSource or null for the default. 405 * @exception org.xml.sax.SAXException The client may throw 406 * an exception during processing. 407 * @exception java.io.IOException The client may throw an 408 * I/O-related exception while obtaining the 409 * new InputSource. 410 * @see org.xml.sax.EntityResolver#resolveEntity 411 */ 412 public InputSource resolveEntity (String publicId, String systemId) 413 throws SAXException, IOException 414 { 415 if (entityResolver != null) { 416 return entityResolver.resolveEntity(publicId, systemId); 417 } else { 418 return null; 419 } 420 } 421 422 423 424 //////////////////////////////////////////////////////////////////// 425 // Implementation of org.xml.sax.DTDHandler. 426 //////////////////////////////////////////////////////////////////// 427 428 429 /** 430 * Filter a notation declaration event. 431 * 432 * @param name The notation name. 433 * @param publicId The notation's public identifier, or null. 434 * @param systemId The notation's system identifier, or null. 435 * @exception org.xml.sax.SAXException The client may throw 436 * an exception during processing. 437 * @see org.xml.sax.DTDHandler#notationDecl 438 */ 439 public void notationDecl (String name, String publicId, String systemId) 440 throws SAXException 441 { 442 if (dtdHandler != null) { 443 dtdHandler.notationDecl(name, publicId, systemId); 444 } 445 } 446 447 448 /** 449 * Filter an unparsed entity declaration event. 450 * 451 * @param name The entity name. 452 * @param publicId The entity's public identifier, or null. 453 * @param systemId The entity's system identifier, or null. 454 * @param notationName The name of the associated notation. 455 * @exception org.xml.sax.SAXException The client may throw 456 * an exception during processing. 457 * @see org.xml.sax.DTDHandler#unparsedEntityDecl 458 */ 459 public void unparsedEntityDecl (String name, String publicId, 460 String systemId, String notationName) 461 throws SAXException 462 { 463 if (dtdHandler != null) { 464 dtdHandler.unparsedEntityDecl(name, publicId, systemId, 465 notationName); 466 } 467 } 468 469 470 471 //////////////////////////////////////////////////////////////////// 472 // Implementation of org.xml.sax.ContentHandler. 473 //////////////////////////////////////////////////////////////////// 474 475 476 /** 477 * Filter a new document locator event. 478 * 479 * @param locator The document locator. 480 * @see org.xml.sax.ContentHandler#setDocumentLocator 481 */ 482 public void setDocumentLocator (Locator locator) 483 { 484 this.locator = locator; 485 if (contentHandler != null) { 486 contentHandler.setDocumentLocator(locator); 487 } 488 } 489 490 491 /** 492 * Filter a start document event. 493 * 494 * @exception org.xml.sax.SAXException The client may throw 495 * an exception during processing. 496 * @see org.xml.sax.ContentHandler#startDocument 497 */ 498 public void startDocument () 499 throws SAXException 500 { 501 if (contentHandler != null) { 502 contentHandler.startDocument(); 503 } 504 } 505 506 507 /** 508 * Filter an end document event. 509 * 510 * @exception org.xml.sax.SAXException The client may throw 511 * an exception during processing. 512 * @see org.xml.sax.ContentHandler#endDocument 513 */ 514 public void endDocument () 515 throws SAXException 516 { 517 if (contentHandler != null) { 518 contentHandler.endDocument(); 519 } 520 } 521 522 523 /** 524 * Filter a start Namespace prefix mapping event. 525 * 526 * @param prefix The Namespace prefix. 527 * @param uri The Namespace URI. 528 * @exception org.xml.sax.SAXException The client may throw 529 * an exception during processing. 530 * @see org.xml.sax.ContentHandler#startPrefixMapping 531 */ 532 public void startPrefixMapping (String prefix, String uri) 533 throws SAXException 534 { 535 if (contentHandler != null) { 536 contentHandler.startPrefixMapping(prefix, uri); 537 } 538 } 539 540 541 /** 542 * Filter an end Namespace prefix mapping event. 543 * 544 * @param prefix The Namespace prefix. 545 * @exception org.xml.sax.SAXException The client may throw 546 * an exception during processing. 547 * @see org.xml.sax.ContentHandler#endPrefixMapping 548 */ 549 public void endPrefixMapping (String prefix) 550 throws SAXException 551 { 552 if (contentHandler != null) { 553 contentHandler.endPrefixMapping(prefix); 554 } 555 } 556 557 558 /** 559 * Filter a start element event. 560 * 561 * @param uri The element's Namespace URI, or the empty string. 562 * @param localName The element's local name, or the empty string. 563 * @param qName The element's qualified (prefixed) name, or the empty 564 * string. 565 * @param atts The element's attributes. 566 * @exception org.xml.sax.SAXException The client may throw 567 * an exception during processing. 568 * @see org.xml.sax.ContentHandler#startElement 569 */ 570 public void startElement (String uri, String localName, String qName, 571 Attributes atts) 572 throws SAXException 573 { 574 if (contentHandler != null) { 575 contentHandler.startElement(uri, localName, qName, atts); 576 } 577 } 578 579 580 /** 581 * Filter an end element event. 582 * 583 * @param uri The element's Namespace URI, or the empty string. 584 * @param localName The element's local name, or the empty string. 585 * @param qName The element's qualified (prefixed) name, or the empty 586 * string. 587 * @exception org.xml.sax.SAXException The client may throw 588 * an exception during processing. 589 * @see org.xml.sax.ContentHandler#endElement 590 */ 591 public void endElement (String uri, String localName, String qName) 592 throws SAXException 593 { 594 if (contentHandler != null) { 595 contentHandler.endElement(uri, localName, qName); 596 } 597 } 598 599 600 /** 601 * Filter a character data event. 602 * 603 * @param ch An array of characters. 604 * @param start The starting position in the array. 605 * @param length The number of characters to use from the array. 606 * @exception org.xml.sax.SAXException The client may throw 607 * an exception during processing. 608 * @see org.xml.sax.ContentHandler#characters 609 */ 610 public void characters (char ch[], int start, int length) 611 throws SAXException 612 { 613 if (contentHandler != null) { 614 contentHandler.characters(ch, start, length); 615 } 616 } 617 618 619 /** 620 * Filter an ignorable whitespace event. 621 * 622 * @param ch An array of characters. 623 * @param start The starting position in the array. 624 * @param length The number of characters to use from the array. 625 * @exception org.xml.sax.SAXException The client may throw 626 * an exception during processing. 627 * @see org.xml.sax.ContentHandler#ignorableWhitespace 628 */ 629 public void ignorableWhitespace (char ch[], int start, int length) 630 throws SAXException 631 { 632 if (contentHandler != null) { 633 contentHandler.ignorableWhitespace(ch, start, length); 634 } 635 } 636 637 638 /** 639 * Filter a processing instruction event. 640 * 641 * @param target The processing instruction target. 642 * @param data The text following the target. 643 * @exception org.xml.sax.SAXException The client may throw 644 * an exception during processing. 645 * @see org.xml.sax.ContentHandler#processingInstruction 646 */ 647 public void processingInstruction (String target, String data) 648 throws SAXException 649 { 650 if (contentHandler != null) { 651 contentHandler.processingInstruction(target, data); 652 } 653 } 654 655 656 /** 657 * Filter a skipped entity event. 658 * 659 * @param name The name of the skipped entity. 660 * @exception org.xml.sax.SAXException The client may throw 661 * an exception during processing. 662 * @see org.xml.sax.ContentHandler#skippedEntity 663 */ 664 public void skippedEntity (String name) 665 throws SAXException 666 { 667 if (contentHandler != null) { 668 contentHandler.skippedEntity(name); 669 } 670 } 671 672 673 674 //////////////////////////////////////////////////////////////////// 675 // Implementation of org.xml.sax.ErrorHandler. 676 //////////////////////////////////////////////////////////////////// 677 678 679 /** 680 * Filter a warning event. 681 * 682 * @param e The nwarning as an exception. 683 * @exception org.xml.sax.SAXException The client may throw 684 * an exception during processing. 685 * @see org.xml.sax.ErrorHandler#warning 686 */ 687 public void warning (SAXParseException e) 688 throws SAXException 689 { 690 if (errorHandler != null) { 691 errorHandler.warning(e); 692 } 693 } 694 695 696 /** 697 * Filter an error event. 698 * 699 * @param e The error as an exception. 700 * @exception org.xml.sax.SAXException The client may throw 701 * an exception during processing. 702 * @see org.xml.sax.ErrorHandler#error 703 */ 704 public void error (SAXParseException e) 705 throws SAXException 706 { 707 if (errorHandler != null) { 708 errorHandler.error(e); 709 } 710 } 711 712 713 /** 714 * Filter a fatal error event. 715 * 716 * @param e The error as an exception. 717 * @exception org.xml.sax.SAXException The client may throw 718 * an exception during processing. 719 * @see org.xml.sax.ErrorHandler#fatalError 720 */ 721 public void fatalError (SAXParseException e) 722 throws SAXException 723 { 724 if (errorHandler != null) { 725 errorHandler.fatalError(e); 726 } 727 } 728 729 730 731 //////////////////////////////////////////////////////////////////// 732 // Internal methods. 733 //////////////////////////////////////////////////////////////////// 734 735 736 /** 737 * Set up before a parse. 738 * 739 * <p>Before every parse, check whether the parent is 740 * non-null, and re-register the filter for all of the 741 * events.</p> 742 */ 743 private void setupParse () 744 { 745 if (parent == null) { 746 throw new NullPointerException("No parent for filter"); 747 } 748 parent.setEntityResolver(this); 749 parent.setDTDHandler(this); 750 parent.setContentHandler(this); 751 parent.setErrorHandler(this); 752 } 753 754 755 756 //////////////////////////////////////////////////////////////////// 757 // Internal state. 758 //////////////////////////////////////////////////////////////////// 759 760 private XMLReader parent = null; 761 private Locator locator = null; 762 private EntityResolver entityResolver = null; 763 private DTDHandler dtdHandler = null; 764 private ContentHandler contentHandler = null; 765 private ErrorHandler errorHandler = null; 766 767} 768 769// end of XMLFilterImpl.java