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