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