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