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