// XAAL toolkit // Copyright (C) 2009 Ville Karavirta // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package xaal.parser; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Stack; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; /** * Xaal parser: a general parser that allows specifying classes that handle * certain types of elements. For example, by specifying a start/endElement(...) * in a class that extend the class xaal.parser.ParserModule and * registering the class to the main "parser" the parser passes the SAX * events of such element to the registered class. * * The xaal.parser.ParserModule has methods for passing information between different * parser modules using the get/setProperty methods. It also contains a stack of the * elements that can (and should) be used when parsing xml. * * @author vkaravir@cs.hut.fi * @see xaal.parser.ParserModule * */ public class XmlParser implements ContentHandler { private HashMap startTagHandlers; private HashMap endTagHandlers; private Stack currHandlers; public XmlParser() { startTagHandlers = new HashMap(); endTagHandlers = new HashMap(); currHandlers = new Stack(); } public void characters(char[] ch, int start, int length) throws SAXException { if (!currHandlers.isEmpty()) { List l = (List) currHandlers.peek(); ListIterator i = l.listIterator(); while (i.hasNext()) { ParserModuleWrapper p = (ParserModuleWrapper) i.next(); p.getParserModule().characters(ch, start, length); } } } public void endDocument() throws SAXException { // TODO Auto-generated method stub } public void endElement(String nsUri, String localName, String qName) throws SAXException { String elemName = cleanString(localName).toLowerCase(); if (endTagHandlers.containsKey(elemName)) { //System.out.println("end element: "+localName); List l = (List) endTagHandlers.get(elemName); ListIterator i = l.listIterator(); while (i.hasNext()) { ParserModuleWrapper p = (ParserModuleWrapper) i.next(); try { p.getMethod().invoke(p.getParserModule(), new Object[] {nsUri, localName, qName}); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } currHandlers.pop(); String currPath = (String) ParserModule.getProperty(ParserModule.CURRENT_PATH); if (currPath.lastIndexOf("/") != -1) { currPath = currPath.substring(0, currPath.lastIndexOf("/")); } else { currPath = ""; } ParserModule.setProperty(ParserModule.CURRENT_PATH, currPath); } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String) */ public void endPrefixMapping(String arg0) throws SAXException { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int) */ public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String, java.lang.String) */ public void processingInstruction(String arg0, String arg1) throws SAXException { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#setDocumentLocator(org.xml.sax.Locator) */ public void setDocumentLocator(Locator arg0) { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String) */ public void skippedEntity(String arg0) throws SAXException { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#startDocument() */ public void startDocument() throws SAXException { ParserModule.setProperty(ParserModule.CURRENT_PATH, ""); } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) */ public void startElement(String nsUri, String localName, String qName, Attributes atts) throws SAXException { String elemName = cleanString(localName).toLowerCase(); String currPath = ParserModule.getProperty(ParserModule.CURRENT_PATH).toString(); ParserModule.setProperty(ParserModule.CURRENT_PATH, currPath + "/" + localName); if (startTagHandlers.containsKey(elemName)) { //System.out.println("start element: "+localName); List l = (List) startTagHandlers.get(elemName); currHandlers.push(l); ListIterator i = l.listIterator(); while (i.hasNext()) { ParserModuleWrapper p = (ParserModuleWrapper) i.next(); try { p.getMethod().invoke(p.getParserModule(), new Object[] {nsUri, localName, qName, atts}); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } else { //System.out.println("unsupported element: " + localName); currHandlers.push(new ArrayList(1)); } } private String cleanString(String localName) { // TODO Correctly handle CombiningChar and Extender // see http://www.w3.org/TR/2006/REC-xml-20060816/#NT-CombiningChar // and http://www.w3.org/TR/2006/REC-xml-20060816/#NT-Extender String[] chars = new String[] { "\\.","\\-","\\_", "\\:"}; for (int i = 0; i < chars.length; i++) { localName = localName.replaceAll(chars[i], ""); } return localName; } /* (non-Javadoc) * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String, java.lang.String) */ public void startPrefixMapping(String arg0, String arg1) throws SAXException { // TODO Auto-generated method stub } public void registerParserModule(ParserModule pm) { Method[] methods = pm.getClass().getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; if (method.getName().startsWith("startElement")) { String tagName = method.getName().substring(12).toLowerCase(); ParserModuleWrapper pmw = new ParserModuleWrapper(pm, method); List l = (List) startTagHandlers.get(tagName); if (l == null) { l = new ArrayList(); } l.add(pmw); startTagHandlers.put(tagName, l); } else if (method.getName().startsWith("endElement")) { String tagName = method.getName().substring(10).toLowerCase(); ParserModuleWrapper pmw = new ParserModuleWrapper(pm, method); List l = (List) endTagHandlers.get(tagName); if (l == null) { l = new ArrayList(); } l.add(pmw); endTagHandlers.put(tagName, l); } } } public void registerParserModule(String className) throws ParserModuleException { Class c; try { c = Class.forName(className); Object o = c.newInstance(); if (o instanceof ParserModule) registerParserModule((ParserModule) o); else throw new ParserModuleException("Failed to register ParserModule " + className + ": class not instance of fi.tkk.cs.svg.xmlparser.ParserModule."); return; } catch (Exception e) { throw new ParserModuleException("Failed to register ParserModule " + className, e); } } public void parse(String fileName) throws SAXException, IOException { XMLReader parser = XMLReaderFactory.createXMLReader(); ErrorHandler errh = new XaalErrorHandler(); parser.setContentHandler(this); parser.setErrorHandler(errh); //parser.parse("/home/vkaravir/projects/dippa/schema/out.xaal"); parser.parse(fileName); } public void parse(InputSource in) throws IOException, SAXException { XMLReader parser = XMLReaderFactory.createXMLReader(); ErrorHandler errh = new XaalErrorHandler(); parser.setContentHandler(this); parser.setErrorHandler(errh); parser.parse(in); } public void parse(InputStream in) throws IOException, SAXException { parse(new InputSource(in)); } public void parse(Reader in) throws IOException, SAXException { parse(new InputSource(in)); } }