-
Notifications
You must be signed in to change notification settings - Fork 0
/
X3DJSONLD.java
387 lines (365 loc) · 15.5 KB
/
X3DJSONLD.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
/**
* Copyright (c) 2022. John Carlson
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of content nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*/
import org.w3c.dom.*;
import org.w3c.dom.ls.*;
import javax.json.*;
import java.util.*;
import java.io.*;
import java.io.FileWriter;
import javax.xml.parsers.*;
public class X3DJSONLD {
private boolean x3dTidy = false;
public String stripQuotes(String value) {
if (value.charAt(0) == '"' && value.charAt(value.length()-1) == '"') {
return value.substring(1, value.length()-1);
} else {
return value;
}
}
public void elementSetAttribute(Element element, String key, List<JsonValue> value) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < value.size(); i++) {
if (i > 0) {
sb.append(" ");
}
sb.append(value.get(i));
}
element.setAttribute(key, sb.toString());
}
public void elementSetAttribute(Element element, String key, String value) {
if (key.equals("SON schema")) {
// JSON Schema
} else if (key.equals("ncoding")) {
// encoding, UTF-8
} else if (value == null) {
element.setAttribute(key, null);
} else {
// System.err.println(key+"= SA "+value);
element.setAttribute(key, stripQuotes(value));
}
}
public Element CreateElement(Document document, String key, String containerField) {
Element child = document.createElement(key);
if (containerField != null &&
((containerField.equals("geometry") && key.equals("IndexedFaceSet")) ||
(containerField.equals("geometry") && key.equals("Text")) ||
(containerField.equals("geometry") && key.equals("IndexedTriangleSet")) ||
(containerField.equals("geometry") && key.equals("Sphere")) ||
(containerField.equals("geometry") && key.equals("Cylinder")) ||
(containerField.equals("geometry") && key.equals("Cone")) ||
(containerField.equals("geometry") && key.equals("LineSet")) ||
(containerField.equals("geometry") && key.equals("IndexedLineSet")) ||
(containerField.equals("geometry") && key.equals("Box")) ||
(containerField.equals("geometry") && key.equals("Extrusion")) ||
(containerField.equals("geometry") && key.equals("GeoElevationGrid")) ||
(containerField.equals("shape") && key.equals("Shape")) ||
(containerField.equals("skin") && key.equals("Shape")) ||
(containerField.endsWith("exture") && key.equals("ImageTexture")) ||
(key.equals("HAnimSegment")) ||
(key.equals("HAnimSite")) ||
(key.equals("HAnimMotion")) ||
(containerField.equals("skinCoord") && key.equals("Coordinate")) || // overwrite coord with skinCoord, if set
(containerField.equals("skin") && key.equals("IndexedFaceSet")) ||
((containerField.equals("skinBindingCoords") || containerField.equals("skinCoord")) && key.equals("Coordinate")) ||
((containerField.equals("normal") || containerField.equals("skinBindingNormals") || containerField.equals("skinNormal")) && key.equals("Normal")) ||
((containerField.equals("skeleton") || containerField.equals("children") || containerField.equals("joints")) && key.equals("HAnimJoint"))
)) {
elementSetAttribute(child, "containerField", containerField);
}
return child;
}
public void CDATACreateFunction(Document document, Element element, JsonArray value) {
// System.err.println("GOT HERE IN CDATA");
StringBuffer sb = new StringBuffer();
for (int i = 0; i < value.size(); i++) {
if (i > 0) {
sb.append("\n");
}
sb.append(value.get(i).toString()
// .replaceAll("
", "")
.replaceAll("^\"", "")
.replaceAll("\\\\t", "\t")
.replaceAll("\"$", "")
.replaceAll("<", "<")
.replaceAll(">", ">")
.replaceAll("&", "&")
.replaceAll(""", "\""));
// .replaceAll("'([^'\r\n]*)\n([^']*)'", "'$1\\r\\n$2'")
}
String str = sb.toString();
CDATASection cdata = document.createCDATASection(str);
element.appendChild(cdata);
}
public void convertProperty(Document document, String key, JsonObject object, Element element, String containerField) {
// System.err.println(key+"= P "+object.get(key));
if (object != null && object.get(key) instanceof JsonObject) {
if (key.equals("@sourceCode")) {
// System.err.println("FOUND SOURCE 1");
CDATACreateFunction(document, element, (JsonArray)object.get(key));
} else if (key.substring(0,1).equals("@")) {
convertJsonValue(document, object.get(key), key, element, containerField);
} else if (key.substring(0,1).equals("-")) {
// System.err.println("converting children at "+key);
convertJsonValue(document, object.get(key), key, element, key.substring(1));
} else if (key.equals("#comment")) {
if (object.get(key) instanceof JsonArray) {
JsonArray array = (JsonArray)object.get(key);
for (int childkey = 0; childkey < array.size(); childkey++) { // for each field
Comment child = document.createComment(CommentStringToXML(array.get(childkey).toString()));
element.appendChild(child);
}
} else {
Comment child = document.createComment(CommentStringToXML(object.get(key).toString()));
element.appendChild(child);
}
} else if (key.equals("#sourceCode")) {
// System.err.println("FOUND SOURCE 2");
CDATACreateFunction(document, element, (JsonArray)object.get(key));
} else if (key.equals("connect") || key.equals("fieldValue") || key.equals("field") || key.equals("meta") || key.equals("component") || key.equals("unit")) {
JsonArray array = (JsonArray)object.get(key);
convertJsonArray(document, array, key, element, containerField);
} else {
convertJsonValue(document, object.get(key), key, element, containerField);
}
}
}
public String CommentStringToXML(String str) {
String y = str;
// System.err.println("X3DJSONLD comment replacing "+ y);
str = y;
String x;
do {
x = str;
str = x.replaceAll("(.*)\\\\\"(.*)\\\\\"(.*)", "$1\"$2\"$3");
} while (!x.equals(str));
do {
x = str;
str = x.replaceAll("(.*)\\\\\"(.*)", "$1\"$2");
} while (!x.equals(str));
do {
x = str;
str = x.replaceAll("\"\"", "\" \"");
} while (!x.equals(str));
if (!y.equals(str)) {
// System.err.println("with "+ str);
} else {
// System.err.println("ok");
}
return str;
}
public String NavigationInfoTypeToXML(String str) {
String y = str;
System.err.println("X3DJSONLD jsonstring replacing "+ y);
str = y.replaceAll("\\\\", "");
if (!y.equals(str)) {
System.err.println("with "+ str);
} else {
System.err.println("ok");
}
return str;
}
public String fixXML(String str, String version) {
String y = str;
// System.err.println("fixXML replacing "+ y);
// str = str.replace("?>", "?>\n<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D "+version+"//EN\" \"https://www.web3d.org/specifications/x3d-"+version+".dtd\">");
// str = str.replaceFirst("xsd:noNamespaceSchemaLocation=\"[^\"]*\"", "");
if (!y.equals(str)) {
// System.err.println("with "+ str);
} else {
// System.err.println("ok");
}
return str;
}
public void convertJsonObject(Document document, JsonObject object, String parentkey, Element element, String containerField) {
Boolean kii;
try {
Integer.parseInt(parentkey);
kii = true;
} catch (Exception e) {
kii = false;
}
Element child;
if (kii || parentkey.startsWith("-")) {
child = element;
} else {
if ((containerField == null || containerField.equals("children")) && parentkey.equals("HAnimJoint") && element.getTagName().equals("HAnimHumanoid")) {
containerField = "joints";
}
if ((containerField == null || containerField.equals("coord")) && parentkey.equals("Coordinate") && element.getTagName().equals("HAnimHumanoid")) {
containerField = "skinCoord";
}
child = CreateElement(document, parentkey, containerField);
}
Iterator<String> keyiter = object.keySet().iterator();
while (keyiter.hasNext()) {
String key = keyiter.next();
JsonValue ok = object.get(key);
// System.err.println(key+"= O "+ok);
if (ok instanceof JsonObject) {
if (key.equals("@type") && parentkey.equals("NavigationInfo") && ok instanceof JsonString) {
elementSetAttribute(child, key.substring(1), NavigationInfoTypeToXML(ok.toString()));
} else if (key.substring(0,1).equals("@")) {
convertProperty(document, key, (JsonObject)ok, child, containerField);
} else if (key.substring(0,1).equals("-")) {
convertJsonObject(document, (JsonObject)ok, key, child, key.substring(1));
} else {
convertJsonObject(document, (JsonObject)ok, key, child, containerField);
}
} else if (ok instanceof JsonArray) {
convertJsonArray(document, (JsonArray)ok, key, child, containerField);
} else if (ok instanceof JsonNumber) {
elementSetAttribute(child, key.substring(1),ok.toString());
} else if (ok instanceof JsonString) {
if (key.equals("#comment")) {
Comment comment = document.createComment(CommentStringToXML(ok.toString()));
child.appendChild(comment);
} else if (key.equals("@type") && parentkey.equals("NavigationInfo")) {
elementSetAttribute(child, key.substring(1), NavigationInfoTypeToXML(ok.toString()));
} else {
// ordinary string attributes
elementSetAttribute(child, key.substring(1), ok.toString());
}
} else if (ok == JsonValue.FALSE || ok == JsonValue.TRUE || ok == JsonValue.NULL) {
elementSetAttribute(child, key.substring(1),ok.toString());
} else if (ok == null) {
} else {
}
}
if (!kii && !parentkey.startsWith("-")) {
element.appendChild(child);
// element.appendChild(document.createTextNode("\n"));
}
}
public void convertJsonArray(Document document, JsonArray array, String parentkey, Element element, String containerField) {
Boolean arrayOfStrings = false;
List<JsonValue> localArray = new ArrayList<JsonValue>();
Integer arraysize = array.size();
if ("meta".equals(parentkey)) {
arraysize = array.size() - (this.x3dTidy ? 2 : 3); // skip meta statements added by X3dToJson.xslt and x3d-tidy
}
for (int key = 0; key < arraysize; key++) {
JsonValue ok = array.get(key);
// System.err.println(key+","+parentkey+"= A "+ok);
if (ok instanceof JsonNumber) {
localArray.add(ok);
} else if (ok instanceof JsonString) {
localArray.add(ok);
arrayOfStrings = true;
} else if (ok == JsonValue.TRUE || ok == JsonValue.FALSE || ok == JsonValue.NULL) {
localArray.add(ok);
} else if (ok instanceof JsonObject) {
Boolean kii;
try {
Integer.parseInt(""+key);
kii = true;
} catch (Exception e) {
kii = false;
}
if (!parentkey.startsWith("-") && kii) {
convertJsonValue(document, ok, parentkey, element, containerField);
} else {
convertJsonValue(document, ok, ""+key, element, parentkey.substring(1));
}
} else if (ok instanceof JsonArray) {
convertJsonValue(document, ok, ""+key, element, containerField);
} else if (ok == null) {
} else {
}
}
if (parentkey.equals("@sourceCode")) {
// System.err.println("FOUND SOURCE 3");
CDATACreateFunction(document, element, array);
} else if (parentkey.substring(0,1).equals("@")) {
elementSetAttribute(element, parentkey.substring(1), localArray);
} else if (parentkey.equals("#sourceCode")) {
// System.err.println("FOUND SOURCE 4");
CDATACreateFunction(document, element, array);
}
}
public Element convertJsonValue(Document document, JsonValue object, String parentkey, Element element, String containerField) {
// System.err.println(parentkey+"= V "+object);
if (object instanceof JsonArray) {
convertJsonArray(document, (JsonArray)object, parentkey, element, containerField);
} else {
convertJsonObject(document, (JsonObject)object, parentkey, element, containerField);
}
return element;
}
public Document loadJsonIntoDocument(JsonObject jsobj, String version, boolean x3dTidy) throws ParserConfigurationException {
this.x3dTidy = x3dTidy;
String unenversion = version.toString().replaceAll("%22", "").replaceAll("\"", "");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
Element element = CreateElement(document, "X3D", null);
elementSetAttribute(element, "xmlns:xsd", "http://www.w3.org/2001/XMLSchema-instance");
// elementSetAttribute(element, "xsi:schemaLocation", "https://www.web3d.org/specifications/x3d-"+unenversion+".xsd");
// ((JsonObject)jsobj.get("X3D")).remove("xsd:noNamespaceSchemaLocation");
convertJsonObject(document, (JsonObject)jsobj.get("X3D"), "-", element, null);
// element.removeAttribute("xsd:noNamespaceSchemaLocation");
// convertProperty(document, "X3D", (JsonObject)(jsobj.get("X3D")), element, null);
document.appendChild(element);
DOMImplementation domImplementation = db.getDOMImplementation();
DocumentType doctype = domImplementation.createDocumentType("X3D", "ISO//Web3D//DTD X3D "+unenversion+"//EN", "https://www.web3d.org/specifications/x3d-"+unenversion+".dtd");
document.insertBefore(doctype, element);
return document;
}
public JsonObject readJsonFile(File jsonFile) throws FileNotFoundException {
InputStream is = new FileInputStream(jsonFile);
JsonReader reader = Json.createReader(is);
JsonObject jsobj = reader.readObject();
return jsobj;
}
public String getX3DVersion(JsonObject jsobj) {
String version = "4.0";
if (jsobj != null) {
version = ((JsonObject)jsobj.get("X3D")).get("@version").toString();
}
return version.replaceAll("\"", "");
}
public static void main(String args[]) {
try {
X3DJSONLD loader = new X3DJSONLD();
JsonObject jsobj = loader.readJsonFile(new File(args[0]));
Document document = loader.loadJsonIntoDocument(jsobj, loader.getX3DVersion(jsobj), args[0].endsWith(".x3dj"));
System.out.println(loader.serializeDOM(loader.getX3DVersion(jsobj), document));
} catch (Exception e) {
e.printStackTrace();
}
}
public String serializeDOM(String x3dVersion, Document document) {
DOMImplementationLS ls = (DOMImplementationLS)document.getImplementation();
LSOutput output = ls.createLSOutput();
LSSerializer ser = ls.createLSSerializer();
ser.getDomConfig().setParameter("format-pretty-print", true);
StringWriter writer = new StringWriter();
output.setCharacterStream(writer);
output.setEncoding("UTF-8");
ser.write(document, output);
String xml = writer.toString();
// xml = fixXML(xml, x3dVersion);
return xml;
}
}