X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.xml.sax.base%2Fsrc%2Forg%2Fsimantics%2Fxml%2Fsax%2Fbase%2FXMLParser.java;fp=org.simantics.xml.sax.base%2Fsrc%2Forg%2Fsimantics%2Fxml%2Fsax%2Fbase%2FXMLParser.java;h=be8fef042f4cb882d97d73aac759c5661ef63bb9;hb=ada38ab0a1a98dcb413bef3273064da36ce2d273;hp=0000000000000000000000000000000000000000;hpb=db6def39515fd442543064502a9ae7ae07ffc160;p=simantics%2Finterop.git diff --git a/org.simantics.xml.sax.base/src/org/simantics/xml/sax/base/XMLParser.java b/org.simantics.xml.sax.base/src/org/simantics/xml/sax/base/XMLParser.java new file mode 100644 index 0000000..be8fef0 --- /dev/null +++ b/org.simantics.xml.sax.base/src/org/simantics/xml/sax/base/XMLParser.java @@ -0,0 +1,237 @@ +package org.simantics.xml.sax.base; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.Serializable; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.simantics.db.Resource; +import org.simantics.db.WriteGraph; +import org.simantics.db.exception.DatabaseException; +import org.simantics.message.ILogger; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +public class XMLParser extends DefaultHandler implements Serializable { + + private static final long serialVersionUID = 7360740940824360338L; + private static final boolean debug = false; + private ILogger logger; + private Resource root; + private Deque current = new ArrayDeque(); + private Map parsers = new HashMap(); + private WriteGraph graph; + + private Map, XMLElementParser> namedParsers = new HashMap, XMLElementParser>(); + + public XMLParser(WriteGraph graph) { + this.graph = graph; + } + + public void add(XMLElementParser parser) { + if (parser.getElementId() != null) + parsers.put(parser.getElementId(), parser); + namedParsers.put(parser.getClass(), parser); + } + + + private List idReferenceElements = new ArrayList(); + private void loadElement(Deque parents, Element element) throws SAXException{ + XMLElementParser parser = null; + Element parent = null; + if (parents.size() > 0) { + parent = parents.peek(); + if (parent.getParser() instanceof XMLElementNamedChildParser) { + // use parent's named child parser if it is supported + Class parserClass = ((XMLElementNamedChildParser)parent.getParser()).getParser(parsers,parent,element); + if (parserClass != null) { + parser = namedParsers.get(parserClass); + if (parser == null) { + try { + parser = parserClass.newInstance(); + namedParsers.put(parserClass, parser); + } catch (IllegalAccessException | InstantiationException e) { + String err = "Element parsers must have accessible default constructor"; + logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err)); + throw new SAXException(err, e); + } + } + } +// if (parser == null && ((XMLElementNamedChildParser)parent.getParser()).useGlobalRules()) +// parser = parsers.get(element.qName); + } else { + // otherwise use globally configured element parser + parser = parsers.get(element.qName); + } + } else { + // use globally configured element parser + parser = parsers.get(element.qName); + } + + if (parser != null) { + try { + + element.setData(parser.create(graph, element)); + if (parser instanceof IDReferenceParser) + idReferenceElements.add(element); + element.setParser(parser); + } catch (DatabaseException e) { + throw new SAXException(e); + } + } else { + if (parent == null && parents.size() > 0) + parent = parents.peek(); + String err = "Unknown element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None"); + logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err)); + if (debug) System.err.println(err); + } + } + + private Map idMap = new HashMap(); + + private void handleElement(Deque parents, Element element) throws SAXException{ + XMLElementParser parser = element.getParser(); + if (parser != null) { + try { + parser.configure(graph, parents, element); + if (parents.size() > 0) { + Element parent = parents.peek(); + if (parent.getParser() != null) { + if (!parent.getParser().connectChild(graph, parent, element)) + if (!parser.connectParent(graph, parent, element)) { + String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None"); + logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err)); + if (debug) System.err.println(err); + } + } else { + String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None") + " was not imported"; + logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err)); + if (debug) System.err.println(err); + } + } + String id = parser.getID(); + if (id != null) { + Element existing = idMap.put(id, element); + if (existing != null) { + // report error + use id priorities to select the kept element. + boolean useExt = existing.parser.idPriority() > element.parser.idPriority(); + if (useExt) + idMap.put(id, existing); + String err = "Duplicate XML element id: " + id + " for " + element.getQName() + " and " + existing.getQName() + ", using " + (useExt ? existing.getQName() : element.getQName()); + logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err)); + if (debug) System.err.println(err); + } + } + } catch (DatabaseException e) { + throw new SAXException(e); + } + } else { + Element parent = parents.peek(); + if (parent != null) { + parser = parent.getParser(); + if (parser != null && parser instanceof UnrecognizedElementParser) { + try { + ((UnrecognizedElementParser)parser).configureChild(graph, parents, parent, element); + } catch (DatabaseException e) { + throw new SAXException(e); + } + } + } + } + } + + private void handleCharacters(Element element, String string) throws SAXException{ + XMLElementParser parser = element.getParser(); + if (parser != null) { + try { + parser.configure(graph, element, string); + } catch (DatabaseException e) { + logger.log(new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage())); + throw new SAXException(e); + } + } + } + + private static String PLUGIN_ID = "org.simantics.xml.sax.base"; + + public void done() throws SAXException{ + try { + for (Element e : idReferenceElements) { + IDReferenceParser parser = (IDReferenceParser)parsers.get(e.qName); + if (!parser.connectReferences(graph, e, idMap)) { + String err ="Could not resolve ID references for " + e.getQName() + " " + e.getUri(); + logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err)); + if (debug) System.err.println(err); + } + } + } catch (DatabaseException e) { + throw new SAXException(e); + } + } + + public Resource getRoot() { + return root; + } + + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { + Element e = new Element(uri,localName,name,attributes); + + loadElement(current,e); + current.push(e); + } + + @Override + public void endElement(String uri, String localName, String name) + throws SAXException { + Element e = null; + if (!current.isEmpty()) { + e = current.pop(); + } + if (e != null) { + handleElement(current,e); + } + if (current.isEmpty()) { + root = e.getData(); + } + } + + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + + if (!current.isEmpty()) { + String s = new String(ch,start,length); + Element e = current.peek(); + handleCharacters(e, s); + } + + } + + public void parse(File file, ILogger logger) throws Exception { + this.logger = logger; + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser saxParser = spf.newSAXParser(); + + XMLReader reader = saxParser.getXMLReader(); + reader.setContentHandler(this); + reader.parse(new InputSource(new BufferedInputStream(new FileInputStream(file)))); + done(); + } + + +} \ No newline at end of file