Saturday 29 April 2017

android - Java SAX parser & multiple ContentHandlers




I've written a Java SAX parser, on Android, using XmlReader and DefaultHandler.



Its growing size has become unwieldy so what I want to do is delegate responsibility for content beneath certain elements to 'child' handlers.



Suppose I have the XML:














I intended to have the original handler implementation handover to separate respective handlers for apples, oranges etc, and have those hand back when done.



Therefore, I do something a bit like this:




@Override
public void startElement( ... ) ...
{
//...

if ( localName.equals("oranges"))
{
ContentHandler orangeHandler = new OrangeHandler( xmlReader, this );
xmlReader.setContentHandler( orangeHandler );
}


super.startElement( uri, localName, qName, attributes );
}


and then restore the main handler in a similar way.



What I expect to see: further calls to startElement(), characters(), endElement() etc go to the new handler.



What I actually see: that, but continued calls to those methods on the main handler as well.




Javadoc says:




public void setContentHandler(ContentHandler handler)



Allow an application to register a content event handler.



If the application does not register a content handler, all content events reported by the SAX parser will be silently ignored.




Applications may register a new or different handler in the middle of a parse, and the SAX parser must begin using the new handler
immediately.




I can get around the reporting behaviour by keeping my own record of whether I'm delegating or not, and ignoring those surplus calls, but it makes me wonder if I'm doing something stupid that will bite me later.



Does anyone have experience of this?


Answer



I think it's perhaps easier to maintain your original SAX parser that issues your callbacks, and substitute in separate handlers underneath that simply proxy the SAX callback methods with different implementations, but don't perform the actual XML reading, as you're currently doing.




e.g. (in pseudocode)



class SaxHandler {
SaxProxy proxy = new SaxProxyImpl();
public void startElement(e) {
proxy.startElement(e);
}
}



and swap your proxy to a different implementation as required. I suspect you'll need a stack of proxies, and pop your stack upon the appropriate endElement() callback.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...