1 package org.simantics.xml.sax.base;
\r
3 import java.io.BufferedInputStream;
\r
5 import java.io.FileInputStream;
\r
6 import java.io.Serializable;
\r
7 import java.util.ArrayDeque;
\r
8 import java.util.ArrayList;
\r
9 import java.util.Deque;
\r
10 import java.util.HashMap;
\r
11 import java.util.List;
\r
12 import java.util.Map;
\r
14 import javax.xml.parsers.SAXParser;
\r
15 import javax.xml.parsers.SAXParserFactory;
\r
17 import org.eclipse.core.runtime.IStatus;
\r
18 import org.eclipse.core.runtime.Status;
\r
19 import org.simantics.db.Resource;
\r
20 import org.simantics.db.WriteGraph;
\r
21 import org.simantics.db.exception.DatabaseException;
\r
22 import org.simantics.message.ILogger;
\r
23 import org.xml.sax.Attributes;
\r
24 import org.xml.sax.InputSource;
\r
25 import org.xml.sax.SAXException;
\r
26 import org.xml.sax.XMLReader;
\r
27 import org.xml.sax.helpers.DefaultHandler;
\r
29 public class XMLParser extends DefaultHandler implements Serializable {
\r
31 private static final long serialVersionUID = 7360740940824360338L;
\r
32 private static final boolean debug = false;
\r
33 private ILogger logger;
\r
34 private Resource root;
\r
35 private Deque<Element> current = new ArrayDeque<Element>();
\r
36 private Map<String, XMLElementParser> parsers = new HashMap<String, XMLElementParser>();
\r
37 private WriteGraph graph;
\r
39 private Map<Class<? extends XMLElementParser>, XMLElementParser> namedParsers = new HashMap<Class<? extends XMLElementParser>, XMLElementParser>();
\r
41 public XMLParser(WriteGraph graph) {
\r
45 public void add(XMLElementParser parser) {
\r
46 if (parser.getElementId() != null)
\r
47 parsers.put(parser.getElementId(), parser);
\r
48 namedParsers.put(parser.getClass(), parser);
\r
52 private List<Element> idReferenceElements = new ArrayList<Element>();
\r
53 private void loadElement(Deque<Element> parents, Element element) throws SAXException{
\r
54 XMLElementParser parser = null;
\r
55 Element parent = null;
\r
56 if (parents.size() > 0) {
\r
57 parent = parents.peek();
\r
58 if (parent.getParser() instanceof XMLElementNamedChildParser) {
\r
59 // use parent's named child parser if it is supported
\r
60 Class<? extends XMLElementParser> parserClass = ((XMLElementNamedChildParser)parent.getParser()).getParser(parsers,parent,element);
\r
61 if (parserClass != null) {
\r
62 parser = namedParsers.get(parserClass);
\r
63 if (parser == null) {
\r
65 parser = parserClass.newInstance();
\r
66 namedParsers.put(parserClass, parser);
\r
67 } catch (IllegalAccessException | InstantiationException e) {
\r
68 String err = "Element parsers must have accessible default constructor";
\r
69 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
70 throw new SAXException(err, e);
\r
74 // if (parser == null && ((XMLElementNamedChildParser)parent.getParser()).useGlobalRules())
\r
75 // parser = parsers.get(element.qName);
\r
77 // otherwise use globally configured element parser
\r
78 parser = parsers.get(element.qName);
\r
81 // use globally configured element parser
\r
82 parser = parsers.get(element.qName);
\r
85 if (parser != null) {
\r
88 element.setData(parser.create(graph, element));
\r
89 if (parser instanceof IDReferenceParser)
\r
90 idReferenceElements.add(element);
\r
91 element.setParser(parser);
\r
92 } catch (DatabaseException e) {
\r
93 throw new SAXException(e);
\r
96 if (parent == null && parents.size() > 0)
\r
97 parent = parents.peek();
\r
98 String err = "Unknown element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None");
\r
99 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
100 if (debug) System.err.println(err);
\r
104 private Map<String, Element> idMap = new HashMap<String, Element>();
\r
106 private void handleElement(Deque<Element> parents, Element element) throws SAXException{
\r
107 XMLElementParser parser = element.getParser();
\r
108 if (parser != null) {
\r
110 parser.configure(graph, parents, element);
\r
111 if (parents.size() > 0) {
\r
112 Element parent = parents.peek();
\r
113 if (parent.getParser() != null) {
\r
114 if (!parent.getParser().connectChild(graph, parent, element))
\r
115 if (!parser.connectParent(graph, parent, element)) {
\r
116 String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None");
\r
117 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
118 if (debug) System.err.println(err);
\r
121 String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None") + " was not imported";
\r
122 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
123 if (debug) System.err.println(err);
\r
126 String id = parser.getID();
\r
128 Element existing = idMap.put(id, element);
\r
129 if (existing != null) {
\r
130 // report error + use id priorities to select the kept element.
\r
131 boolean useExt = existing.parser.idPriority() > element.parser.idPriority();
\r
133 idMap.put(id, existing);
\r
134 String err = "Duplicate XML element id: " + id + " for " + element.getQName() + " and " + existing.getQName() + ", using " + (useExt ? existing.getQName() : element.getQName());
\r
135 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
136 if (debug) System.err.println(err);
\r
139 } catch (DatabaseException e) {
\r
140 throw new SAXException(e);
\r
143 Element parent = parents.peek();
\r
144 if (parent != null) {
\r
145 parser = parent.getParser();
\r
146 if (parser != null && parser instanceof UnrecognizedElementParser) {
\r
148 ((UnrecognizedElementParser)parser).configureChild(graph, parents, parent, element);
\r
149 } catch (DatabaseException e) {
\r
150 throw new SAXException(e);
\r
157 private void handleCharacters(Element element, String string) throws SAXException{
\r
158 XMLElementParser parser = element.getParser();
\r
159 if (parser != null) {
\r
161 parser.configure(graph, element, string);
\r
162 } catch (DatabaseException e) {
\r
163 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage()));
\r
164 throw new SAXException(e);
\r
169 private static String PLUGIN_ID = "org.simantics.xml.sax.base";
\r
171 public void done() throws SAXException{
\r
173 for (Element e : idReferenceElements) {
\r
174 IDReferenceParser parser = (IDReferenceParser)parsers.get(e.qName);
\r
175 if (!parser.connectReferences(graph, e, idMap)) {
\r
176 String err ="Could not resolve ID references for " + e.getQName() + " " + e.getUri();
\r
177 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
178 if (debug) System.err.println(err);
\r
181 } catch (DatabaseException e) {
\r
182 throw new SAXException(e);
\r
186 public Resource getRoot() {
\r
191 public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
\r
192 Element e = new Element(uri,localName,name,attributes);
\r
194 loadElement(current,e);
\r
199 public void endElement(String uri, String localName, String name)
\r
200 throws SAXException {
\r
202 if (!current.isEmpty()) {
\r
206 handleElement(current,e);
\r
208 if (current.isEmpty()) {
\r
209 root = e.getData();
\r
214 public void characters(char[] ch, int start, int length)
\r
215 throws SAXException {
\r
217 if (!current.isEmpty()) {
\r
218 String s = new String(ch,start,length);
\r
219 Element e = current.peek();
\r
220 handleCharacters(e, s);
\r
225 public void parse(File file, ILogger logger) throws Exception {
\r
226 this.logger = logger;
\r
227 SAXParserFactory spf = SAXParserFactory.newInstance();
\r
228 SAXParser saxParser = spf.newSAXParser();
\r
230 XMLReader reader = saxParser.getXMLReader();
\r
231 reader.setContentHandler(this);
\r
232 reader.parse(new InputSource(new BufferedInputStream(new FileInputStream(file))));
\r