Java – is there any way to use Sax parser and visitor mode?
I'm curious about this: if I need to use a Sax parser to improve efficiency (this is a big file) Usually I use something like this:
public class Example extends DefaultHandler { private Stack stack = new Stack (); public void startElement (String uri,String local,String qName,Attributes atts) throws SAXException { stack.push (qName); } public void endElement (String uri,String qName) throws SAXException { if ("line".equals (qName)) System.out.println (); stack.pop (); } public void characters (char buf [],int offset,int length) throws SAXException { if (!"line".equals (stack.peek ())) return; System.out.write (new String (buf,offset,length)); } }
Example from here
Sax is already an implementation of visitor pattern, but in my case, I only need to get the content of each element according to the nature of the element itself and do some operations on it
My typical XML file is similar to:
<?xml version="1.0" encoding="utf-8"?> <labs xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <auth> <uid> </uid> <gid> </gid> <key> </key> </auth> <campaign> <sms> <newsletter>206</newsletter> <message> <from>Da Definire</from> <subject>Da definire</subject> <body><![CDATA[Testo Da Definire]]></body> </message> <delivery method="manual"></delivery> <recipients> <db>276</db> <filter> <test>1538</test> </filter> <new_recipients> <csv_file>Corso2012_SMS.csv</csv_file> </new_recipients> </recipients> </sms> </campaign> </labs>
When I was in CSV_ File node, I need to get the file name and upload the user from the file. If I am in the filter / test, I need to check whether the filter exists, etc Is there a way to apply guest mode to Sax?
Solution
You can simply get a map < string, elementhandler > in your sax parser and allow elementhandlers to be registered for element names Suppose you are only interested in leaf elements:
>Each time the element starts, you will check whether there is a handler for this element name in the map and clear the buffer. > Every time characters() is called, characters are appended to the buffer (if there is a handler for the previous element) > at the end of each element, if there is a handler started by the previous element, the handler is called using the contents of the buffer
Here is an example:
private ElementHandler currentHandler; private StringBuilder buffer = new StringBuilder(); private Map<String,ElementHandler> handlers = new HashMap<String,ElementHandler>(); public void registerHandler(String qName,ElementHandler handler) { handlers.put(qName,handler); } public void startElement (String uri,Attributes atts) throws SAXException { currentHandler = handlers.get(qName); buffer.delete(0,buffer.length()); } public void characters (char buf [],int length) throws SAXException { if (currentHandler != null) { buffer.append(buf,length); } } public void endElement (String uri,String qName) throws SAXException { if (currentHandler != null) { currentHandler.handle(buffer.toString(); } }