source: main/trunk/model-sites-dev/cambridge-museum/collect/waikato-independent/pre-import/EditableDatabaseTable/src/org/json/JSONML.java@ 34493

Last change on this file since 34493 was 34493, checked in by davidb, 4 years ago

Base project for providing jquery/jquery-ui controlled interface to editing a database table

File size: 14.6 KB
Line 
1package org.json;
2
3/*
4Copyright (c) 2008 JSON.org
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16The Software shall be used for Good, not Evil.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25*/
26
27import java.util.Iterator;
28
29
30/**
31 * This provides static methods to convert an XML text into a JSONArray or
32 * JSONObject, and to covert a JSONArray or JSONObject into an XML text using
33 * the JsonML transform.
34 * @author JSON.org
35 * @version 2010-12-23
36 */
37public class JSONML {
38
39 /**
40 * Parse XML values and store them in a JSONArray.
41 * @param x The XMLTokener containing the source string.
42 * @param arrayForm true if array form, false if object form.
43 * @param ja The JSONArray that is containing the current tag or null
44 * if we are at the outermost level.
45 * @return A JSONArray if the value is the outermost tag, otherwise null.
46 * @throws JSONException
47 */
48 private static Object parse(XMLTokener x, boolean arrayForm,
49 JSONArray ja) throws JSONException {
50 String attribute;
51 char c;
52 String closeTag = null;
53 int i;
54 JSONArray newja = null;
55 JSONObject newjo = null;
56 Object token;
57 String tagName = null;
58
59// Test for and skip past these forms:
60// <!-- ... -->
61// <![ ... ]]>
62// <! ... >
63// <? ... ?>
64
65 while (true) {
66 token = x.nextContent();
67 if (token == XML.LT) {
68 token = x.nextToken();
69 if (token instanceof Character) {
70 if (token == XML.SLASH) {
71
72// Close tag </
73
74 token = x.nextToken();
75 if (!(token instanceof String)) {
76 throw new JSONException(
77 "Expected a closing name instead of '" +
78 token + "'.");
79 }
80 if (x.nextToken() != XML.GT) {
81 throw x.syntaxError("Misshaped close tag");
82 }
83 return token;
84 } else if (token == XML.BANG) {
85
86// <!
87
88 c = x.next();
89 if (c == '-') {
90 if (x.next() == '-') {
91 x.skipPast("-->");
92 }
93 x.back();
94 } else if (c == '[') {
95 token = x.nextToken();
96 if (token.equals("CDATA") && x.next() == '[') {
97 if (ja != null) {
98 ja.put(x.nextCDATA());
99 }
100 } else {
101 throw x.syntaxError("Expected 'CDATA['");
102 }
103 } else {
104 i = 1;
105 do {
106 token = x.nextMeta();
107 if (token == null) {
108 throw x.syntaxError("Missing '>' after '<!'.");
109 } else if (token == XML.LT) {
110 i += 1;
111 } else if (token == XML.GT) {
112 i -= 1;
113 }
114 } while (i > 0);
115 }
116 } else if (token == XML.QUEST) {
117
118// <?
119
120 x.skipPast("?>");
121 } else {
122 throw x.syntaxError("Misshaped tag");
123 }
124
125// Open tag <
126
127 } else {
128 if (!(token instanceof String)) {
129 throw x.syntaxError("Bad tagName '" + token + "'.");
130 }
131 tagName = (String)token;
132 newja = new JSONArray();
133 newjo = new JSONObject();
134 if (arrayForm) {
135 newja.put(tagName);
136 if (ja != null) {
137 ja.put(newja);
138 }
139 } else {
140 newjo.put("tagName", tagName);
141 if (ja != null) {
142 ja.put(newjo);
143 }
144 }
145 token = null;
146 for (;;) {
147 if (token == null) {
148 token = x.nextToken();
149 }
150 if (token == null) {
151 throw x.syntaxError("Misshaped tag");
152 }
153 if (!(token instanceof String)) {
154 break;
155 }
156
157// attribute = value
158
159 attribute = (String)token;
160 if (!arrayForm && (attribute == "tagName" || attribute == "childNode")) {
161 throw x.syntaxError("Reserved attribute.");
162 }
163 token = x.nextToken();
164 if (token == XML.EQ) {
165 token = x.nextToken();
166 if (!(token instanceof String)) {
167 throw x.syntaxError("Missing value");
168 }
169 newjo.accumulate(attribute, XML.stringToValue((String)token));
170 token = null;
171 } else {
172 newjo.accumulate(attribute, "");
173 }
174 }
175 if (arrayForm && newjo.length() > 0) {
176 newja.put(newjo);
177 }
178
179// Empty tag <.../>
180
181 if (token == XML.SLASH) {
182 if (x.nextToken() != XML.GT) {
183 throw x.syntaxError("Misshaped tag");
184 }
185 if (ja == null) {
186 if (arrayForm) {
187 return newja;
188 } else {
189 return newjo;
190 }
191 }
192
193// Content, between <...> and </...>
194
195 } else {
196 if (token != XML.GT) {
197 throw x.syntaxError("Misshaped tag");
198 }
199 closeTag = (String)parse(x, arrayForm, newja);
200 if (closeTag != null) {
201 if (!closeTag.equals(tagName)) {
202 throw x.syntaxError("Mismatched '" + tagName +
203 "' and '" + closeTag + "'");
204 }
205 tagName = null;
206 if (!arrayForm && newja.length() > 0) {
207 newjo.put("childNodes", newja);
208 }
209 if (ja == null) {
210 if (arrayForm) {
211 return newja;
212 } else {
213 return newjo;
214 }
215 }
216 }
217 }
218 }
219 } else {
220 if (ja != null) {
221 ja.put(token instanceof String ?
222 XML.stringToValue((String)token) : token);
223 }
224 }
225 }
226 }
227
228
229 /**
230 * Convert a well-formed (but not necessarily valid) XML string into a
231 * JSONArray using the JsonML transform. Each XML tag is represented as
232 * a JSONArray in which the first element is the tag name. If the tag has
233 * attributes, then the second element will be JSONObject containing the
234 * name/value pairs. If the tag contains children, then strings and
235 * JSONArrays will represent the child tags.
236 * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
237 * @param string The source string.
238 * @return A JSONArray containing the structured data from the XML string.
239 * @throws JSONException
240 */
241 public static JSONArray toJSONArray(String string) throws JSONException {
242 return toJSONArray(new XMLTokener(string));
243 }
244
245
246 /**
247 * Convert a well-formed (but not necessarily valid) XML string into a
248 * JSONArray using the JsonML transform. Each XML tag is represented as
249 * a JSONArray in which the first element is the tag name. If the tag has
250 * attributes, then the second element will be JSONObject containing the
251 * name/value pairs. If the tag contains children, then strings and
252 * JSONArrays will represent the child content and tags.
253 * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
254 * @param x An XMLTokener.
255 * @return A JSONArray containing the structured data from the XML string.
256 * @throws JSONException
257 */
258 public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
259 return (JSONArray)parse(x, true, null);
260 }
261
262
263 /**
264 * Convert a well-formed (but not necessarily valid) XML string into a
265 * JSONObject using the JsonML transform. Each XML tag is represented as
266 * a JSONObject with a "tagName" property. If the tag has attributes, then
267 * the attributes will be in the JSONObject as properties. If the tag
268 * contains children, the object will have a "childNodes" property which
269 * will be an array of strings and JsonML JSONObjects.
270
271 * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
272 * @param x An XMLTokener of the XML source text.
273 * @return A JSONObject containing the structured data from the XML string.
274 * @throws JSONException
275 */
276 public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
277 return (JSONObject)parse(x, false, null);
278 }
279
280
281 /**
282 * Convert a well-formed (but not necessarily valid) XML string into a
283 * JSONObject using the JsonML transform. Each XML tag is represented as
284 * a JSONObject with a "tagName" property. If the tag has attributes, then
285 * the attributes will be in the JSONObject as properties. If the tag
286 * contains children, the object will have a "childNodes" property which
287 * will be an array of strings and JsonML JSONObjects.
288
289 * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
290 * @param string The XML source text.
291 * @return A JSONObject containing the structured data from the XML string.
292 * @throws JSONException
293 */
294 public static JSONObject toJSONObject(String string) throws JSONException {
295 return toJSONObject(new XMLTokener(string));
296 }
297
298
299 /**
300 * Reverse the JSONML transformation, making an XML text from a JSONArray.
301 * @param ja A JSONArray.
302 * @return An XML string.
303 * @throws JSONException
304 */
305 public static String toString(JSONArray ja) throws JSONException {
306 int i;
307 JSONObject jo;
308 String key;
309 Iterator keys;
310 int length;
311 Object object;
312 StringBuffer sb = new StringBuffer();
313 String tagName;
314 String value;
315
316// Emit <tagName
317
318 tagName = ja.getString(0);
319 XML.noSpace(tagName);
320 tagName = XML.escape(tagName);
321 sb.append('<');
322 sb.append(tagName);
323
324 object = ja.opt(1);
325 if (object instanceof JSONObject) {
326 i = 2;
327 jo = (JSONObject)object;
328
329// Emit the attributes
330
331 keys = jo.keys();
332 while (keys.hasNext()) {
333 key = keys.next().toString();
334 XML.noSpace(key);
335 value = jo.optString(key);
336 if (value != null) {
337 sb.append(' ');
338 sb.append(XML.escape(key));
339 sb.append('=');
340 sb.append('"');
341 sb.append(XML.escape(value));
342 sb.append('"');
343 }
344 }
345 } else {
346 i = 1;
347 }
348
349//Emit content in body
350
351 length = ja.length();
352 if (i >= length) {
353 sb.append('/');
354 sb.append('>');
355 } else {
356 sb.append('>');
357 do {
358 object = ja.get(i);
359 i += 1;
360 if (object != null) {
361 if (object instanceof String) {
362 sb.append(XML.escape(object.toString()));
363 } else if (object instanceof JSONObject) {
364 sb.append(toString((JSONObject)object));
365 } else if (object instanceof JSONArray) {
366 sb.append(toString((JSONArray)object));
367 }
368 }
369 } while (i < length);
370 sb.append('<');
371 sb.append('/');
372 sb.append(tagName);
373 sb.append('>');
374 }
375 return sb.toString();
376 }
377
378 /**
379 * Reverse the JSONML transformation, making an XML text from a JSONObject.
380 * The JSONObject must contain a "tagName" property. If it has children,
381 * then it must have a "childNodes" property containing an array of objects.
382 * The other properties are attributes with string values.
383 * @param jo A JSONObject.
384 * @return An XML string.
385 * @throws JSONException
386 */
387 public static String toString(JSONObject jo) throws JSONException {
388 StringBuffer sb = new StringBuffer();
389 int i;
390 JSONArray ja;
391 String key;
392 Iterator keys;
393 int length;
394 Object object;
395 String tagName;
396 String value;
397
398//Emit <tagName
399
400 tagName = jo.optString("tagName");
401 if (tagName == null) {
402 return XML.escape(jo.toString());
403 }
404 XML.noSpace(tagName);
405 tagName = XML.escape(tagName);
406 sb.append('<');
407 sb.append(tagName);
408
409//Emit the attributes
410
411 keys = jo.keys();
412 while (keys.hasNext()) {
413 key = keys.next().toString();
414 if (!key.equals("tagName") && !key.equals("childNodes")) {
415 XML.noSpace(key);
416 value = jo.optString(key);
417 if (value != null) {
418 sb.append(' ');
419 sb.append(XML.escape(key));
420 sb.append('=');
421 sb.append('"');
422 sb.append(XML.escape(value));
423 sb.append('"');
424 }
425 }
426 }
427
428//Emit content in body
429
430 ja = jo.optJSONArray("childNodes");
431 if (ja == null) {
432 sb.append('/');
433 sb.append('>');
434 } else {
435 sb.append('>');
436 length = ja.length();
437 for (i = 0; i < length; i += 1) {
438 object = ja.get(i);
439 if (object != null) {
440 if (object instanceof String) {
441 sb.append(XML.escape(object.toString()));
442 } else if (object instanceof JSONObject) {
443 sb.append(toString((JSONObject)object));
444 } else if (object instanceof JSONArray) {
445 sb.append(toString((JSONArray)object));
446 }
447 }
448 }
449 sb.append('<');
450 sb.append('/');
451 sb.append(tagName);
452 sb.append('>');
453 }
454 return sb.toString();
455 }
456}
Note: See TracBrowser for help on using the repository browser.