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