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