|
FiltersThe SAX interface assumes two basic streams:
With SAX1, programmers quickly realized that it was possible to use these streams in processing chains. Events (or requests) could flow through several different components, or "filters", and each filter could make changes to the stream as it passes through. SAX2 formalizes this design technique by adding a new interface, org.xml.sax.XMLFilter, and a new helper class, org.xml.sax.helpers.XMLFilterImpl. These can be used to construct event processing pipelines, and can be used in two modes:
Long filter chains are not always the best approach, but you will find that it is sometimes easier to build complex XML applications if you can break them down into a collection of simple SAX components, each one a filter processing events from its parent. org.xml.sax.XMLFilter InterfaceThe XMLFilter interface itself is very simple, extending the basic XMLReader interface with two additional methods: public interface XMLFilter extends XMLReader { public abstract void setParent (XMLReader parent); public abstract XMLReader getParent (); } In other words, a SAX2 XMLFilter is simply an XMLReader that has another XMLReader as its parent. It forwards most requests to that parent, and filters events reported by it, preprocessing them before they are reported to applications. org.xml.sax.helpers.XMLFilterImpl ClassIn one mode, a filter will implement not only the XMLFilter interface but also one or all of the various resolver and handler interfaces (EntityResolver, DTDHandler, ContentHandler, and ErrorHandler) as well as the extension interfaces (DeclHandler, LexicalHandler). To the parent XML reader, the filter is the client application receiving the events; to the client application, the filter is the SAX driver producing the events. The XMLFilterImpl helper class provides a convenient base for deriving SAX2 filters. This class implements the XMLFilter, EntityResolver, DTDHandler, ContentHandler, and ErrorHandler interfaces. (The extension interfaces are not implemented here: DeclHandler and LexicalHandler). By default, it passes all events on unmodified, but the derived filter can override specific methods. Example using XMLFilterImplHere's an example of a very simple filter that changes the
Namespace URI public class FooFilter extends XMLFilterImpl { public FooFilter () { } public FooFilter (XMLReader parent) { super(parent); } /** * Filter the Namespace URI for start-element events. */ public void startElement (String uri, String localName, String qName, Attributes atts) throws SAXException { if (uri.equals("http://www.foo.com/ns/")) { uri = "http://www.bar.com/ns/"; } super.startElement(uri, localName, qName, atts); } /** * Filter the Namespace URI for end-element events. */ public void endElement (String uri, String localName, String qName) throws SAXException { if (uri.equals("http://www.foo.com/ns/")) { uri = "http://www.bar.com/ns/"; } super.endElement(uri, localName, qName); } } Note the use of super.startElement and super.endElement to send the event on to the client. In a real filter, it would be good to override the ContentHandler.startPrefixMapping and ContentHandler.endPrefixMapping methods as well as checking namespaces found in Attributes, so that the SAX event stream is internally consistent (well formed). |