The XMLFilterImpl Class

SAX includes an adapter class you can subclass to build these
sorts of two-way filters, org.xml.sax.helpers.XMLFilterImpl.
Its general design is similar to what I’ve shown above.
However, it implements all the relevant interfaces in one
class:

When the parent parser calls back to the
ContentHandler
methods, the XMLFilterImpl passes
the call back to the original
ContentHandler
object stored in the contentHandler field.
For example, here’s the
startElement() method:

The other callback methods are similar.
Thus by default, XMLFilterImpl doesn’t
filter anything, much like the earlier
TransparentFilter example.
However, you can subclass this class and
override those methods where you want to change the data
passed back. You pass your changed data by invoking the usual
callback methods in this class. Since you may have
overridden the relevant methods in a subclass, you may need
to use super to access the methods in
XMLFilterImpl directly.

For example, the startElement()
method in Example 8.12
adds an id attribute to every element that
doesn’t already have one, and then passes
that modified element on to the underlying content handler
to do whatever it needs to do.

You’ll notice that this code is much shorter and simpler than
the programs that implemented
XMLFilter directly.
There’s a lot of code inside XMLFilterImpl
you can reuse without a lot of thought.
When subclassing XMLFilterImpl, you only need
to override the methods that implement the filter.
The remaining methods can be left to the superclass.
In fact, it is so much easier to use
XMLFilterImpl rather than
XMLFilter that almost all
real-world filters are based on
XMLFilterImpl.
A few books even ignore the existence of the XMLFilter
interface completely. I mostly covered it here because I spent
a lot of time being confused by XMLFilter
since I didn’t realize how much more
XMLFilterImpl does. It is not
just an implementation of the XMLFilter
interface.

Since XMLFilterImpl is still an
XMLReader,
the client application uses it like it would use any other
XMLReader, by setting handlers, features, and properties and
then parsing documents. The only difference is that the
client application needs to pass an actual parser object to the
setParent() method before doing anything else.

Here’s the beginning of the output from when I used
IDFilter and
FilterTester
on the RDDL specification, after the usual adjustments for line
length. The initial doc
processing instruction is an artifact of the
XMLWriter class.