Mercurial > hg > fulltextSearchServer
comparison lib/org.json_2.0/src/org/json/XML.java @ 0:db87c1b7eb6d
initial
author | dwinter |
---|---|
date | Wed, 03 Nov 2010 12:18:46 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:db87c1b7eb6d |
---|---|
1 package org.json; | |
2 | |
3 /* | |
4 Copyright (c) 2002 JSON.org | |
5 | |
6 Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 of this software and associated documentation files (the "Software"), to deal | |
8 in the Software without restriction, including without limitation the rights | |
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 copies of the Software, and to permit persons to whom the Software is | |
11 furnished to do so, subject to the following conditions: | |
12 | |
13 The above copyright notice and this permission notice shall be included in all | |
14 copies or substantial portions of the Software. | |
15 | |
16 The Software shall be used for Good, not Evil. | |
17 | |
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
24 SOFTWARE. | |
25 */ | |
26 | |
27 import java.util.Iterator; | |
28 | |
29 | |
30 /** | |
31 * This provides static methods to convert an XML text into a JSONObject, | |
32 * and to covert a JSONObject into an XML text. | |
33 * @author JSON.org | |
34 * @version 2008-10-14 | |
35 */ | |
36 public class XML { | |
37 | |
38 /** The Character '&'. */ | |
39 public static final Character AMP = new Character('&'); | |
40 | |
41 /** The Character '''. */ | |
42 public static final Character APOS = new Character('\''); | |
43 | |
44 /** The Character '!'. */ | |
45 public static final Character BANG = new Character('!'); | |
46 | |
47 /** The Character '='. */ | |
48 public static final Character EQ = new Character('='); | |
49 | |
50 /** The Character '>'. */ | |
51 public static final Character GT = new Character('>'); | |
52 | |
53 /** The Character '<'. */ | |
54 public static final Character LT = new Character('<'); | |
55 | |
56 /** The Character '?'. */ | |
57 public static final Character QUEST = new Character('?'); | |
58 | |
59 /** The Character '"'. */ | |
60 public static final Character QUOT = new Character('"'); | |
61 | |
62 /** The Character '/'. */ | |
63 public static final Character SLASH = new Character('/'); | |
64 | |
65 /** | |
66 * Replace special characters with XML escapes: | |
67 * <pre> | |
68 * & <small>(ampersand)</small> is replaced by &amp; | |
69 * < <small>(less than)</small> is replaced by &lt; | |
70 * > <small>(greater than)</small> is replaced by &gt; | |
71 * " <small>(double quote)</small> is replaced by &quot; | |
72 * </pre> | |
73 * @param string The string to be escaped. | |
74 * @return The escaped string. | |
75 */ | |
76 public static String escape(String string) { | |
77 StringBuffer sb = new StringBuffer(); | |
78 for (int i = 0, len = string.length(); i < len; i++) { | |
79 char c = string.charAt(i); | |
80 switch (c) { | |
81 case '&': | |
82 sb.append("&"); | |
83 break; | |
84 case '<': | |
85 sb.append("<"); | |
86 break; | |
87 case '>': | |
88 sb.append(">"); | |
89 break; | |
90 case '"': | |
91 sb.append("""); | |
92 break; | |
93 default: | |
94 sb.append(c); | |
95 } | |
96 } | |
97 return sb.toString(); | |
98 } | |
99 | |
100 /** | |
101 * Throw an exception if the string contains whitespace. | |
102 * Whitespace is not allowed in tagNames and attributes. | |
103 * @param string | |
104 * @throws JSONException | |
105 */ | |
106 public static void noSpace(String string) throws JSONException { | |
107 int i, length = string.length(); | |
108 if (length == 0) { | |
109 throw new JSONException("Empty string."); | |
110 } | |
111 for (i = 0; i < length; i += 1) { | |
112 if (Character.isWhitespace(string.charAt(i))) { | |
113 throw new JSONException("'" + string + | |
114 "' contains a space character."); | |
115 } | |
116 } | |
117 } | |
118 | |
119 /** | |
120 * Scan the content following the named tag, attaching it to the context. | |
121 * @param x The XMLTokener containing the source string. | |
122 * @param context The JSONObject that will include the new material. | |
123 * @param name The tag name. | |
124 * @return true if the close tag is processed. | |
125 * @throws JSONException | |
126 */ | |
127 private static boolean parse(XMLTokener x, JSONObject context, | |
128 String name) throws JSONException { | |
129 char c; | |
130 int i; | |
131 String n; | |
132 JSONObject o = null; | |
133 String s; | |
134 Object t; | |
135 | |
136 // Test for and skip past these forms: | |
137 // <!-- ... --> | |
138 // <! ... > | |
139 // <![ ... ]]> | |
140 // <? ... ?> | |
141 // Report errors for these forms: | |
142 // <> | |
143 // <= | |
144 // << | |
145 | |
146 t = x.nextToken(); | |
147 | |
148 // <! | |
149 | |
150 if (t == BANG) { | |
151 c = x.next(); | |
152 if (c == '-') { | |
153 if (x.next() == '-') { | |
154 x.skipPast("-->"); | |
155 return false; | |
156 } | |
157 x.back(); | |
158 } else if (c == '[') { | |
159 t = x.nextToken(); | |
160 if (t.equals("CDATA")) { | |
161 if (x.next() == '[') { | |
162 s = x.nextCDATA(); | |
163 if (s.length() > 0) { | |
164 context.accumulate("content", s); | |
165 } | |
166 return false; | |
167 } | |
168 } | |
169 throw x.syntaxError("Expected 'CDATA['"); | |
170 } | |
171 i = 1; | |
172 do { | |
173 t = x.nextMeta(); | |
174 if (t == null) { | |
175 throw x.syntaxError("Missing '>' after '<!'."); | |
176 } else if (t == LT) { | |
177 i += 1; | |
178 } else if (t == GT) { | |
179 i -= 1; | |
180 } | |
181 } while (i > 0); | |
182 return false; | |
183 } else if (t == QUEST) { | |
184 | |
185 // <? | |
186 | |
187 x.skipPast("?>"); | |
188 return false; | |
189 } else if (t == SLASH) { | |
190 | |
191 // Close tag </ | |
192 | |
193 t = x.nextToken(); | |
194 if (name == null) { | |
195 throw x.syntaxError("Mismatched close tag" + t); | |
196 } | |
197 if (!t.equals(name)) { | |
198 throw x.syntaxError("Mismatched " + name + " and " + t); | |
199 } | |
200 if (x.nextToken() != GT) { | |
201 throw x.syntaxError("Misshaped close tag"); | |
202 } | |
203 return true; | |
204 | |
205 } else if (t instanceof Character) { | |
206 throw x.syntaxError("Misshaped tag"); | |
207 | |
208 // Open tag < | |
209 | |
210 } else { | |
211 n = (String)t; | |
212 t = null; | |
213 o = new JSONObject(); | |
214 for (;;) { | |
215 if (t == null) { | |
216 t = x.nextToken(); | |
217 } | |
218 | |
219 // attribute = value | |
220 | |
221 if (t instanceof String) { | |
222 s = (String)t; | |
223 t = x.nextToken(); | |
224 if (t == EQ) { | |
225 t = x.nextToken(); | |
226 if (!(t instanceof String)) { | |
227 throw x.syntaxError("Missing value"); | |
228 } | |
229 o.accumulate(s, JSONObject.stringToValue((String)t)); | |
230 t = null; | |
231 } else { | |
232 o.accumulate(s, ""); | |
233 } | |
234 | |
235 // Empty tag <.../> | |
236 | |
237 } else if (t == SLASH) { | |
238 if (x.nextToken() != GT) { | |
239 throw x.syntaxError("Misshaped tag"); | |
240 } | |
241 context.accumulate(n, o); | |
242 return false; | |
243 | |
244 // Content, between <...> and </...> | |
245 | |
246 } else if (t == GT) { | |
247 for (;;) { | |
248 t = x.nextContent(); | |
249 if (t == null) { | |
250 if (n != null) { | |
251 throw x.syntaxError("Unclosed tag " + n); | |
252 } | |
253 return false; | |
254 } else if (t instanceof String) { | |
255 s = (String)t; | |
256 if (s.length() > 0) { | |
257 o.accumulate("content", JSONObject.stringToValue(s)); | |
258 } | |
259 | |
260 // Nested element | |
261 | |
262 } else if (t == LT) { | |
263 if (parse(x, o, n)) { | |
264 if (o.length() == 0) { | |
265 context.accumulate(n, ""); | |
266 } else if (o.length() == 1 && | |
267 o.opt("content") != null) { | |
268 context.accumulate(n, o.opt("content")); | |
269 } else { | |
270 context.accumulate(n, o); | |
271 } | |
272 return false; | |
273 } | |
274 } | |
275 } | |
276 } else { | |
277 throw x.syntaxError("Misshaped tag"); | |
278 } | |
279 } | |
280 } | |
281 } | |
282 | |
283 | |
284 /** | |
285 * Convert a well-formed (but not necessarily valid) XML string into a | |
286 * JSONObject. Some information may be lost in this transformation | |
287 * because JSON is a data format and XML is a document format. XML uses | |
288 * elements, attributes, and content text, while JSON uses unordered | |
289 * collections of name/value pairs and arrays of values. JSON does not | |
290 * does not like to distinguish between elements and attributes. | |
291 * Sequences of similar elements are represented as JSONArrays. Content | |
292 * text may be placed in a "content" member. Comments, prologs, DTDs, and | |
293 * <code><[ [ ]]></code> are ignored. | |
294 * @param string The source string. | |
295 * @return A JSONObject containing the structured data from the XML string. | |
296 * @throws JSONException | |
297 */ | |
298 public static JSONObject toJSONObject(String string) throws JSONException { | |
299 JSONObject o = new JSONObject(); | |
300 XMLTokener x = new XMLTokener(string); | |
301 while (x.more() && x.skipPast("<")) { | |
302 parse(x, o, null); | |
303 } | |
304 return o; | |
305 } | |
306 | |
307 | |
308 /** | |
309 * Convert a JSONObject into a well-formed, element-normal XML string. | |
310 * @param o A JSONObject. | |
311 * @return A string. | |
312 * @throws JSONException | |
313 */ | |
314 public static String toString(Object o) throws JSONException { | |
315 return toString(o, null); | |
316 } | |
317 | |
318 | |
319 /** | |
320 * Convert a JSONObject into a well-formed, element-normal XML string. | |
321 * @param o A JSONObject. | |
322 * @param tagName The optional name of the enclosing tag. | |
323 * @return A string. | |
324 * @throws JSONException | |
325 */ | |
326 public static String toString(Object o, String tagName) | |
327 throws JSONException { | |
328 StringBuffer b = new StringBuffer(); | |
329 int i; | |
330 JSONArray ja; | |
331 JSONObject jo; | |
332 String k; | |
333 Iterator keys; | |
334 int len; | |
335 String s; | |
336 Object v; | |
337 if (o instanceof JSONObject) { | |
338 | |
339 // Emit <tagName> | |
340 | |
341 if (tagName != null) { | |
342 b.append('<'); | |
343 b.append(tagName); | |
344 b.append('>'); | |
345 } | |
346 | |
347 // Loop thru the keys. | |
348 | |
349 jo = (JSONObject)o; | |
350 keys = jo.keys(); | |
351 while (keys.hasNext()) { | |
352 k = keys.next().toString(); | |
353 v = jo.opt(k); | |
354 if (v == null) { | |
355 v = ""; | |
356 } | |
357 if (v instanceof String) { | |
358 s = (String)v; | |
359 } else { | |
360 s = null; | |
361 } | |
362 | |
363 // Emit content in body | |
364 | |
365 if (k.equals("content")) { | |
366 if (v instanceof JSONArray) { | |
367 ja = (JSONArray)v; | |
368 len = ja.length(); | |
369 for (i = 0; i < len; i += 1) { | |
370 if (i > 0) { | |
371 b.append('\n'); | |
372 } | |
373 b.append(escape(ja.get(i).toString())); | |
374 } | |
375 } else { | |
376 b.append(escape(v.toString())); | |
377 } | |
378 | |
379 // Emit an array of similar keys | |
380 | |
381 } else if (v instanceof JSONArray) { | |
382 ja = (JSONArray)v; | |
383 len = ja.length(); | |
384 for (i = 0; i < len; i += 1) { | |
385 v = ja.get(i); | |
386 if (v instanceof JSONArray) { | |
387 b.append('<'); | |
388 b.append(k); | |
389 b.append('>'); | |
390 b.append(toString(v)); | |
391 b.append("</"); | |
392 b.append(k); | |
393 b.append('>'); | |
394 } else { | |
395 b.append(toString(v, k)); | |
396 } | |
397 } | |
398 } else if (v.equals("")) { | |
399 b.append('<'); | |
400 b.append(k); | |
401 b.append("/>"); | |
402 | |
403 // Emit a new tag <k> | |
404 | |
405 } else { | |
406 b.append(toString(v, k)); | |
407 } | |
408 } | |
409 if (tagName != null) { | |
410 | |
411 // Emit the </tagname> close tag | |
412 | |
413 b.append("</"); | |
414 b.append(tagName); | |
415 b.append('>'); | |
416 } | |
417 return b.toString(); | |
418 | |
419 // XML does not have good support for arrays. If an array appears in a place | |
420 // where XML is lacking, synthesize an <array> element. | |
421 | |
422 } else if (o instanceof JSONArray) { | |
423 ja = (JSONArray)o; | |
424 len = ja.length(); | |
425 for (i = 0; i < len; ++i) { | |
426 v = ja.opt(i); | |
427 b.append(toString(v, (tagName == null) ? "array" : tagName)); | |
428 } | |
429 return b.toString(); | |
430 } else { | |
431 s = (o == null) ? "null" : escape(o.toString()); | |
432 return (tagName == null) ? "\"" + s + "\"" : | |
433 (s.length() == 0) ? "<" + tagName + "/>" : | |
434 "<" + tagName + ">" + s + "</" + tagName + ">"; | |
435 } | |
436 } | |
437 } |