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 public static String PLUGIN_ID = "org.simantics.xml.sax.base";
\r
32 public static String XML_NAMESPACE_REF = "xmlns";
\r
34 private static final long serialVersionUID = 7360740940824360338L;
\r
35 private static final boolean debug = false;
\r
37 private ILogger logger;
\r
38 private WriteGraph graph;
\r
39 private Resource root;
\r
40 private String schemaURI;
\r
41 private Deque<ParserElement> current = new ArrayDeque<ParserElement>();
\r
42 private Map<String, XMLElementParser> parsers = new HashMap<String, XMLElementParser>();
\r
43 private Map<Class<? extends XMLElementParser>, XMLElementParser> namedParsers = new HashMap<Class<? extends XMLElementParser>, XMLElementParser>();
\r
44 private Map<String, XMLParser> subParsers = new HashMap<String, XMLParser>();
\r
46 public XMLParser() {
\r
50 public WriteGraph getGraph() {
\r
54 public void setGraph(WriteGraph graph) {
\r
56 for (XMLParser p : subParsers.values())
\r
60 public String getSchemaURI() {
\r
64 public void setSchemaURI(String schemaURI) {
\r
65 this.schemaURI = schemaURI;
\r
68 public void add(XMLElementParser parser) {
\r
69 if (parser.getElementId() != null)
\r
70 parsers.put(parser.getElementId(), parser);
\r
71 namedParsers.put(parser.getClass(), parser);
\r
74 public void add(XMLParser parser) {
\r
75 subParsers.put(parser.getSchemaURI(), parser);
\r
78 private List<ParserElement> idReferenceElements = new ArrayList<ParserElement>();
\r
79 private void loadElement(Deque<ParserElement> parents, ParserElement element) throws SAXException{
\r
80 XMLElementParser parser = null;
\r
81 ParserElement parent = null;
\r
82 if (parents.size() > 0) {
\r
83 parent = parents.peek();
\r
84 // check for assigned subparser
\r
85 if (parent.getXMLParser() != null && parent.getXMLParser() != this) {
\r
86 element.setXMLParser(parent.getXMLParser());
\r
87 parent.getXMLParser().loadElement(parents, element);
\r
90 if (parent.getElementParser() instanceof XMLElementNamedChildParser) {
\r
91 // use parent's named child parser if it is supported
\r
92 Class<? extends XMLElementParser> parserClass = ((XMLElementNamedChildParser)parent.getElementParser()).getParser(parsers,parent,element);
\r
93 if (parserClass != null) {
\r
94 parser = namedParsers.get(parserClass);
\r
95 if (parser == null) {
\r
97 parser = parserClass.newInstance();
\r
98 namedParsers.put(parserClass, parser);
\r
99 } catch (IllegalAccessException | InstantiationException e) {
\r
100 String err = "Error processing " + parserClass.getName() + " : element parsers must have accessible default constructor";
\r
101 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
102 throw new SAXException(err, e);
\r
106 // if (parser == null && ((XMLElementNamedChildParser)parent.getParser()).useGlobalRules())
\r
107 // parser = parsers.get(element.qName);
\r
109 // otherwise use globally configured element parser
\r
110 parser = parsers.get(element.qName);
\r
113 // use globally configured element parser
\r
114 parser = parsers.get(element.qName);
\r
117 if (parser != null) {
\r
120 element.setData(parser.create(graph, element));
\r
121 if (parser instanceof IDReferenceParser)
\r
122 idReferenceElements.add(element);
\r
123 element.setElementParser(parser);
\r
124 } catch (DatabaseException e) {
\r
125 throw new SAXException(e);
\r
128 // check for schema reference attempt to locate subparser for it.
\r
129 Attribute schemaRef = element.getAttribute(XML_NAMESPACE_REF);
\r
130 if (schemaRef != null && subParsers.containsKey(schemaRef.value)) {
\r
131 XMLParser subParser = subParsers.get(schemaRef.value);
\r
132 subParser.loadElement(parents, element);
\r
133 element.setXMLParser(subParser);
\r
135 if (parent == null && parents.size() > 0)
\r
136 parent = parents.peek();
\r
137 String err = "Unknown element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None");
\r
138 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
139 if (debug) System.err.println(err);
\r
144 private Map<String, ParserElement> idMap = new HashMap<String, ParserElement>();
\r
146 private void handleElement(Deque<ParserElement> parents, ParserElement element) throws SAXException{
\r
147 XMLElementParser parser = element.getElementParser();
\r
148 if (parser != null) {
\r
150 parser.configure(graph, parents, element);
\r
151 if (parents.size() > 0) {
\r
152 ParserElement parent = parents.peek();
\r
153 if (parent.getElementParser() != null) {
\r
154 if (!parent.getElementParser().connectChild(graph, parent, element))
\r
155 if (!parser.connectParent(graph, parent, element)) {
\r
156 String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None");
\r
157 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
158 if (debug) System.err.println(err);
\r
161 String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None") + " was not imported";
\r
162 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
163 if (debug) System.err.println(err);
\r
166 String id = parser.getID();
\r
168 ParserElement existing = idMap.put(id, element);
\r
169 if (existing != null) {
\r
170 // report error + use id priorities to select the kept element.
\r
171 boolean useExt = existing.elementParser.idPriority() > element.elementParser.idPriority();
\r
173 idMap.put(id, existing);
\r
174 String err = "Duplicate XML element id: " + id + " for " + element.getQName() + " and " + existing.getQName() + ", using " + (useExt ? existing.getQName() : element.getQName());
\r
175 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
176 if (debug) System.err.println(err);
\r
179 } catch (DatabaseException e) {
\r
180 throw new SAXException(e);
\r
183 ParserElement parent = parents.peek();
\r
184 if (parent != null) {
\r
185 parser = parent.getElementParser();
\r
186 if (parser != null && parser instanceof UnrecognizedElementParser) {
\r
188 ((UnrecognizedElementParser)parser).configureChild(graph, parents, parent, element);
\r
189 } catch (DatabaseException e) {
\r
190 throw new SAXException(e);
\r
197 private void handleCharacters(ParserElement element, String string) throws SAXException{
\r
198 XMLElementParser parser = element.getElementParser();
\r
199 if (parser != null) {
\r
201 parser.configure(graph, element, string);
\r
202 } catch (DatabaseException e) {
\r
203 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage()));
\r
204 throw new SAXException(e);
\r
211 public void done() throws SAXException{
\r
213 for (ParserElement e : idReferenceElements) {
\r
214 IDReferenceParser parser = (IDReferenceParser)parsers.get(e.qName);
\r
215 if (!parser.connectReferences(graph, e, idMap)) {
\r
216 String err ="Could not resolve ID references for " + e.getQName() + " " + e.getUri();
\r
217 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
\r
218 if (debug) System.err.println(err);
\r
221 } catch (DatabaseException e) {
\r
222 throw new SAXException(e);
\r
226 public Resource getRoot() {
\r
230 StringBuilder charactersValue;
\r
233 public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
\r
234 ParserElement e = new ParserElement(uri,localName,name,attributes);
\r
236 loadElement(current,e);
\r
239 charactersValue = new StringBuilder();
\r
243 public void endElement(String uri, String localName, String name)
\r
244 throws SAXException {
\r
245 ParserElement e = null;
\r
246 if (!current.isEmpty()) {
\r
250 handleCharacters(e, charactersValue.toString());
\r
251 handleElement(current,e);
\r
253 if (current.isEmpty()) {
\r
254 root = e.getData();
\r
257 charactersValue = new StringBuilder();
\r
261 public void characters(char[] ch, int start, int length)
\r
262 throws SAXException {
\r
263 charactersValue.append(new String(ch,start,length));
\r
264 // if (!current.isEmpty()) {
\r
265 // String s = new String(ch,start,length);
\r
266 // Element e = current.peek();
\r
267 // handleCharacters(e, s);
\r
272 public void parse(File file, ILogger logger) throws Exception {
\r
273 this.logger = logger;
\r
274 SAXParserFactory spf = SAXParserFactory.newInstance();
\r
275 SAXParser saxParser = spf.newSAXParser();
\r
277 XMLReader reader = saxParser.getXMLReader();
\r
278 reader.setContentHandler(this);
\r
279 reader.parse(new InputSource(new BufferedInputStream(new FileInputStream(file))));
\r