Mercurial > hg > monetdb-java
comparison src/main/java/nl/cwi/monetdb/util/XMLExporter.java @ 0:a5a898f6886c
Copy of MonetDB java directory changeset e6e32756ad31.
author | Sjoerd Mullender <sjoerd@acm.org> |
---|---|
date | Wed, 21 Sep 2016 09:34:48 +0200 (2016-09-21) |
parents | |
children | 57978db4ee57 17fbaf2635bb |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a5a898f6886c |
---|---|
1 /* | |
2 * This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
5 * | |
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V. | |
7 */ | |
8 | |
9 package nl.cwi.monetdb.util; | |
10 | |
11 import java.io.*; | |
12 import java.sql.*; | |
13 import java.util.*; | |
14 import java.text.*; | |
15 | |
16 public class XMLExporter extends Exporter { | |
17 private boolean useNil; | |
18 | |
19 public final static int TYPE_NIL = 1; | |
20 public final static int VALUE_OMIT = 0; | |
21 public final static int VALUE_XSI = 1; | |
22 | |
23 public XMLExporter(PrintWriter out) { | |
24 super(out); | |
25 } | |
26 | |
27 public void dumpSchema( | |
28 DatabaseMetaData dbmd, | |
29 String type, | |
30 String catalog, | |
31 String schema, | |
32 String name) | |
33 throws SQLException | |
34 { | |
35 if (type.indexOf("VIEW") != -1) { | |
36 String[] types = new String[1]; | |
37 types[0] = type; | |
38 ResultSet tbl = dbmd.getTables(catalog, schema, name, types); | |
39 if (!tbl.next()) throw new SQLException("Whoops no data for " + name); | |
40 | |
41 // This will probably only work for MonetDB | |
42 out.print("<!-- unable to represent: CREATE " + type + " " + | |
43 (!useSchema ? dq(schema) + "." : "") + dq(name)); | |
44 out.print(" AS "); | |
45 out.print(tbl.getString("REMARKS").trim()); | |
46 out.print(" -->"); | |
47 return; | |
48 } | |
49 | |
50 out.println("<xsd:schema>"); | |
51 | |
52 ResultSet cols = dbmd.getColumns(catalog, schema, name, null); | |
53 String ident; | |
54 Set<String> types = new HashSet<String>(); | |
55 // walk through the ResultSet and create the types | |
56 // for a bit of a clue on the types, see this url: | |
57 // http://books.xmlschemata.org/relaxng/relax-CHP-19.html | |
58 while (cols.next()) { | |
59 switch (cols.getInt("DATA_TYPE")) { | |
60 case java.sql.Types.CHAR: | |
61 ident = "CHAR_" + cols.getString("COLUMN_SIZE"); | |
62 if (types.contains(ident)) break; | |
63 types.add(ident); | |
64 | |
65 out.print(" <xsd:simpleType name="); | |
66 out.print(dq(ident)); | |
67 out.println(">"); | |
68 out.println(" <xsd:restriction base=\"xsd:string\">"); | |
69 out.print(" <xsd:length value="); | |
70 out.print(dq(cols.getString("COLUMN_SIZE"))); | |
71 out.println(" />"); | |
72 out.println(" </xsd:restriction>"); | |
73 out.println(" </xsd:simpleType>"); | |
74 break; | |
75 case java.sql.Types.VARCHAR: | |
76 case java.sql.Types.LONGVARCHAR: | |
77 ident = "VARCHAR_" + cols.getString("COLUMN_SIZE"); | |
78 if (types.contains(ident)) break; | |
79 types.add(ident); | |
80 | |
81 out.print(" <xsd:simpleType name="); | |
82 out.print(dq(ident)); | |
83 out.println(">"); | |
84 out.println(" <xsd:restriction base=\"xsd:string\">"); | |
85 out.print(" <xsd:maxLength value="); | |
86 out.print(dq(cols.getString("COLUMN_SIZE"))); | |
87 out.println(" />"); | |
88 out.println(" </xsd:restriction>"); | |
89 out.println(" </xsd:simpleType>"); | |
90 break; | |
91 case java.sql.Types.CLOB: | |
92 ident = "CLOB"; | |
93 if (types.contains(ident)) break; | |
94 types.add(ident); | |
95 | |
96 out.print(" <xsd:simpleType name="); | |
97 out.print(dq(ident)); | |
98 out.println(">"); | |
99 out.println(" <xsd:restriction base=\"xsd:string\" />"); | |
100 out.println(" </xsd:simpleType>"); | |
101 break; | |
102 case java.sql.Types.DECIMAL: | |
103 case java.sql.Types.NUMERIC: | |
104 ident = "DECIMAL_" + cols.getString("COLUMN_SIZE") + | |
105 "_" + cols.getString("DECIMAL_DIGITS"); | |
106 if (types.contains(ident)) break; | |
107 types.add(ident); | |
108 | |
109 out.print(" <xsd:simpleType name="); | |
110 out.print(dq(ident)); | |
111 out.println(">"); | |
112 out.println(" <xsd:restriction base=\"xsd:decimal\">"); | |
113 out.print(" <xsd:totalDigits value="); | |
114 out.print(dq(cols.getString("COLUMN_SIZE"))); | |
115 out.println(" />"); | |
116 out.print(" <xsd:fractionDigits value="); | |
117 out.print(dq(cols.getString("DECIMAL_DIGITS"))); | |
118 out.println(" />"); | |
119 out.println(" </xsd:restriction>"); | |
120 out.println(" </xsd:simpleType>"); | |
121 break; | |
122 case java.sql.Types.TINYINT: | |
123 ident = "TINYINT"; | |
124 if (types.contains(ident)) break; | |
125 types.add(ident); | |
126 | |
127 out.print(" <xsd:simpleType name="); | |
128 out.print(dq(ident)); | |
129 out.println(">"); | |
130 out.println(" <xsd:restriction base=\"xsd:byte\" />"); | |
131 out.println(" </xsd:simpleType>"); | |
132 break; | |
133 case java.sql.Types.SMALLINT: | |
134 ident = "SMALLINT"; | |
135 if (types.contains(ident)) break; | |
136 types.add(ident); | |
137 | |
138 out.print(" <xsd:simpleType name="); | |
139 out.print(dq(ident)); | |
140 out.println(">"); | |
141 out.println(" <xsd:restriction base=\"xsd:short\" />"); | |
142 out.println(" </xsd:simpleType>"); | |
143 break; | |
144 case java.sql.Types.INTEGER: | |
145 ident = "INTEGER"; | |
146 if (types.contains(ident)) break; | |
147 types.add(ident); | |
148 | |
149 out.print(" <xsd:simpleType name="); | |
150 out.print(dq(ident)); | |
151 out.println(">"); | |
152 out.println(" <xsd:restriction base=\"xsd:integer\" />"); | |
153 out.println(" </xsd:simpleType>"); | |
154 break; | |
155 case java.sql.Types.BIGINT: | |
156 ident = "BIGINT"; | |
157 if (types.contains(ident)) break; | |
158 types.add(ident); | |
159 | |
160 out.print(" <xsd:simpleType name="); | |
161 out.print(dq(ident)); | |
162 out.println(">"); | |
163 out.println(" <xsd:restriction base=\"xsd:long\" />"); | |
164 out.println(" </xsd:simpleType>"); | |
165 break; | |
166 case java.sql.Types.BIT: | |
167 case java.sql.Types.BOOLEAN: | |
168 ident = "BOOLEAN"; | |
169 if (types.contains(ident)) break; | |
170 types.add(ident); | |
171 | |
172 out.print(" <xsd:simpleType name="); | |
173 out.print(dq(ident)); | |
174 out.println(">"); | |
175 out.println(" <xsd:restriction base=\"xsd:boolean\" />"); | |
176 out.println(" </xsd:simpleType>"); | |
177 break; | |
178 case java.sql.Types.DATE: | |
179 ident = "DATE"; | |
180 if (types.contains(ident)) break; | |
181 types.add(ident); | |
182 | |
183 out.print(" <xsd:simpleType name="); | |
184 out.print(dq(ident)); | |
185 out.println(">"); | |
186 out.println(" <xsd:restriction base=\"xsd:date\" />"); | |
187 out.println(" </xsd:simpleType>"); | |
188 break; | |
189 case java.sql.Types.TIME: | |
190 if ("timetz".equals(cols.getString("TYPE_NAME"))) { | |
191 ident = "TIME_WTZ"; | |
192 } else { | |
193 ident = "TIME"; | |
194 } | |
195 if (types.contains(ident)) break; | |
196 types.add(ident); | |
197 | |
198 out.print(" <xsd:simpleType name="); | |
199 out.print(dq(ident)); | |
200 out.println(">"); | |
201 out.println(" <xsd:restriction base=\"xsd:time\" />"); | |
202 out.println(" </xsd:simpleType>"); | |
203 break; | |
204 case java.sql.Types.TIMESTAMP: | |
205 if ("timestamptz".equals(cols.getString("TYPE_NAME"))) { | |
206 ident = "TIMESTAMP_WTZ"; | |
207 } else { | |
208 ident = "TIMESTAMP"; | |
209 } | |
210 if (types.contains(ident)) break; | |
211 types.add(ident); | |
212 | |
213 out.print(" <xsd:simpleType name="); | |
214 out.print(dq(ident)); | |
215 out.println(">"); | |
216 out.println(" <xsd:restriction base=\"xsd:dateTime\" />"); | |
217 out.println(" </xsd:simpleType>"); | |
218 break; | |
219 } | |
220 } | |
221 | |
222 // rewind the ResultSet | |
223 cols.beforeFirst(); | |
224 | |
225 // create the RowType | |
226 out.print(" <xsd:complexType name="); | |
227 out.print(dq("RowType." + catalog.replaceAll("\\.", "_x002e_") + | |
228 "." + schema.replaceAll("\\.", "_x002e_") + | |
229 "." + name.replaceAll("\\.", "_x002e_"))); | |
230 out.println(">"); | |
231 out.println(" <xsd:sequence>"); | |
232 while (cols.next()) { | |
233 out.print(" <xsd:element name="); | |
234 out.print(dq(cols.getString("COLUMN_NAME"))); | |
235 out.print(" type="); | |
236 switch (cols.getInt("DATA_TYPE")) { | |
237 case java.sql.Types.CHAR: | |
238 ident = "CHAR_" + cols.getString("COLUMN_SIZE"); | |
239 break; | |
240 case java.sql.Types.VARCHAR: | |
241 case java.sql.Types.LONGVARCHAR: | |
242 ident = "VARCHAR_" + cols.getString("COLUMN_SIZE"); | |
243 break; | |
244 case java.sql.Types.CLOB: | |
245 ident = "CLOB"; | |
246 break; | |
247 case java.sql.Types.DECIMAL: | |
248 case java.sql.Types.NUMERIC: | |
249 ident = "DECIMAL_" + cols.getString("COLUMN_SIZE") + | |
250 "_" + cols.getString("DECIMAL_DIGITS"); | |
251 break; | |
252 case java.sql.Types.TINYINT: | |
253 ident = "TINYINT"; | |
254 break; | |
255 case java.sql.Types.SMALLINT: | |
256 ident = "SMALLINT"; | |
257 break; | |
258 case java.sql.Types.INTEGER: | |
259 ident = "INTEGER"; | |
260 break; | |
261 case java.sql.Types.BIGINT: | |
262 ident = "BIGINT"; | |
263 break; | |
264 case java.sql.Types.BIT: | |
265 case java.sql.Types.BOOLEAN: | |
266 ident = "BOOLEAN"; | |
267 break; | |
268 case java.sql.Types.DATE: | |
269 ident = "DATE"; | |
270 break; | |
271 case java.sql.Types.TIME: | |
272 if ("timetz".equals(cols.getString("TYPE_NAME"))) { | |
273 ident = "TIME_WTZ"; | |
274 } else { | |
275 ident = "TIME"; | |
276 } | |
277 break; | |
278 case java.sql.Types.TIMESTAMP: | |
279 if ("timestamptz".equals(cols.getString("TYPE_NAME"))) { | |
280 ident = "TIMESTAMP_WTZ"; | |
281 } else { | |
282 ident = "TIMESTAMP"; | |
283 } | |
284 break; | |
285 default: | |
286 ident = "(unknown)"; | |
287 break; | |
288 } | |
289 out.print(dq(ident)); | |
290 out.println(" />"); | |
291 } | |
292 out.println(" </xsd:sequence>"); | |
293 out.println(" </xsd:complexType>"); | |
294 | |
295 out.print(" <xsd:complexType name="); | |
296 out.print(dq("TableType." + catalog.replaceAll("\\.", "_x002e_") + | |
297 "." + schema.replaceAll("\\.", "_x002e_") + | |
298 "." + name.replaceAll("\\.", "_x002e_"))); | |
299 out.println(">"); | |
300 out.println(" <xsd:sequence>"); | |
301 out.print(" <xsd:element name=\"row\" type="); | |
302 out.print(dq("RowType." + catalog.replaceAll("\\.", "_x002e_") + | |
303 "." + schema.replaceAll("\\.", "_x002e_") + | |
304 "." + name.replaceAll("\\.", "_x002e_"))); | |
305 out.println(" minOccurs=\"0\" maxOccurs=\"unbounded\" />"); | |
306 out.println(" </xsd:sequence>"); | |
307 out.println(" </xsd:complexType>"); | |
308 | |
309 out.println("</xsd:schema>"); | |
310 } | |
311 | |
312 private final static SimpleDateFormat xsd_ts = | |
313 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); | |
314 private final static SimpleDateFormat xsd_tstz = | |
315 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); | |
316 | |
317 /** | |
318 * Generates an XML representation of the given ResultSet. | |
319 * | |
320 * @param rs the ResultSet | |
321 */ | |
322 public void dumpResultSet(ResultSet rs) throws SQLException { | |
323 // write simple XML serialisation | |
324 ResultSetMetaData rsmd = rs.getMetaData(); | |
325 if (!useSchema) out.println("<" + rsmd.getSchemaName(1) + ">"); | |
326 out.println("<" + rsmd.getTableName(1) + ">"); | |
327 String data; | |
328 while (rs.next()) { | |
329 out.println(" <row>"); | |
330 for (int i = 1; i <= rsmd.getColumnCount(); i++) { | |
331 switch (rsmd.getColumnType(i)) { | |
332 case java.sql.Types.TIMESTAMP: | |
333 Timestamp ts = rs.getTimestamp(i); | |
334 if ("timestamptz".equals(rsmd.getColumnTypeName(i))) { | |
335 data = xsd_tstz.format(ts).toString(); | |
336 } else { | |
337 data = xsd_ts.format(ts).toString(); | |
338 } | |
339 break; | |
340 default: | |
341 data = rs.getString(i); | |
342 break; | |
343 } | |
344 if (data == null) { | |
345 if (useNil) { | |
346 // "nil" method: write <tag xsi:nil="true" /> | |
347 out.print(" "); | |
348 out.print("<" + rsmd.getColumnLabel(i)); | |
349 out.println(" xsi:nil=\"true\" />"); | |
350 } else { | |
351 // This is the "absent" method (of completely | |
352 // hiding the tag if null | |
353 } | |
354 } else { | |
355 out.print(" "); | |
356 out.print("<" + rsmd.getColumnLabel(i)); | |
357 if (data.length() == 0) { | |
358 out.println(" />"); | |
359 } else { | |
360 out.print(">" + data.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">")); | |
361 out.println("</" + rsmd.getColumnLabel(i) + ">"); | |
362 } | |
363 } | |
364 } | |
365 out.println(" </row>"); | |
366 } | |
367 out.println("</" + rsmd.getTableName(1) + ">"); | |
368 if (!useSchema) out.println("</" + rsmd.getSchemaName(1) + ">"); | |
369 } | |
370 | |
371 public void setProperty(int type, int value) throws Exception { | |
372 switch (type) { | |
373 case TYPE_NIL: | |
374 switch (value) { | |
375 case VALUE_OMIT: | |
376 useNil = false; | |
377 break; | |
378 case VALUE_XSI: | |
379 useNil = true; | |
380 break; | |
381 default: | |
382 throw new Exception("Illegal value " + value + " for TYPE_NIL"); | |
383 } | |
384 break; | |
385 default: | |
386 throw new Exception("Illegal type " + type); | |
387 } | |
388 } | |
389 | |
390 public int getProperty(int type) throws Exception { | |
391 switch (type) { | |
392 case TYPE_NIL: | |
393 return useNil ? VALUE_XSI : VALUE_OMIT; | |
394 default: | |
395 throw new Exception("Illegal type " + type); | |
396 } | |
397 } | |
398 } |