]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.xml.sax.base/src/org/simantics/xml/sax/base/XMLParser.java
3d708f4842f729ea4f58bf5a76041524a3420242
[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                 if (graph == this.graph)
56                         return;
57                 this.graph = graph;
58                 for (XMLParser p : subParsers.values())
59                         p.setGraph(graph);
60         }
61         
62         public void setLogger(ILogger logger) {
63                 if (logger == this.logger)
64                         return;
65                 this.logger = logger;
66                 for (XMLParser p : subParsers.values())
67                         p.setLogger(logger);
68         }
69         
70         public String getSchemaURI() {
71                 return schemaURI;
72         }
73         
74         public void setSchemaURI(String schemaURI) {
75                 this.schemaURI = schemaURI;
76         }
77         
78         public void add(XMLElementParser parser) {
79                 if (parser.getElementId() != null)
80                         parsers.put(parser.getElementId(), parser);
81                 namedParsers.put(parser.getClass(), parser);
82         }
83         
84         public void add(XMLParser parser) {
85                 subParsers.put(parser.getSchemaURI(), parser);
86                 
87         }
88         
89         public XMLParser resolveDependencies() {
90
91                 java.util.Map<String, XMLParser> map = new java.util.HashMap<>();
92                 map.put(this.getSchemaURI(), this);
93                 addDependencies(map);
94                 return this;
95         }
96         
97         public void addDependencies(java.util.Map<String,XMLParser> map) {
98                 
99         }
100         
101         private List<ParserElement> idReferenceElements = new ArrayList<ParserElement>();
102         
103         private void loadElement(Deque<ParserElement> parents, ParserElement element) throws SAXException{
104                 loadElement(parents, element, true);
105         }
106         private void loadElement(Deque<ParserElement> parents, ParserElement element, boolean checkParent) throws SAXException{
107                 XMLElementParser parser = null;
108                 ParserElement parent = null;
109                 if (parents.size() > 0) {
110                         // process a child element
111                         parent = parents.peek();
112                         // check for assigned subparser
113                         if (checkParent && parent.getXMLParser() != null && parent.getXMLParser() != this) {
114                                 //element.setXMLParser(parent.getXMLParser());
115                                 element.setXMLParser(parent.getXMLParser());
116                                 parent.getXMLParser().loadElement(parents, element);
117                                 return;
118                         }
119                         if (parent.getElementParser() instanceof XMLElementNamedChildParser) {
120                                 // use parent's named child parser if it is supported
121                                 Class<? extends XMLElementParser> parserClass = ((XMLElementNamedChildParser)parent.getElementParser()).getParser(parsers,parent,element);
122                                 if (parserClass != null) {
123                                         parser = namedParsers.get(parserClass);
124                                         if (parser == null) {
125                                                 try {
126                                                         parser = parserClass.newInstance();
127                                                         namedParsers.put(parserClass, parser);
128                                                 } catch (IllegalAccessException | InstantiationException e) {
129                                                         String err = "Error processing " + parserClass.getName() + " : element parsers must have accessible default constructor";
130                                                         logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
131                                                         throw new SAXException(err, e);
132                                                 }
133                                         }
134                                 } 
135 //                              if (parser == null && ((XMLElementNamedChildParser)parent.getParser()).useGlobalRules())
136 //                                      parser = parsers.get(element.qName);
137                         } else {
138                                 // otherwise use globally configured element parser
139                                 parser = parsers.get(element.getLocalName());
140                         }
141                 } else {
142                         // use globally configured element parser for a root element
143                         parser = parsers.get(element.getLocalName());
144                 }
145                 
146                 if (parser != null) {
147                         try {
148                                 
149                                 element.setData(parser.create(graph, element));
150                                 if (parser instanceof IDReferenceParser)
151                                         idReferenceElements.add(element);
152                                 element.setElementParser(parser);
153                         } catch (DatabaseException e) {
154                                 throw new SAXException(e);
155                         }
156                 } else {
157                         // check for schema reference attempt to locate subparser for it.
158                         Attribute schemaRef = element.getAttribute(XML_NAMESPACE_REF);
159                         String nsRef[] = element.getQName().split(":");
160                         if (schemaRef != null && subParsers.containsKey(schemaRef.value)) {
161                                 XMLParser subParser = subParsers.get(schemaRef.value);
162                                 subParser.loadElement(parents, element);
163                                 element.setXMLParser(subParser);
164                         } else if (nsRef.length == 2 && element.getNS(nsRef[0]) != null && subParsers.containsKey(element.getNS(nsRef[0]))) {
165                                 XMLParser subParser = subParsers.get(element.getNS(nsRef[0]));
166                                 subParser.loadElement(parents, element, false);
167                                 element.setXMLParser(subParser);
168                         } else {
169                                 if (parent == null && parents.size() > 0)
170                                         parent = parents.peek();
171                                 String err = null;
172                                 if (parent != null)
173                                         err = "Unknown element " + element.getLocalName() + ", parent " + (parent != null ? parent.getLocalName() : "None");
174                                 else {
175                                         err = "Unknown root element " + element.getLocalName() + ", cannot import the file";
176                                         throw new SAXException(err);
177                                 }
178                                 
179                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
180                                 if (debug) System.err.println(err);
181                         }
182                 }
183         }
184         
185         private Map<String, ParserElement> idMap = new HashMap<String, ParserElement>();
186         
187         private void handleElement(Deque<ParserElement> parents, ParserElement element) throws SAXException{
188                 XMLElementParser parser = element.getElementParser();
189                 if (parser != null) {
190                         try {
191                                 parser.configure(graph, parents, element);
192                                 if (parents.size() > 0) {
193                                         ParserElement parent = parents.peek();
194                                         if (parent.getElementParser() != null) {
195                                                 if (!parent.getElementParser().connectChild(graph, parent, element))
196                                                         if (!parser.connectParent(graph, parent, element)) {
197                                                                 String err = "Did not connect element " + element.getLocalName() + ", parent " + (parent != null ? parent.getLocalName() : "None");
198                                                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
199                                                                 if (debug) System.err.println(err);
200                                                         }
201                                         } else {
202                                                 String err = "Did not connect element " + element.getLocalName() + ", parent " + (parent != null ? parent.getLocalName() : "None") + " was not imported";
203                                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
204                                                 if (debug) System.err.println(err);
205                                         }
206                                 }
207                                 String id = parser.getID();
208                                 if (id != null) {
209                                         ParserElement existing = idMap.put(id, element);
210                                         if (existing != null) {
211                                                 // report error + use id priorities to select the kept element.
212                                                 boolean useExt = existing.elementParser.idPriority() > element.elementParser.idPriority();
213                                                 if (useExt)
214                                                         idMap.put(id, existing);
215                                                 String err = "Duplicate XML element id: " + id + " for " + element.getLocalName() + " and " + existing.getLocalName() + ", using " + (useExt ? existing.getLocalName() : element.getLocalName());
216                                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
217                                                 if (debug) System.err.println(err);
218                                         }
219                                 }
220                         } catch (DatabaseException e) {
221                                 throw new SAXException(e);
222                         }
223                 } else {
224                         ParserElement parent = parents.peek();
225                         if (parent != null) { 
226                                 parser = parent.getElementParser();
227                                 if (parser != null && parser instanceof UnrecognizedElementParser) {
228                                         try {
229                                                 ((UnrecognizedElementParser)parser).configureChild(graph, parents, parent, element);
230                                         } catch (DatabaseException e) {
231                                                 throw new SAXException(e);
232                                         }
233                                 }
234                         }
235                 }
236                 try {
237                         element.createLists(graph);
238                 } catch (DatabaseException e) {
239                         throw new SAXException(e);
240                 }
241         }
242         
243         private void handleCharacters(ParserElement element, String string) throws SAXException{
244                 XMLElementParser parser = element.getElementParser();
245                 if (parser != null) {
246                         try {
247                                 parser.configure(graph, element, string);
248                         } catch (DatabaseException e) {
249                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage()));
250                                 throw new SAXException(e);
251                         }
252                 }
253         }
254         
255         
256         
257         public void done() throws SAXException{
258                 try {
259                         for (ParserElement e : idReferenceElements) {
260                                 IDReferenceParser parser = (IDReferenceParser)parsers.get(e.getLocalName());
261                                 if (!parser.connectReferences(graph, e, idMap)) {
262                                         String err ="Could not resolve ID references for " + e.getLocalName() + " " + e.getUri();
263                                         logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
264                                         if (debug) System.err.println(err);
265                                 }
266                         }
267                 } catch (DatabaseException e) {
268                         throw new SAXException(e);
269                 }
270         }
271         
272         public Resource getRoot() {
273                 return root;
274         }
275         
276         StringBuilder charactersValue;
277         
278         @Override
279         public void startElement(String uri, String localName, String name,     Attributes attributes) throws SAXException {
280                 ParserElement e = new ParserElement(current.peek(),uri,localName,name,attributes);
281                 
282                 loadElement(current,e);
283                 current.push(e);
284                 
285                 charactersValue = new StringBuilder();
286         }
287         
288         @Override
289         public void endElement(String uri, String localName, String name)
290                         throws SAXException {
291                 ParserElement e = null;
292                 if (!current.isEmpty()) {
293                         e = current.pop();
294                 }
295                 if (e != null) {
296                         handleCharacters(e, charactersValue.toString());
297                         handleElement(current,e);
298                         if (current.isEmpty()) {
299                                 root = e.getData();
300                         }
301                 }
302                 
303                 
304                 charactersValue = new StringBuilder();
305         }
306         
307         @Override
308         public void characters(char[] ch, int start, int length)
309                         throws SAXException {
310                 charactersValue.append(new String(ch,start,length));
311 //              if (!current.isEmpty()) {
312 //                      String s = new String(ch,start,length);
313 //                      Element e = current.peek();
314 //                      handleCharacters(e, s);
315 //              }
316                 
317         }
318         
319         public void parse(File file, ILogger logger) throws Exception {
320                 setLogger(logger);
321                 SAXParserFactory spf = SAXParserFactory.newInstance();
322                 SAXParser saxParser = spf.newSAXParser();
323                 
324                 XMLReader reader = saxParser.getXMLReader();
325                 reader.setContentHandler(this);
326                 reader.parse(new InputSource(new BufferedInputStream(new FileInputStream(file))));
327                 done();
328         }
329         
330         
331 }