1 package org.djutils.data.xml;
2
3 import java.io.FileReader;
4 import java.io.FileWriter;
5 import java.io.IOException;
6 import java.io.Reader;
7 import java.io.Writer;
8 import java.util.ArrayList;
9 import java.util.List;
10
11 import javax.xml.stream.XMLInputFactory;
12 import javax.xml.stream.XMLOutputFactory;
13 import javax.xml.stream.XMLStreamConstants;
14 import javax.xml.stream.XMLStreamException;
15 import javax.xml.stream.XMLStreamReader;
16 import javax.xml.stream.XMLStreamWriter;
17
18 import org.djutils.data.DataColumn;
19 import org.djutils.data.DataRecord;
20 import org.djutils.data.DataTable;
21 import org.djutils.data.ListDataTable;
22 import org.djutils.data.SimpleDataColumn;
23 import org.djutils.data.serialization.TextSerializationException;
24 import org.djutils.data.serialization.TextSerializer;
25 import org.djutils.exceptions.Throw;
26 import org.djutils.primitives.Primitive;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public final class XMLData
71 {
72
73
74
75 private XMLData()
76 {
77
78 }
79
80
81
82
83
84
85
86
87
88
89 public static void writeData(final Writer writer, final DataTable dataTable)
90 throws IOException, TextSerializationException, XMLStreamException
91 {
92 XMLStreamWriter xmlw = null;
93 try
94 {
95 XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
96 xmlw = xmlOutputFactory.createXMLStreamWriter(writer);
97
98
99 xmlw.writeStartDocument();
100 xmlw.writeCharacters("\n");
101
102
103 xmlw.writeStartElement("xmldata");
104 xmlw.writeCharacters("\n");
105 xmlw.writeCharacters(" ");
106 xmlw.writeStartElement("table");
107 xmlw.writeAttribute("id", dataTable.getId());
108 xmlw.writeAttribute("description", dataTable.getDescription());
109 xmlw.writeAttribute("class", dataTable.getClass().getName());
110 xmlw.writeCharacters("\n");
111 int index = 0;
112 for (DataColumn<?> column : dataTable.getColumns())
113 {
114 xmlw.writeCharacters(" ");
115 xmlw.writeStartElement("column");
116 xmlw.writeAttribute("nr", String.valueOf(index++));
117 xmlw.writeAttribute("id", column.getId());
118 xmlw.writeAttribute("description", column.getDescription());
119 xmlw.writeAttribute("type", column.getValueType().getName());
120 xmlw.writeEndElement();
121 xmlw.writeCharacters("\n");
122 }
123 xmlw.writeCharacters(" ");
124 xmlw.writeEndElement();
125 xmlw.writeCharacters("\n");
126
127
128 TextSerializer<?>[] serializers = new TextSerializer[dataTable.getNumberOfColumns()];
129 for (int i = 0; i < dataTable.getNumberOfColumns(); i++)
130 {
131 DataColumn<?> column = dataTable.getColumns().get(i);
132 serializers[i] = TextSerializer.resolve(column.getValueType());
133 }
134
135
136 xmlw.writeCharacters(" ");
137 xmlw.writeStartElement("data");
138 xmlw.writeCharacters("\n");
139
140
141 int recordNr = 0;
142 for (DataRecord record : dataTable)
143 {
144 Object[] values = record.getValues();
145 xmlw.writeCharacters(" ");
146 xmlw.writeStartElement("record");
147 xmlw.writeAttribute("index", String.valueOf(recordNr++));
148 xmlw.writeCharacters("\n");
149 for (int i = 0; i < dataTable.getNumberOfColumns(); i++)
150 {
151 xmlw.writeCharacters(" ");
152 xmlw.writeStartElement("value");
153 xmlw.writeAttribute("nr", String.valueOf(i));
154 xmlw.writeAttribute("content", serializers[i].serialize(values[i]));
155 xmlw.writeEndElement();
156 xmlw.writeCharacters("\n");
157 }
158 xmlw.writeCharacters(" ");
159 xmlw.writeEndElement();
160 xmlw.writeCharacters("\n");
161 }
162
163
164 xmlw.writeCharacters(" ");
165 xmlw.writeEndElement();
166 xmlw.writeCharacters("\n");
167 xmlw.writeEndElement();
168 xmlw.writeCharacters("\n");
169 xmlw.writeEndDocument();
170 }
171 finally
172 {
173 if (null != xmlw)
174 {
175 xmlw.close();
176 }
177 }
178 }
179
180
181
182
183
184
185
186
187
188
189 public static void writeData(final String filename, final DataTable dataTable)
190 throws IOException, TextSerializationException, XMLStreamException
191 {
192 FileWriter fw = null;
193 try
194 {
195 fw = new FileWriter(filename);
196 writeData(fw, dataTable);
197 }
198 finally
199 {
200 if (null != fw)
201 {
202 fw.close();
203 }
204 }
205 }
206
207
208
209
210
211
212
213
214
215 public static DataTable readData(final Reader reader) throws IOException, TextSerializationException, XMLStreamException
216 {
217 XMLStreamReader xmlr = null;
218 try
219 {
220
221 XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
222 xmlr = xmlInputFactory.createXMLStreamReader(reader);
223
224
225 waitFor(xmlr, "xmldata");
226
227
228 waitFor(xmlr, "table");
229 String[] tableProperties = getAttributes(xmlr, "id", "description", "class");
230 Throw.when(!tableProperties[2].endsWith("ListDataTable"), IOException.class,
231 "Currently, this method can only recreate a ListDataTable");
232
233
234 List<DataColumn<?>> columns = new ArrayList<>();
235 int index = 0;
236 while (waitFor(xmlr, "column", "table"))
237 {
238 String[] columnProperties = getAttributes(xmlr, "nr", "id", "description", "type");
239 if (Integer.valueOf(columnProperties[0]).intValue() != index)
240 {
241 throw new IOException("column nr not ok");
242 }
243 String type = columnProperties[3];
244 Class<?> valueClass = Primitive.forName(type);
245 if (valueClass == null)
246 {
247 try
248 {
249 valueClass = Class.forName(type);
250 }
251 catch (ClassNotFoundException exception)
252 {
253 throw new IOException("Could not find class " + type, exception);
254 }
255 }
256 @SuppressWarnings({ "rawtypes", "unchecked" })
257 DataColumn<?> column = new SimpleDataColumn(columnProperties[1], columnProperties[2], valueClass);
258 columns.add(column);
259 index++;
260 }
261 ListDataTablestDataTable">ListDataTable dataTable = new ListDataTable(tableProperties[0], tableProperties[1], columns);
262
263
264 TextSerializer<?>[] serializers = new TextSerializer[dataTable.getNumberOfColumns()];
265 for (int i = 0; i < dataTable.getNumberOfColumns(); i++)
266 {
267 DataColumn<?> column = dataTable.getColumns().get(i);
268 serializers[i] = TextSerializer.resolve(column.getValueType());
269 }
270
271
272 waitFor(xmlr, "data");
273 while (waitFor(xmlr, "record", "data"))
274 {
275 String[] data = new String[columns.size()];
276 while (waitFor(xmlr, "value", "record"))
277 {
278 String[] valueProperties = getAttributes(xmlr, "nr", "content");
279 data[Integer.valueOf(valueProperties[0]).intValue()] = valueProperties[1];
280 }
281 Object[] values = new Object[columns.size()];
282 for (int i = 0; i < values.length; i++)
283 {
284 values[i] = serializers[i].deserialize(data[i]);
285 }
286 dataTable.addRecord(values);
287 }
288 return dataTable;
289 }
290 finally
291 {
292 if (null != xmlr)
293 {
294 xmlr.close();
295 }
296 }
297 }
298
299
300
301
302
303
304
305
306
307
308 private static void waitFor(final XMLStreamReader xmlr, final String tag) throws XMLStreamException, IOException
309 {
310 while (xmlr.hasNext())
311 {
312 xmlr.next();
313 if (xmlr.getEventType() == XMLStreamConstants.START_ELEMENT)
314 {
315 if (xmlr.getLocalName().equals(tag))
316 {
317 return;
318 }
319 }
320 }
321 throw new IOException("Unexpected end of stream");
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338 private static boolean waitFor(final XMLStreamReader xmlr, final String tag, final String stopEndTag)
339 throws XMLStreamException, IOException
340 {
341 while (xmlr.hasNext())
342 {
343 xmlr.next();
344 if (xmlr.getEventType() == XMLStreamConstants.START_ELEMENT)
345 {
346 if (xmlr.getLocalName().equals(tag))
347 {
348 return true;
349 }
350 }
351 else if (xmlr.getEventType() == XMLStreamConstants.END_ELEMENT)
352 {
353 if (xmlr.getLocalName().equals(stopEndTag))
354 {
355 return false;
356 }
357 }
358 }
359 throw new IOException("Unexpected end of stream");
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373 private static String[] getAttributes(final XMLStreamReader xmlr, final String... attributes)
374 throws XMLStreamException, IOException
375 {
376 String[] result = new String[attributes.length];
377 int found = 0;
378 for (int i = 0; i < xmlr.getAttributeCount(); i++)
379 {
380 String localName = xmlr.getAttributeLocalName(i);
381 String value = xmlr.getAttributeValue(i);
382 for (int j = 0; j < attributes.length; j++)
383 {
384 if (localName.equals(attributes[j]))
385 {
386 result[j] = value;
387 found++;
388 }
389 }
390 }
391 Throw.when(found != attributes.length, IOException.class, "attribute data does not contain %d fields",
392 attributes.length);
393 return result;
394 }
395
396
397
398
399
400
401
402
403
404 public static DataTable readData(final String filename) throws IOException, TextSerializationException, XMLStreamException
405 {
406 FileReader fr = null;
407 try
408 {
409 fr = new FileReader(filename);
410 return readData(fr);
411 }
412 finally
413 {
414 if (null != fr)
415 {
416 fr.close();
417 }
418 }
419 }
420
421 }