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