]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.xml.sax.base/src/org/simantics/xml/sax/base/XMLParser.java
87bb477b788902adc54ffd5f7d38fd21861d726b
[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                 try {
203                         element.createLists(graph);
204                 } catch (DatabaseException e) {
205                         throw new SAXException(e);
206                 }
207         }
208         
209         private void handleCharacters(ParserElement element, String string) throws SAXException{
210                 XMLElementParser parser = element.getElementParser();
211                 if (parser != null) {
212                         try {
213                                 parser.configure(graph, element, string);
214                         } catch (DatabaseException e) {
215                                 logger.log(new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage()));
216                                 throw new SAXException(e);
217                         }
218                 }
219         }
220         
221         
222         
223         public void done() throws SAXException{
224                 try {
225                         for (ParserElement e : idReferenceElements) {
226                                 IDReferenceParser parser = (IDReferenceParser)parsers.get(e.qName);
227                                 if (!parser.connectReferences(graph, e, idMap)) {
228                                         String err ="Could not resolve ID references for " + e.getQName() + " " + e.getUri();
229                                         logger.log(new Status(IStatus.ERROR, PLUGIN_ID, err));
230                                         if (debug) System.err.println(err);
231                                 }
232                         }
233                 } catch (DatabaseException e) {
234                         throw new SAXException(e);
235                 }
236         }
237         
238         public Resource getRoot() {
239                 return root;
240         }
241         
242         StringBuilder charactersValue;
243         
244         @Override
245         public void startElement(String uri, String localName, String name,     Attributes attributes) throws SAXException {
246                 ParserElement e = new ParserElement(uri,localName,name,attributes);
247                 
248                 loadElement(current,e);
249                 current.push(e);
250                 
251                 charactersValue = new StringBuilder();
252         }
253         
254         @Override
255         public void endElement(String uri, String localName, String name)
256                         throws SAXException {
257                 ParserElement e = null;
258                 if (!current.isEmpty()) {
259                         e = current.pop();
260                 }
261                 if (e != null) {
262                         handleCharacters(e, charactersValue.toString());
263                         handleElement(current,e);
264                 }
265                 if (current.isEmpty()) {
266                         root = e.getData();
267                 }
268                 
269                 charactersValue = new StringBuilder();
270         }
271         
272         @Override
273         public void characters(char[] ch, int start, int length)
274                         throws SAXException {
275                 charactersValue.append(new String(ch,start,length));
276 //              if (!current.isEmpty()) {
277 //                      String s = new String(ch,start,length);
278 //                      Element e = current.peek();
279 //                      handleCharacters(e, s);
280 //              }
281                 
282         }
283         
284         public void parse(File file, ILogger logger) throws Exception {
285                 this.logger = logger;
286                 SAXParserFactory spf = SAXParserFactory.newInstance();
287                 SAXParser saxParser = spf.newSAXParser();
288                 
289                 XMLReader reader = saxParser.getXMLReader();
290                 reader.setContentHandler(this);
291                 reader.parse(new InputSource(new BufferedInputStream(new FileInputStream(file))));
292                 done();
293         }
294         
295         
296 }