1 package org
.gaixie
.jibu
.json
;
4 Copyright (c) 2008 JSON.org
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:
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
16 The Software shall be used for Good, not Evil.
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
27 import java
.util
.Iterator
;
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.
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
48 private static Object
parse(XMLTokener x
, boolean arrayForm
,
49 JSONArray ja
) throws JSONException
{
52 String closeTag
= null;
54 JSONArray newja
= null;
55 JSONObject newjo
= null;
57 String tagName
= null;
59 // Test for and skip past these forms:
66 token
= x
.nextContent();
67 if (token
== XML
.LT
) {
68 token
= x
.nextToken();
69 if (token
instanceof Character
) {
70 if (token
== XML
.SLASH
) {
74 token
= x
.nextToken();
75 if (!(token
instanceof String
)) {
76 throw new JSONException(
77 "Expected a closing name instead of '" +
80 if (x
.nextToken() != XML
.GT
) {
81 throw x
.syntaxError("Misshaped close tag");
84 } else if (token
== XML
.BANG
) {
90 if (x
.next() == '-') {
94 } else if (c
== '[') {
95 token
= x
.nextToken();
96 if (token
.equals("CDATA") && x
.next() == '[') {
98 ja
.put(x
.nextCDATA());
101 throw x
.syntaxError("Expected 'CDATA['");
106 token
= x
.nextMeta();
108 throw x
.syntaxError("Missing '>' after '<!'.");
109 } else if (token
== XML
.LT
) {
111 } else if (token
== XML
.GT
) {
116 } else if (token
== XML
.QUEST
) {
122 throw x
.syntaxError("Misshaped tag");
128 if (!(token
instanceof String
)) {
129 throw x
.syntaxError("Bad tagName '" + token
+ "'.");
131 tagName
= (String
)token
;
132 newja
= new JSONArray();
133 newjo
= new JSONObject();
140 newjo
.put("tagName", tagName
);
148 token
= x
.nextToken();
151 throw x
.syntaxError("Misshaped tag");
153 if (!(token
instanceof String
)) {
159 attribute
= (String
)token
;
160 if (!arrayForm
&& (attribute
== "tagName" || attribute
== "childNode")) {
161 throw x
.syntaxError("Reserved attribute.");
163 token
= x
.nextToken();
164 if (token
== XML
.EQ
) {
165 token
= x
.nextToken();
166 if (!(token
instanceof String
)) {
167 throw x
.syntaxError("Missing value");
169 newjo
.accumulate(attribute
, JSONObject
.stringToValue((String
)token
));
172 newjo
.accumulate(attribute
, "");
175 if (arrayForm
&& newjo
.length() > 0) {
181 if (token
== XML
.SLASH
) {
182 if (x
.nextToken() != XML
.GT
) {
183 throw x
.syntaxError("Misshaped tag");
193 // Content, between <...> and </...>
196 if (token
!= XML
.GT
) {
197 throw x
.syntaxError("Misshaped tag");
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
+ "'");
206 if (!arrayForm
&& newja
.length() > 0) {
207 newjo
.put("childNodes", newja
);
221 ja
.put(token
instanceof String ?
222 JSONObject
.stringToValue((String
)token
) : token
);
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><[ [ ]]></code> are ignored.
237 * @param string The source string.
238 * @return A JSONArray containing the structured data from the XML string.
239 * @throws JSONException
241 public static JSONArray
toJSONArray(String string
) throws JSONException
{
242 return toJSONArray(new XMLTokener(string
));
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><[ [ ]]></code> are ignored.
254 * @param x An XMLTokener.
255 * @return A JSONArray containing the structured data from the XML string.
256 * @throws JSONException
258 public static JSONArray
toJSONArray(XMLTokener x
) throws JSONException
{
259 return (JSONArray
)parse(x
, true, null);
265 * Convert a well-formed (but not necessarily valid) XML string into a
266 * JSONObject using the JsonML transform. Each XML tag is represented as
267 * a JSONObject with a "tagName" property. If the tag has attributes, then
268 * the attributes will be in the JSONObject as properties. If the tag
269 * contains children, the object will have a "childNodes" property which
270 * will be an array of strings and JsonML JSONObjects.
272 * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
273 * @param x An XMLTokener of the XML source text.
274 * @return A JSONObject containing the structured data from the XML string.
275 * @throws JSONException
277 public static JSONObject
toJSONObject(XMLTokener x
) throws JSONException
{
278 return (JSONObject
)parse(x
, false, null);
281 * Convert a well-formed (but not necessarily valid) XML string into a
282 * JSONObject using the JsonML transform. Each XML tag is represented as
283 * a JSONObject with a "tagName" property. If the tag has attributes, then
284 * the attributes will be in the JSONObject as properties. If the tag
285 * contains children, the object will have a "childNodes" property which
286 * will be an array of strings and JsonML JSONObjects.
288 * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
289 * @param string The XML source text.
290 * @return A JSONObject containing the structured data from the XML string.
291 * @throws JSONException
293 public static JSONObject
toJSONObject(String string
) throws JSONException
{
294 return toJSONObject(new XMLTokener(string
));
299 * Reverse the JSONML transformation, making an XML text from a JSONArray.
300 * @param ja A JSONArray.
301 * @return An XML string.
302 * @throws JSONException
304 public static String
toString(JSONArray ja
) throws JSONException
{
311 StringBuffer sb
= new StringBuffer();
317 tagName
= ja
.getString(0);
318 XML
.noSpace(tagName
);
319 tagName
= XML
.escape(tagName
);
324 if (e
instanceof JSONObject
) {
328 // Emit the attributes
331 while (keys
.hasNext()) {
332 k
= keys
.next().toString();
337 sb
.append(XML
.escape(k
));
340 sb
.append(XML
.escape(v
));
348 //Emit content in body
350 length
= ja
.length();
360 if (e
instanceof String
) {
361 sb
.append(XML
.escape(e
.toString()));
362 } else if (e
instanceof JSONObject
) {
363 sb
.append(toString((JSONObject
)e
));
364 } else if (e
instanceof JSONArray
) {
365 sb
.append(toString((JSONArray
)e
));
368 } while (i
< length
);
374 return sb
.toString();
378 * Reverse the JSONML transformation, making an XML text from a JSONObject.
379 * The JSONObject must contain a "tagName" property. If it has children,
380 * then it must have a "childNodes" property containing an array of objects.
381 * The other properties are attributes with string values.
382 * @param jo A JSONObject.
383 * @return An XML string.
384 * @throws JSONException
386 public static String
toString(JSONObject jo
) throws JSONException
{
387 StringBuffer sb
= new StringBuffer();
399 tagName
= jo
.optString("tagName");
400 if (tagName
== null) {
401 return XML
.escape(jo
.toString());
403 XML
.noSpace(tagName
);
404 tagName
= XML
.escape(tagName
);
408 //Emit the attributes
411 while (keys
.hasNext()) {
412 k
= keys
.next().toString();
413 if (!k
.equals("tagName") && !k
.equals("childNodes")) {
418 sb
.append(XML
.escape(k
));
421 sb
.append(XML
.escape(v
));
427 //Emit content in body
429 ja
= jo
.optJSONArray("childNodes");
436 for (i
= 0; i
< len
; i
+= 1) {
439 if (e
instanceof String
) {
440 sb
.append(XML
.escape(e
.toString()));
441 } else if (e
instanceof JSONObject
) {
442 sb
.append(toString((JSONObject
)e
));
443 } else if (e
instanceof JSONArray
) {
444 sb
.append(toString((JSONArray
)e
));
453 return sb
.toString();