1 /* 2 * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package org.xml.sax.helpers; 27 28 import java.io.IOException; 29 30 import org.xml.sax.XMLReader; 31 import org.xml.sax.XMLFilter; 32 import org.xml.sax.InputSource; 33 import org.xml.sax.Locator; 34 import org.xml.sax.Attributes; 35 import org.xml.sax.EntityResolver; 36 import org.xml.sax.DTDHandler; 37 import org.xml.sax.ContentHandler; 38 import org.xml.sax.ErrorHandler; 39 import org.xml.sax.SAXException; 40 import org.xml.sax.SAXParseException; 41 import org.xml.sax.SAXNotSupportedException; 42 import org.xml.sax.SAXNotRecognizedException; 43 44 45 /** 46 * Base class for deriving an XML filter. 47 * 48 * <p>This class is designed to sit between an {@link org.xml.sax.XMLReader 49 * XMLReader} and the client application's event handlers. By default, it 50 * does nothing but pass requests up to the reader and events 51 * on to the handlers unmodified, but subclasses can override 52 * specific methods to modify the event stream or the configuration 53 * requests as they pass through.</p> 54 * 55 * @since 1.4, SAX 2.0 56 * @author David Megginson 57 * @see org.xml.sax.XMLFilter 58 * @see org.xml.sax.XMLReader 59 * @see org.xml.sax.EntityResolver 60 * @see org.xml.sax.DTDHandler 61 * @see org.xml.sax.ContentHandler 62 * @see org.xml.sax.ErrorHandler 63 */ 64 public class XMLFilterImpl 65 implements XMLFilter, EntityResolver, DTDHandler, ContentHandler, ErrorHandler 66 { 67 68 69 //////////////////////////////////////////////////////////////////// 70 // Constructors. 71 //////////////////////////////////////////////////////////////////// 72 73 74 /** 75 * Construct an empty XML filter, with no parent. 76 * 77 * <p>This filter will have no parent: you must assign a parent 78 * before you start a parse or do any configuration with 79 * setFeature or setProperty, unless you use this as a pure event 80 * consumer rather than as an {@link XMLReader}.</p> 81 * 82 * @see org.xml.sax.XMLReader#setFeature 83 * @see org.xml.sax.XMLReader#setProperty 84 * @see #setParent 85 */ 86 public XMLFilterImpl () 87 { 88 super(); 89 } 90 91 92 /** 93 * Construct an XML filter with the specified parent. 94 * 95 * @see #setParent 96 * @see #getParent 97 */ 98 public XMLFilterImpl (XMLReader parent) 99 { 100 super(); 101 setParent(parent); 102 } 103 104 105 106 //////////////////////////////////////////////////////////////////// 107 // Implementation of org.xml.sax.XMLFilter. 108 //////////////////////////////////////////////////////////////////// 109 110 111 /** 112 * Set the parent reader. 113 * 114 * <p>This is the {@link org.xml.sax.XMLReader XMLReader} from which 115 * this filter will obtain its events and to which it will pass its 116 * configuration requests. The parent may itself be another filter.</p> 117 * 118 * <p>If there is no parent reader set, any attempt to parse 119 * or to set or get a feature or property will fail.</p> 120 * 121 * @param parent The parent XML reader. 122 * @see #getParent 123 */ 124 public void setParent (XMLReader parent) 125 { 126 this.parent = parent; 127 } 128 129 130 /** 131 * Get the parent reader. 132 * 133 * @return The parent XML reader, or null if none is set. 134 * @see #setParent 135 */ 136 public XMLReader getParent () 137 { 138 return parent; 139 } 140 141 142 143 //////////////////////////////////////////////////////////////////// 144 // Implementation of org.xml.sax.XMLReader. 145 //////////////////////////////////////////////////////////////////// 146 147 148 /** 149 * Set the value of a feature. 150 * 151 * <p>This will always fail if the parent is null.</p> 152 * 153 * @param name The feature name. 154 * @param value The requested feature value. 155 * @exception org.xml.sax.SAXNotRecognizedException If the feature 156 * value can't be assigned or retrieved from the parent. 157 * @exception org.xml.sax.SAXNotSupportedException When the 158 * parent recognizes the feature name but 159 * cannot set the requested value. 160 */ 161 public void setFeature (String name, boolean value) 162 throws SAXNotRecognizedException, SAXNotSupportedException 163 { 164 if (parent != null) { 165 parent.setFeature(name, value); 166 } else { 167 throw new SAXNotRecognizedException("Feature: " + name); 168 } 169 } 170 171 172 /** 173 * Look up the value of a feature. 174 * 175 * <p>This will always fail if the parent is null.</p> 176 * 177 * @param name The feature name. 178 * @return The current value of the feature. 179 * @exception org.xml.sax.SAXNotRecognizedException If the feature 180 * value can't be assigned or retrieved from the parent. 181 * @exception org.xml.sax.SAXNotSupportedException When the 182 * parent recognizes the feature name but 183 * cannot determine its value at this time. 184 */ 185 public boolean getFeature (String name) 186 throws SAXNotRecognizedException, SAXNotSupportedException 187 { 188 if (parent != null) { 189 return parent.getFeature(name); 190 } else { 191 throw new SAXNotRecognizedException("Feature: " + name); 192 } 193 } 194 195 196 /** 197 * Set the value of a property. 198 * 199 * <p>This will always fail if the parent is null.</p> 200 * 201 * @param name The property name. 202 * @param value The requested property value. 203 * @exception org.xml.sax.SAXNotRecognizedException If the property 204 * value can't be assigned or retrieved from the parent. 205 * @exception org.xml.sax.SAXNotSupportedException When the 206 * parent recognizes the property name but 207 * cannot set the requested value. 208 */ 209 public void setProperty (String name, Object value) 210 throws SAXNotRecognizedException, SAXNotSupportedException 211 { 212 if (parent != null) { 213 parent.setProperty(name, value); 214 } else { 215 throw new SAXNotRecognizedException("Property: " + name); 216 } 217 } 218 219 220 /** 221 * Look up the value of a property. 222 * 223 * @param name The property name. 224 * @return The current value of the property. 225 * @exception org.xml.sax.SAXNotRecognizedException If the property 226 * value can't be assigned or retrieved from the parent. 227 * @exception org.xml.sax.SAXNotSupportedException When the 228 * parent recognizes the property name but 229 * cannot determine its value at this time. 230 */ 231 public Object getProperty (String name) 232 throws SAXNotRecognizedException, SAXNotSupportedException 233 { 234 if (parent != null) { 235 return parent.getProperty(name); 236 } else { 237 throw new SAXNotRecognizedException("Property: " + name); 238 } 239 } 240 241 242 /** 243 * Set the entity resolver. 244 * 245 * @param resolver The new entity resolver. 246 */ 247 public void setEntityResolver (EntityResolver resolver) 248 { 249 entityResolver = resolver; 250 } 251 252 253 /** 254 * Get the current entity resolver. 255 * 256 * @return The current entity resolver, or null if none was set. 257 */ 258 public EntityResolver getEntityResolver () 259 { 260 return entityResolver; 261 } 262 263 264 /** 265 * Set the DTD event handler. 266 * 267 * @param handler the new DTD handler 268 */ 269 public void setDTDHandler (DTDHandler handler) 270 { 271 dtdHandler = handler; 272 } 273 274 275 /** 276 * Get the current DTD event handler. 277 * 278 * @return The current DTD handler, or null if none was set. 279 */ 280 public DTDHandler getDTDHandler () 281 { 282 return dtdHandler; 283 } 284 285 286 /** 287 * Set the content event handler. 288 * 289 * @param handler the new content handler 290 */ 291 public void setContentHandler (ContentHandler handler) 292 { 293 contentHandler = handler; 294 } 295 296 297 /** 298 * Get the content event handler. 299 * 300 * @return The current content handler, or null if none was set. 301 */ 302 public ContentHandler getContentHandler () 303 { 304 return contentHandler; 305 } 306 307 308 /** 309 * Set the error event handler. 310 * 311 * @param handler the new error handler 312 */ 313 public void setErrorHandler (ErrorHandler handler) 314 { 315 errorHandler = handler; 316 } 317 318 319 /** 320 * Get the current error event handler. 321 * 322 * @return The current error handler, or null if none was set. 323 */ 324 public ErrorHandler getErrorHandler () 325 { 326 return errorHandler; 327 } 328 329 330 /** 331 * Parse a document. 332 * 333 * @param input The input source for the document entity. 334 * @exception org.xml.sax.SAXException Any SAX exception, possibly 335 * wrapping another exception. 336 * @exception java.io.IOException An IO exception from the parser, 337 * possibly from a byte stream or character stream 338 * supplied by the application. 339 */ 340 public void parse (InputSource input) 341 throws SAXException, IOException 342 { 343 setupParse(); 344 parent.parse(input); 345 } 346 347 348 /** 349 * Parse a document. 350 * 351 * @param systemId The system identifier as a fully-qualified URI. 352 * @exception org.xml.sax.SAXException Any SAX exception, possibly 353 * wrapping another exception. 354 * @exception java.io.IOException An IO exception from the parser, 355 * possibly from a byte stream or character stream 356 * supplied by the application. 357 */ 358 public void parse (String systemId) 359 throws SAXException, IOException 360 { 361 parse(new InputSource(systemId)); 362 } 363 364 365 366 //////////////////////////////////////////////////////////////////// 367 // Implementation of org.xml.sax.EntityResolver. 368 //////////////////////////////////////////////////////////////////// 369 370 371 /** 372 * Filter an external entity resolution. 373 * 374 * @param publicId The entity's public identifier, or null. 375 * @param systemId The entity's system identifier. 376 * @return A new InputSource or null for the default. 377 * @exception org.xml.sax.SAXException The client may throw 378 * an exception during processing. 379 * @exception java.io.IOException The client may throw an 380 * I/O-related exception while obtaining the 381 * new InputSource. 382 */ 383 public InputSource resolveEntity (String publicId, String systemId) 384 throws SAXException, IOException 385 { 386 if (entityResolver != null) { 387 return entityResolver.resolveEntity(publicId, systemId); 388 } else { 389 return null; 390 } 391 } 392 393 394 395 //////////////////////////////////////////////////////////////////// 396 // Implementation of org.xml.sax.DTDHandler. 397 //////////////////////////////////////////////////////////////////// 398 399 400 /** 401 * Filter a notation declaration event. 402 * 403 * @param name The notation name. 404 * @param publicId The notation's public identifier, or null. 405 * @param systemId The notation's system identifier, or null. 406 * @exception org.xml.sax.SAXException The client may throw 407 * an exception during processing. 408 */ 409 public void notationDecl (String name, String publicId, String systemId) 410 throws SAXException 411 { 412 if (dtdHandler != null) { 413 dtdHandler.notationDecl(name, publicId, systemId); 414 } 415 } 416 417 418 /** 419 * Filter an unparsed entity declaration event. 420 * 421 * @param name The entity name. 422 * @param publicId The entity's public identifier, or null. 423 * @param systemId The entity's system identifier, or null. 424 * @param notationName The name of the associated notation. 425 * @exception org.xml.sax.SAXException The client may throw 426 * an exception during processing. 427 */ 428 public void unparsedEntityDecl (String name, String publicId, 429 String systemId, String notationName) 430 throws SAXException 431 { 432 if (dtdHandler != null) { 433 dtdHandler.unparsedEntityDecl(name, publicId, systemId, 434 notationName); 435 } 436 } 437 438 439 440 //////////////////////////////////////////////////////////////////// 441 // Implementation of org.xml.sax.ContentHandler. 442 //////////////////////////////////////////////////////////////////// 443 444 445 /** 446 * Filter a new document locator event. 447 * 448 * @param locator The document locator. 449 */ 450 public void setDocumentLocator (Locator locator) 451 { 452 this.locator = locator; 453 if (contentHandler != null) { 454 contentHandler.setDocumentLocator(locator); 455 } 456 } 457 458 459 /** 460 * Filter a start document event. 461 * 462 * @exception org.xml.sax.SAXException The client may throw 463 * an exception during processing. 464 */ 465 public void startDocument () 466 throws SAXException 467 { 468 if (contentHandler != null) { 469 contentHandler.startDocument(); 470 } 471 } 472 473 474 /** 475 * Filter an end document event. 476 * 477 * @exception org.xml.sax.SAXException The client may throw 478 * an exception during processing. 479 */ 480 public void endDocument () 481 throws SAXException 482 { 483 if (contentHandler != null) { 484 contentHandler.endDocument(); 485 } 486 } 487 488 489 /** 490 * Filter a start Namespace prefix mapping event. 491 * 492 * @param prefix The Namespace prefix. 493 * @param uri The Namespace URI. 494 * @exception org.xml.sax.SAXException The client may throw 495 * an exception during processing. 496 */ 497 public void startPrefixMapping (String prefix, String uri) 498 throws SAXException 499 { 500 if (contentHandler != null) { 501 contentHandler.startPrefixMapping(prefix, uri); 502 } 503 } 504 505 506 /** 507 * Filter an end Namespace prefix mapping event. 508 * 509 * @param prefix The Namespace prefix. 510 * @exception org.xml.sax.SAXException The client may throw 511 * an exception during processing. 512 */ 513 public void endPrefixMapping (String prefix) 514 throws SAXException 515 { 516 if (contentHandler != null) { 517 contentHandler.endPrefixMapping(prefix); 518 } 519 } 520 521 522 /** 523 * Filter a start element event. 524 * 525 * @param uri The element's Namespace URI, or the empty string. 526 * @param localName The element's local name, or the empty string. 527 * @param qName The element's qualified (prefixed) name, or the empty 528 * string. 529 * @param atts The element's attributes. 530 * @exception org.xml.sax.SAXException The client may throw 531 * an exception during processing. 532 */ 533 public void startElement (String uri, String localName, String qName, 534 Attributes atts) 535 throws SAXException 536 { 537 if (contentHandler != null) { 538 contentHandler.startElement(uri, localName, qName, atts); 539 } 540 } 541 542 543 /** 544 * Filter an end element event. 545 * 546 * @param uri The element's Namespace URI, or the empty string. 547 * @param localName The element's local name, or the empty string. 548 * @param qName The element's qualified (prefixed) name, or the empty 549 * string. 550 * @exception org.xml.sax.SAXException The client may throw 551 * an exception during processing. 552 */ 553 public void endElement (String uri, String localName, String qName) 554 throws SAXException 555 { 556 if (contentHandler != null) { 557 contentHandler.endElement(uri, localName, qName); 558 } 559 } 560 561 562 /** 563 * Filter a character data event. 564 * 565 * @param ch An array of characters. 566 * @param start The starting position in the array. 567 * @param length The number of characters to use from the array. 568 * @exception org.xml.sax.SAXException The client may throw 569 * an exception during processing. 570 */ 571 public void characters (char ch[], int start, int length) 572 throws SAXException 573 { 574 if (contentHandler != null) { 575 contentHandler.characters(ch, start, length); 576 } 577 } 578 579 580 /** 581 * Filter an ignorable whitespace event. 582 * 583 * @param ch An array of characters. 584 * @param start The starting position in the array. 585 * @param length The number of characters to use from the array. 586 * @exception org.xml.sax.SAXException The client may throw 587 * an exception during processing. 588 */ 589 public void ignorableWhitespace (char ch[], int start, int length) 590 throws SAXException 591 { 592 if (contentHandler != null) { 593 contentHandler.ignorableWhitespace(ch, start, length); 594 } 595 } 596 597 598 /** 599 * Filter a processing instruction event. 600 * 601 * @param target The processing instruction target. 602 * @param data The text following the target. 603 * @exception org.xml.sax.SAXException The client may throw 604 * an exception during processing. 605 */ 606 public void processingInstruction (String target, String data) 607 throws SAXException 608 { 609 if (contentHandler != null) { 610 contentHandler.processingInstruction(target, data); 611 } 612 } 613 614 615 /** 616 * Filter a skipped entity event. 617 * 618 * @param name The name of the skipped entity. 619 * @exception org.xml.sax.SAXException The client may throw 620 * an exception during processing. 621 */ 622 public void skippedEntity (String name) 623 throws SAXException 624 { 625 if (contentHandler != null) { 626 contentHandler.skippedEntity(name); 627 } 628 } 629 630 631 632 //////////////////////////////////////////////////////////////////// 633 // Implementation of org.xml.sax.ErrorHandler. 634 //////////////////////////////////////////////////////////////////// 635 636 637 /** 638 * Filter a warning event. 639 * 640 * @param e The warning as an exception. 641 * @exception org.xml.sax.SAXException The client may throw 642 * an exception during processing. 643 */ 644 public void warning (SAXParseException e) 645 throws SAXException 646 { 647 if (errorHandler != null) { 648 errorHandler.warning(e); 649 } 650 } 651 652 653 /** 654 * Filter an error event. 655 * 656 * @param e The error as an exception. 657 * @exception org.xml.sax.SAXException The client may throw 658 * an exception during processing. 659 */ 660 public void error (SAXParseException e) 661 throws SAXException 662 { 663 if (errorHandler != null) { 664 errorHandler.error(e); 665 } 666 } 667 668 669 /** 670 * Filter a fatal error event. 671 * 672 * @param e The error as an exception. 673 * @exception org.xml.sax.SAXException The client may throw 674 * an exception during processing. 675 */ 676 public void fatalError (SAXParseException e) 677 throws SAXException 678 { 679 if (errorHandler != null) { 680 errorHandler.fatalError(e); 681 } 682 } 683 684 685 686 //////////////////////////////////////////////////////////////////// 687 // Internal methods. 688 //////////////////////////////////////////////////////////////////// 689 690 691 /** 692 * Set up before a parse. 693 * 694 * <p>Before every parse, check whether the parent is 695 * non-null, and re-register the filter for all of the 696 * events.</p> 697 */ 698 private void setupParse () 699 { 700 if (parent == null) { 701 throw new NullPointerException("No parent for filter"); 702 } 703 parent.setEntityResolver(this); 704 parent.setDTDHandler(this); 705 parent.setContentHandler(this); 706 parent.setErrorHandler(this); 707 } 708 709 710 711 //////////////////////////////////////////////////////////////////// 712 // Internal state. 713 //////////////////////////////////////////////////////////////////// 714 715 private XMLReader parent = null; 716 private Locator locator = null; 717 private EntityResolver entityResolver = null; 718 private DTDHandler dtdHandler = null; 719 private ContentHandler contentHandler = null; 720 private ErrorHandler errorHandler = null; 721 722 } 723 724 // end of XMLFilterImpl.java