]> gerrit.simantics Code Review - simantics/interop.git/blob - org.simantics.xml.sax.base/src/org/simantics/xml/sax/base/XMLWriter.java
Attribute namespace + multi-schema data export
[simantics/interop.git] / org.simantics.xml.sax.base / src / org / simantics / xml / sax / base / XMLWriter.java
1 package org.simantics.xml.sax.base;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.InvocationTargetException;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.LinkedHashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Map.Entry;
11 import java.util.Set;
12
13 import javax.xml.stream.XMLStreamException;
14 import javax.xml.stream.XMLStreamWriter;
15
16 import org.eclipse.core.runtime.IStatus;
17 import org.eclipse.core.runtime.Status;
18 import org.simantics.db.ReadGraph;
19 import org.simantics.db.Resource;
20 import org.simantics.db.Session;
21 import org.simantics.db.Statement;
22 import org.simantics.db.common.utils.ListUtils;
23 import org.simantics.db.common.utils.NameUtils;
24 import org.simantics.db.exception.DatabaseException;
25 import org.simantics.layer0.Layer0;
26 import org.simantics.message.ILogger;
27 import org.simantics.xml.sax.ontology.XMLResource;
28
29 public class XMLWriter {
30         
31         public static String XML_SCHEMA_URI = "http://www.w3.org/2001/XMLSchema";
32         public static String XML_SCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance";
33         
34         private ReadGraph graph;
35         private Map<Resource, XMLWriter> subWriters = new HashMap<Resource, XMLWriter>();
36         private Map<Class<? extends XMLElementWriter>, XMLElementWriter> namedWriters = new HashMap<Class<? extends XMLElementWriter>, XMLElementWriter>();
37         private Map<Resource,XMLElementWriter> writers = new HashMap<>();
38         private String schemaURI;
39         private String ontologyURI;
40         private Resource ontology;
41         
42         private ILogger logger;
43         
44         protected Map<String,String> nsPrefixes;
45         
46         public ReadGraph getGraph() {
47                 return graph;
48         }
49         
50         public void setGraph(ReadGraph graph) throws DatabaseException {
51                 this.graph = graph;
52                 for (XMLWriter p : subWriters.values())
53                         p.setGraph(graph);
54                 if (ontologyURI != null)
55                         this.ontology = graph.getResource(ontologyURI);
56         }
57         
58         public String getSchemaURI() {
59                 return schemaURI;
60         }
61         
62         public void setSchemaURI(String schemaURI) {
63                 this.schemaURI = schemaURI;
64         }
65         
66         public String getOntologyURI() {
67                 return ontologyURI;
68         }
69         
70         public void setOntologyURI(String ontologyURI) {
71                 this.ontologyURI = ontologyURI;
72         }
73         
74         public Resource getOntology() {
75                 return ontology;
76         }
77         
78         public void add(XMLElementWriter writer) throws DatabaseException {
79                 Resource type = writer.getType(graph);
80                 if (type != null)
81                         writers.put(type, writer);
82                 namedWriters.put(writer.getClass(), writer);
83         }
84         
85         public void add(XMLWriter writer) {
86                 subWriters.put(writer.getOntology(), writer);
87         }
88         
89         public void configureWriter(XMLStreamWriter writer) throws XMLStreamException {
90                 if (nsPrefixes == null)
91                         return;
92                 for (Entry<String, String> nsEntry : nsPrefixes.entrySet()) {
93                         writer.setPrefix(nsEntry.getValue(), nsEntry.getKey());
94                 }
95                         
96         }
97         
98         public void writeNS(XMLStreamWriter writer) throws XMLStreamException {
99                 if (nsPrefixes == null)
100                         return;
101                 for (Entry<String, String> nsEntry : nsPrefixes.entrySet()) {
102                         writer.writeNamespace(nsEntry.getValue(), nsEntry.getKey());
103                 }
104                         
105         }
106         
107         public XMLWriter resolveDependencies(Session session) throws DatabaseException {
108                 java.util.Map<String, XMLWriter> map = new java.util.HashMap<>();
109                 map.put(this.schemaURI, this);
110                 addDependencies(session,map);
111                 nsPrefixes = new HashMap<>();
112                 int i = 0;
113                 for (String ns : map.keySet()) {
114                         if (this.schemaURI.equals(ns))
115                                 continue;
116                         if (!nsPrefixes.containsKey(ns)) {
117                                 nsPrefixes.put(ns, "ns"+i);
118                                 i++;
119                         }
120                 }
121                 return this;
122         }
123         
124         public void addDependencies(Session session,java.util.Map<String,XMLWriter> map) throws DatabaseException {
125                 
126         }
127         
128         public void write(Resource root, XMLStreamWriter writer) throws DatabaseException, XMLStreamException {
129                 WriterElement element = new WriterElement(root);
130                 loadElement(element);
131                 write(element, writer);
132         }
133         
134         
135         protected void write(WriterElement instance, XMLStreamWriter writer) throws DatabaseException, XMLStreamException {
136                 XMLResource XML = XMLResource.getInstance(graph);
137
138                 XMLElementWriter elementWriter = instance.writer;
139                 elementWriter.start(graph, instance, writer);
140                 if (instance.parent == null) {
141                         if(getSchemaURI() != null) {
142                                 writer.writeDefaultNamespace(getSchemaURI());
143                         }
144                         writer.writeNamespace("xsd", XML_SCHEMA_URI);
145                         writer.writeNamespace("xsi", XML_SCHEMA_INSTANCE_URI);
146                         this.configureWriter(writer);
147                         this.writeNS(writer);
148                 }
149                 
150                 elementWriter.attributes(graph, instance, graph.getStatements(instance.instance, XML.hasAttribute), writer);
151                 if (graph.hasValue(instance.instance))
152                         elementWriter.characters(graph, instance, writer);
153                 // get all child elements
154                 Set<Statement> childElements = new HashSet<>();
155                 childElements.addAll(graph.getStatements(instance.instance, XML.hasElement));
156                 childElements.addAll(graph.getStatements(instance.instance, XML.hasComplexType));
157                 // load elements, assign writers
158                 Map<Resource,WriterElement> elementMap = new HashMap<>();
159                 for (Statement s : childElements) {
160                         WriterElement c = new WriterElement(instance,s);
161                         loadElement(c);
162                         elementMap.put(s.getObject(), c);
163                 }
164                 LinkedHashSet<Resource> sorted = new LinkedHashSet<>();
165                 if (graph.hasStatement(instance.instance, XML.hasOriginalElementList)) {
166                         Resource originalList = graph.getSingleObject(instance.instance, XML.hasOriginalElementList);
167                         List<Resource> l = ListUtils.toList(graph, originalList);
168                         sorted.addAll(l);
169                 }
170                 elementWriter.children(graph, instance, sorted);
171                 Set<Resource> processed = new HashSet<>();
172                 for (Resource r : sorted) {
173                         if (processed.contains(r)) // badly generated writer could report elements several times. 
174                                 continue;
175                         WriterElement child = elementMap.get(r);
176                         if (child == null)
177                                 throw new DatabaseException("Trying to export unregonized resource " +NameUtils.getSafeName(graph, r) + " " + r);
178                         write(child, writer);
179                         processed.add(r);
180                 }
181                 //write the rest of the elements (in random order) 
182                 for (Statement stm : childElements) {
183                         if (processed.contains(stm.getObject()))
184                                 continue;
185                         WriterElement child = elementMap.get(stm.getObject());
186                         if (child == null)
187                                 throw new DatabaseException("Trying to export unregonized resource " +NameUtils.getSafeName(graph, stm.getObject()) + " " + stm.getObject());
188                         write(child, writer);
189                 }
190         
191                 elementWriter.end(graph, instance, writer);
192                 
193         }
194         
195         private void loadElement(WriterElement child) throws DatabaseException {
196                 if (child.instance.getResourceId() == 983084L)
197                         System.out.println();
198                 XMLElementWriter childWriter = null;
199                 if (child.parent != null && child.parent.writer instanceof XMLElementNamedChildWriter) {
200                         XMLElementNamedChildWriter namedParentWriter = (XMLElementNamedChildWriter)child.parent.writer;
201                         Class<? extends XMLElementWriter> childWriterClass = namedParentWriter.getWriter(graph, writers, child);
202                         if (childWriterClass != null) {
203                                 childWriter = this.writers.get(childWriterClass);
204                                 if (childWriter == null) {
205                                         try {
206                                                 Constructor<? extends XMLElementWriter> c = null;
207                                                 try {
208                                                         c = childWriterClass.getConstructor(ReadGraph.class);
209                                                         childWriter = c.newInstance(graph);
210                                                 } catch (NoSuchMethodException e) {
211                                                         c = childWriterClass.getConstructor();
212                                                         childWriter = c.newInstance();
213                                                 }
214                                                 namedWriters.put(childWriterClass, childWriter);
215                                         } catch (IllegalAccessException|InstantiationException|NoSuchMethodException|SecurityException|InvocationTargetException e) {
216                                                 String err = "Error processing " + childWriterClass.getName() + " : element writers must have accessible constructor with ReadGraph parameter";
217                                                 logger.log(new Status(IStatus.ERROR, XMLParser.PLUGIN_ID, err, e));
218                                         } 
219                                 }
220                         }
221                 } else {
222                         Resource type = graph.getSingleType(child.instance);
223                         childWriter = writers.get(type);
224                 }
225                 if (childWriter == null) {
226                         // try child ontology/schema
227                         //Resource type = graph.getSingleType(child.instance);
228                         // hack fix for elements containing character data (Current schema conversion does not recognise such cases, leaving Literal type inheritance out).
229                         XMLResource XML = XMLResource.getInstance(graph);
230                         Resource type = graph.getSingleType(child.instance,XML.Element);
231                         Resource ontology = getOntology(type);
232                         if (ontology != null) {
233                                 XMLWriter xmlWriter = subWriters.get(ontology);
234                                 if (xmlWriter == null) {
235                                         // FIXME: We need better way to resolve correct ontology and writer.
236                                         for (XMLWriter w : subWriters.values()) {
237                                                 xmlWriter = w.subWriters.get(ontology);
238                                                 if (xmlWriter != null)
239                                                         break;
240                                         }
241                                 }
242                                 if (xmlWriter != null) {
243                                         childWriter = xmlWriter.writers.get(type);
244                                         // wrap the child writer with namespace writer
245                                         if (childWriter != null) {
246                                                 if (childWriter instanceof XMLElementNamedChildWriter) {
247                                                         childWriter = new XMLNSNamedChildWriter((XMLElementNamedChildWriter)childWriter, xmlWriter.schemaURI);
248                                                 } else {
249                                                         childWriter = new XMLNSElementWriter(childWriter, xmlWriter.schemaURI);
250                                                 }
251                                         }
252                                 }
253                         }
254                         if (childWriter == null)
255                                 throw new DatabaseException("Cannot locate writer for " + NameUtils.getSafeName(graph, child.instance) + ", " + child.instance);
256                 }
257                 child.writer = childWriter;
258                 
259         }
260         
261         private Resource getOntology(Resource type) throws DatabaseException {
262                 Layer0 L0 = Layer0.getInstance(graph);
263                 Resource r = type;
264                 while (true) {
265                         r = graph.getPossibleObject(r, L0.PartOf);
266                         if (r != null && graph.isInstanceOf(r, L0.Ontology))
267                                 break;
268                 }
269                 return r;
270         }
271
272 }