Skip to content

Instantly share code, notes, and snippets.

@moriyoshi
Created May 12, 2009 10:05
Show Gist options
  • Save moriyoshi/110407 to your computer and use it in GitHub Desktop.
Save moriyoshi/110407 to your computer and use it in GitHub Desktop.
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import org.xml.sax.ContentHandler;
import org.xml.sax.Attributes;
import org.xml.sax.XMLReader;
import org.xml.sax.InputSource;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import javax.xml.parsers.SAXParserFactory;
import java.util.Stack;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.ArrayList;
class SemanticException extends SAXException {
public SemanticException() {}
public SemanticException(String msg) {
super(msg);
}
}
interface Dispatchee {
public void $(char[] ch, int start, int len);
}
class DispatchingHandler extends DefaultHandler {
static class MethodMapPair {
public final Map<String, Method> beginMethodMap;
public final Map<String, Method> endMethodMap;
public MethodMapPair() {
beginMethodMap = new HashMap<String, Method>();
endMethodMap = new HashMap<String, Method>();
}
}
final static Map<Class<? extends Dispatchee>, MethodMapPair> methodMaps;
Dispatchee o;
MethodMapPair mapPair;
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
Method m = mapPair.beginMethodMap.get(qName);
if (m == null)
throw new SemanticException("Unexpected element: " + qName);
try {
m.invoke(o, attributes);
} catch (IllegalAccessException e) {
throw new SAXException(e);
} catch (IllegalArgumentException e) {
throw new SAXException(e);
} catch (InvocationTargetException e) {
Throwable te = e.getTargetException();
if (te instanceof SemanticException)
throw (SemanticException)te;
else if (te instanceof RuntimeException)
throw (RuntimeException)te;
else if (te instanceof Error)
throw (Error)te;
throw new SAXException((Exception)te);
}
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
Method m = mapPair.endMethodMap.get(qName);
if (m == null)
return;
try {
m.invoke(o);
} catch (IllegalAccessException e) {
throw new SAXException(e);
} catch (IllegalArgumentException e) {
throw new SAXException(e);
} catch (InvocationTargetException e) {
Throwable te = e.getTargetException();
if (te instanceof SemanticException)
throw (SemanticException)te;
else if (te instanceof RuntimeException)
throw (RuntimeException)te;
else if (te instanceof Error)
throw (Error)te;
throw new SAXException((Exception)te);
}
}
public void characters(char[] ch, int start, int len) {
o.$(ch, start, len);
}
public void setDispatchee(Dispatchee o) {
this.o = o;
this.mapPair = getMethodMap(o.getClass());
}
public DispatchingHandler(Dispatchee o) {
setDispatchee(o);
}
public DispatchingHandler() {}
static MethodMapPair getMethodMap(Class<? extends Dispatchee> klass) {
synchronized (methodMaps) {
MethodMapPair retval = methodMaps.get(klass);
if (retval != null)
return retval;
retval = new MethodMapPair();
for (Method m: klass.getMethods()) {
Class<?>[] paramTypes = m.getParameterTypes();
String name = m.getName();
if (name.equals("$"))
continue;
if (!name.startsWith("_")) {
if (paramTypes.length == 1 && paramTypes[0] == Attributes.class)
retval.beginMethodMap.put(name, m);
} else {
if (paramTypes.length == 0)
retval.endMethodMap.put(name.substring(1), m);
}
}
methodMaps.put(klass, retval);
return retval;
}
}
static {
methodMaps = new HashMap<Class<? extends Dispatchee>, MethodMapPair>();
}
}
class EasyHandler extends DispatchingHandler implements Dispatchee {
public EasyHandler() {
super();
setDispatchee(this);
}
public void $(char[] ch, int start, int len) {}
}
public class SAXTest {
public static void main(String[] args) throws Exception {
final SAXParserFactory spf = SAXParserFactory.newInstance();
final XMLReader parser = spf.newSAXParser().getXMLReader();
final Stack<ContentHandler> stack = new Stack<ContentHandler>();
final List<List<String>> lists = new ArrayList<List<String>>();
parser.setContentHandler(new EasyHandler() {
public void document(Attributes attrs) {
stack.push(this);
parser.setContentHandler(new EasyHandler() {
public void list(Attributes attrs) {
stack.push(this);
parser.setContentHandler(new EasyHandler() {
List<String> items = new ArrayList<String>();
public void item(Attributes attrs) {
stack.push(this);
parser.setContentHandler(new EasyHandler() {
StringBuffer buf = new StringBuffer();
public void $(char[] ch, int start, int len) {
buf.append(ch, start, len);
}
public void _item() {
items.add(buf.toString());
parser.setContentHandler(stack.pop());
}
});
}
public void _list() {
lists.add(items);
parser.setContentHandler(stack.pop());
}
});
}
public void _document() {
parser.setContentHandler(stack.pop());
}
});
}
});
parser.parse(new InputSource(System.in));
for (int i = 0; i < lists.size(); ++i) {
System.out.printf("List #%d:\n", i);
for (String str: lists.get(i)) {
System.out.printf(" * %s\n", str);
}
}
}
}
// vim: sts=2 sw=2 ts=2 et
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment