Created
May 12, 2009 10:05
-
-
Save moriyoshi/110407 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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