]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.xml.sax.base/src/org/simantics/xml/sax/base/XMLParser.java
9689eda1f8c56b396f50ad383e60d6eccd19bab6
[simantics/interop.git] / org.simantics.xml.sax.base / src / org / simantics / xml / sax / base / XMLParser.java
1 package org.simantics.xml.sax.base;
2
3 import java.io.BufferedInputStream;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.Serializable;
7 import java.util.ArrayDeque;
8 import java.util.ArrayList;
9 import java.util.Deque;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.Map;
13
14 import javax.xml.parsers.SAXParser;
15 import javax.xml.parsers.SAXParserFactory;
16
17 import org.eclipse.core.runtime.IStatus;
18 import org.eclipse.core.runtime.Status;
19 import org.simantics.db.Resource;
20 import org.simantics.db.WriteGraph;
21 import org.simantics.db.exception.DatabaseException;
22 import org.simantics.message.ILogger;
23 import org.xml.sax.Attributes;
24 import org.xml.sax.InputSource;
25 import org.xml.sax.SAXException;
26 import org.xml.sax.XMLReader;
27 import org.xml.sax.helpers.DefaultHandler;
28
29 public class XMLParser extends DefaultHandler implements Serializable {
30
31         public static String PLUGIN_ID = "org.simantics.xml.sax.base";
32         public static String XML_NAMESPACE_REF = "xmlns";
33         
34         private static final long serialVersionUID = 7360740940824360338L;
35         private static final boolean debug = false;
36         
37         private ILogger logger;
38         private WriteGraph graph;
39         private Resource root;
40         private String schemaURI;
41         private Deque<ParserElement> current = new ArrayDeque<ParserElement>();
42         private Map<String, XMLElementParser> parsers = new HashMap<String, XMLElementParser>();
43         private Map<Class<? extends XMLElementParser>, XMLElementParser> namedParsers = new HashMap<Class<? extends XMLElementParser>, XMLElementParser>();
44         private Map<String, XMLParser> subParsers = new HashMap<String, XMLParser>();
45         
46         public XMLParser() {
47         
48         }
49         
50         public WriteGraph getGraph() {
51                 return graph;
52         }
53         
54         public void setGraph(WriteGraph graph) {
55                 this.graph = graph;
56                 for (XMLParser p : subParsers.values())
57                         p.setGraph(graph);
58         }
59         
60         public String getSchemaURI() {
61                 return schemaURI;
62         }
63         
64         public void setSchemaURI(String schemaURI) {
65                 this.schemaURI = schemaURI;
66         }
67         
68         public void add(XMLElementParser parser) {
69                 if (parser.getElementId() != null)
70                         parsers.put(parser.getElementId(), parser);
71                 namedParsers.put(parser.getClass(), parser);
72         }
73         
74         public void add(XMLParser parser) {
75                 subParsers.put(parser.getSchemaURI(), parser);
76         }
77         
78         private List<ParserElement> idReferenceElements = new ArrayList<ParserElement>();
79         private void loadElement(Deque<ParserElement> parents, ParserElement element) throws SAXException{
80                 XMLElementParser parser = null;
81                 ParserElement parent = null;
82                 if (parents.size() > 0) {
83                         parent = parents.peek();
84                         // check for assigned subparser
85                         if (parent.getXMLParser() != null && parent.getXMLParser() != this) {
86                                 element.setXMLParser(parent.getXMLParser());
87                                 parent.getXMLParser().loadElement(parents, element);
88                                 return;
89                         }
90                         if (parent.getElementParser() instanceof XMLElementNamedChildParser) {
91                                 // use parent's named child parser if it is supported
92                                 Class<? extends XMLElementParser> parserClass = ((XMLElementNamedChildParser)parent.getElementParser()).getParser(parsers,parent,element);
93                                 if (parserClass != null) {
94                                         parser = namedParsers.get(parserClass);
95                                         if (parser == null) {
96                                                 try {
97                                                         parser = parserClass.newInstance();
98                                                         namedParsers.put(parserClass, parser);
99                                                 } catch (IllegalAccessException | InstantiationException e) {
100                                                         String err = "Error processing " + parserClass.getName() + " : element parsers must have accessible default constructor";
101                                                         logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
102                                                         throw new SAXException(err, e);
103                                                 }
104                                         }
105                                 } 
106 //                              if (parser == null && ((XMLElementNamedChildParser)parent.getParser()).useGlobalRules())
107 //                                      parser = parsers.get(element.qName);
108                         } else {
109                                 // otherwise use globally configured element parser
110                                 parser = parsers.get(element.qName);
111                         }
112                 } else {
113                         // use globally configured element parser
114                         parser = parsers.get(element.qName);
115                 }
116                 
117                 if (parser != null) {
118                         try {
119                                 
120                                 element.setData(parser.create(graph, element));
121                                 if (parser instanceof IDReferenceParser)
122                                         idReferenceElements.add(element);
123                                 element.setElementParser(parser);
124                         } catch (DatabaseException e) {
125                                 throw new SAXException(e);
126                         }
127                 } else {
128                         // check for schema reference attempt to locate subparser for it.
129                         Attribute schemaRef = element.getAttribute(XML_NAMESPACE_REF);
130                         if (schemaRef != null && subParsers.containsKey(schemaRef.value)) {
131                                 XMLParser subParser = subParsers.get(schemaRef.value);
132                                 subParser.loadElement(parents, element);
133                                 element.setXMLParser(subParser);
134                         } else {
135                                 if (parent == null && parents.size() > 0)
136                                         parent = parents.peek();
137                                 String err = null;
138                                 if (parent != null)
139                                         err = "Unknown element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None");
140                                 else {
141                                         err = "Unknown root element " + element.qName + ", cannot import the file";
142                                         throw new SAXException(err);
143                                 }
144                                 
145                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
146                                 if (debug) System.err.println(err);
147                         }
148                 }
149         }
150         
151         private Map<String, ParserElement> idMap = new HashMap<String, ParserElement>();
152         
153         private void handleElement(Deque<ParserElement> parents, ParserElement element) throws SAXException{
154                 XMLElementParser parser = element.getElementParser();
155                 if (parser != null) {
156                         try {
157                                 parser.configure(graph, parents, element);
158                                 if (parents.size() > 0) {
159                                         ParserElement parent = parents.peek();
160                                         if (parent.getElementParser() != null) {
161                                                 if (!parent.getElementParser().connectChild(graph, parent, element))
162                                                         if (!parser.connectParent(graph, parent, element)) {
163                                                                 String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None");
164                                                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
165                                                                 if (debug) System.err.println(err);
166                                                         }
167                                         } else {
168                                                 String err = "Did not connect element " + element.qName + ", parent " + (parent != null ? parent.getQName() : "None") + " was not imported";
169                                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
170                                                 if (debug) System.err.println(err);
171                                         }
172                                 }
173                                 String id = parser.getID();
174                                 if (id != null) {
175                                         ParserElement existing = idMap.put(id, element);
176                                         if (existing != null) {
177                                                 // report error + use id priorities to select the kept element.
178                                                 boolean useExt = existing.elementParser.idPriority() > element.elementParser.idPriority();
179                                                 if (useExt)
180                                                         idMap.put(id, existing);
181                                                 String err = "Duplicate XML element id: " + id + " for " + element.getQName() + " and " + existing.getQName() + ", using " + (useExt ? existing.getQName() : element.getQName());
182                                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
183                                                 if (debug) System.err.println(err);
184                                         }
185                                 }
186                         } catch (DatabaseException e) {
187                                 throw new SAXException(e);
188                         }
189                 } else {
190                         ParserElement parent = parents.peek();
191                         if (parent != null) { 
192                                 parser = parent.getElementParser();
193                                 if (parser != null && parser instanceof UnrecognizedElementParser) {
194                                         try {
195                                                 ((UnrecognizedElementParser)parser).configureChild(graph, parents, parent, element);
196                                         } catch (DatabaseException e) {
197                                                 throw new SAXException(e);
198                                         }
199                                 }
200                         }
201                 }
202         }
203         
204         private void handleCharacters(ParserElement element, String string) throws SAXException{
205                 XMLElementParser parser = element.getElementParser();
206                 if (parser != null) {
207                         try {
208                                 parser.configure(graph, element, string);
209                         } catch (DatabaseException e) {
210                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage()));
211                                 throw new SAXException(e);
212                         }
213                 }
214         }
215         
216         
217         
218         public void done() throws SAXException{
219                 try {
220                         for (ParserElement e : idReferenceElements) {
221                                 IDReferenceParser parser = (IDReferenceParser)parsers.get(e.qName);
222                                 if (!parser.connectReferences(graph, e, idMap)) {
223                                         String err ="Could not resolve ID references for " + e.getQName() + " " + e.getUri();
224                                         logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
225                                         if (debug) System.err.println(err);
226                                 }
227                         }
228                 } catch (DatabaseException e) {
229                         throw new SAXException(e);
230                 }
231         }
232         
233         public Resource getRoot() {
234                 return root;
235         }
236         
237         StringBuilder charactersValue;
238         
239         @Override
240         public void startElement(String uri, String localName, String name,     Attributes attributes) throws SAXException {
241                 ParserElement e = new ParserElement(uri,localName,name,attributes);
242                 
243                 loadElement(current,e);
244                 current.push(e);
245                 
246                 charactersValue = new StringBuilder();
247         }
248         
249         @Override
250         public void endElement(String uri, String localName, String name)
251                         throws SAXException {
252                 ParserElement e = null;
253                 if (!current.isEmpty()) {
254                         e = current.pop();
255                 }
256                 if (e != null) {
257                         handleCharacters(e, charactersValue.toString());
258                         handleElement(current,e);
259                 }
260                 if (current.isEmpty()) {
261                         root = e.getData();
262                 }
263                 
264                 charactersValue = new StringBuilder();
265         }
266         
267         @Override
268         public void characters(char[] ch, int start, int length)
269                         throws SAXException {
270                 charactersValue.append(new String(ch,start,length));
271 //              if (!current.isEmpty()) {
272 //                      String s = new String(ch,start,length);
273 //                      Element e = current.peek();
274 //                      handleCharacters(e, s);
275 //              }
276                 
277         }
278         
279         public void parse(File file, ILogger logger) throws Exception {
280                 this.logger = logger;
281                 SAXParserFactory spf = SAXParserFactory.newInstance();
282                 SAXParser saxParser = spf.newSAXParser();
283                 
284                 XMLReader reader = saxParser.getXMLReader();
285                 reader.setContentHandler(this);
286                 reader.parse(new InputSource(new BufferedInputStream(new FileInputStream(file))));
287                 done();
288         }
289         
290         
291 }