PageRenderTime 42ms CodeModel.GetById 24ms app.highlight 14ms RepoModel.GetById 0ms app.codeStats 0ms

/utils/src/org/json/JSONML.java

https://bitbucket.org/crholm/mdfs
Java | 465 lines | 298 code | 45 blank | 122 comment | 120 complexity | d7af33832138a63358357e755a6b46b2 MD5 | raw file
  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 2011-11-24
 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(
 49        XMLTokener x,
 50        boolean    arrayForm,
 51        JSONArray  ja
 52    ) throws JSONException {
 53        String     attribute;
 54        char       c;
 55        String       closeTag = null;
 56        int        i;
 57        JSONArray  newja = null;
 58        JSONObject newjo = null;
 59        Object     token;
 60        String       tagName = null;
 61
 62// Test for and skip past these forms:
 63//      <!-- ... -->
 64//      <![  ... ]]>
 65//      <!   ...   >
 66//      <?   ...  ?>
 67
 68        while (true) {
 69            if (!x.more()) {
 70                throw x.syntaxError("Bad XML");
 71            }
 72            token = x.nextContent();
 73            if (token == XML.LT) {
 74                token = x.nextToken();
 75                if (token instanceof Character) {
 76                    if (token == XML.SLASH) {
 77
 78// Close tag </
 79
 80                        token = x.nextToken();
 81                        if (!(token instanceof String)) {
 82                            throw new JSONException(
 83                                    "Expected a closing name instead of '" +
 84                                    token + "'.");
 85                        }
 86                        if (x.nextToken() != XML.GT) {
 87                            throw x.syntaxError("Misshaped close tag");
 88                        }
 89                        return token;
 90                    } else if (token == XML.BANG) {
 91
 92// <!
 93
 94                        c = x.next();
 95                        if (c == '-') {
 96                            if (x.next() == '-') {
 97                                x.skipPast("-->");
 98                            }
 99                            x.back();
100                        } else if (c == '[') {
101                            token = x.nextToken();
102                            if (token.equals("CDATA") && x.next() == '[') {
103                                if (ja != null) {
104                                    ja.put(x.nextCDATA());
105                                }
106                            } else {
107                                throw x.syntaxError("Expected 'CDATA['");
108                            }
109                        } else {
110                            i = 1;
111                            do {
112                                token = x.nextMeta();
113                                if (token == null) {
114                                    throw x.syntaxError("Missing '>' after '<!'.");
115                                } else if (token == XML.LT) {
116                                    i += 1;
117                                } else if (token == XML.GT) {
118                                    i -= 1;
119                                }
120                            } while (i > 0);
121                        }
122                    } else if (token == XML.QUEST) {
123
124// <?
125
126                        x.skipPast("?>");
127                    } else {
128                        throw x.syntaxError("Misshaped tag");
129                    }
130
131// Open tag <
132
133                } else {
134                    if (!(token instanceof String)) {
135                        throw x.syntaxError("Bad tagName '" + token + "'.");
136                    }
137                    tagName = (String)token;
138                    newja = new JSONArray();
139                    newjo = new JSONObject();
140                    if (arrayForm) {
141                        newja.put(tagName);
142                        if (ja != null) {
143                            ja.put(newja);
144                        }
145                    } else {
146                        newjo.put("tagName", tagName);
147                        if (ja != null) {
148                            ja.put(newjo);
149                        }
150                    }
151                    token = null;
152                    for (;;) {
153                        if (token == null) {
154                            token = x.nextToken();
155                        }
156                        if (token == null) {
157                            throw x.syntaxError("Misshaped tag");
158                        }
159                        if (!(token instanceof String)) {
160                            break;
161                        }
162
163// attribute = value
164
165                        attribute = (String)token;
166                        if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {
167                            throw x.syntaxError("Reserved attribute.");
168                        }
169                        token = x.nextToken();
170                        if (token == XML.EQ) {
171                            token = x.nextToken();
172                            if (!(token instanceof String)) {
173                                throw x.syntaxError("Missing value");
174                            }
175                            newjo.accumulate(attribute, XML.stringToValue((String)token));
176                            token = null;
177                        } else {
178                            newjo.accumulate(attribute, "");
179                        }
180                    }
181                    if (arrayForm && newjo.length() > 0) {
182                        newja.put(newjo);
183                    }
184
185// Empty tag <.../>
186
187                    if (token == XML.SLASH) {
188                        if (x.nextToken() != XML.GT) {
189                            throw x.syntaxError("Misshaped tag");
190                        }
191                        if (ja == null) {
192                            if (arrayForm) {
193                                return newja;
194                            } else {
195                                return newjo;
196                            }
197                        }
198
199// Content, between <...> and </...>
200
201                    } else {
202                        if (token != XML.GT) {
203                            throw x.syntaxError("Misshaped tag");
204                        }
205                        closeTag = (String)parse(x, arrayForm, newja);
206                        if (closeTag != null) {
207                            if (!closeTag.equals(tagName)) {
208                                throw x.syntaxError("Mismatched '" + tagName +
209                                        "' and '" + closeTag + "'");
210                            }
211                            tagName = null;
212                            if (!arrayForm && newja.length() > 0) {
213                                newjo.put("childNodes", newja);
214                            }
215                            if (ja == null) {
216                                if (arrayForm) {
217                                    return newja;
218                                } else {
219                                    return newjo;
220                                }
221                            }
222                        }
223                    }
224                }
225            } else {
226                if (ja != null) {
227                    ja.put(token instanceof String
228                        ? XML.stringToValue((String)token)
229                        : token);
230                }
231            }
232        }
233    }
234
235
236    /**
237     * Convert a well-formed (but not necessarily valid) XML string into a
238     * JSONArray using the JsonML transform. Each XML tag is represented as
239     * a JSONArray in which the first element is the tag name. If the tag has
240     * attributes, then the second element will be JSONObject containing the
241     * name/value pairs. If the tag contains children, then strings and
242     * JSONArrays will represent the child tags.
243     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
244     * @param string The source string.
245     * @return A JSONArray containing the structured data from the XML string.
246     * @throws JSONException
247     */
248    public static JSONArray toJSONArray(String string) throws JSONException {
249        return toJSONArray(new XMLTokener(string));
250    }
251
252
253    /**
254     * Convert a well-formed (but not necessarily valid) XML string into a
255     * JSONArray using the JsonML transform. Each XML tag is represented as
256     * a JSONArray in which the first element is the tag name. If the tag has
257     * attributes, then the second element will be JSONObject containing the
258     * name/value pairs. If the tag contains children, then strings and
259     * JSONArrays will represent the child content and tags.
260     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
261     * @param x An XMLTokener.
262     * @return A JSONArray containing the structured data from the XML string.
263     * @throws JSONException
264     */
265    public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
266        return (JSONArray)parse(x, true, null);
267    }
268
269
270    /**
271     * Convert a well-formed (but not necessarily valid) XML string into a
272     * JSONObject using the JsonML transform. Each XML tag is represented as
273     * a JSONObject with a "tagName" property. If the tag has attributes, then
274     * the attributes will be in the JSONObject as properties. If the tag
275     * contains children, the object will have a "childNodes" property which
276     * will be an array of strings and JsonML JSONObjects.
277
278     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
279     * @param x An XMLTokener of the XML source text.
280     * @return A JSONObject containing the structured data from the XML string.
281     * @throws JSONException
282     */
283    public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
284           return (JSONObject)parse(x, false, null);
285    }
286
287
288    /**
289     * Convert a well-formed (but not necessarily valid) XML string into a
290     * JSONObject using the JsonML transform. Each XML tag is represented as
291     * a JSONObject with a "tagName" property. If the tag has attributes, then
292     * the attributes will be in the JSONObject as properties. If the tag
293     * contains children, the object will have a "childNodes" property which
294     * will be an array of strings and JsonML JSONObjects.
295
296     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
297     * @param string The XML source text.
298     * @return A JSONObject containing the structured data from the XML string.
299     * @throws JSONException
300     */
301    public static JSONObject toJSONObject(String string) throws JSONException {
302        return toJSONObject(new XMLTokener(string));
303    }
304
305
306    /**
307     * Reverse the JSONML transformation, making an XML text from a JSONArray.
308     * @param ja A JSONArray.
309     * @return An XML string.
310     * @throws JSONException
311     */
312    public static String toString(JSONArray ja) throws JSONException {
313        int             i;
314        JSONObject   jo;
315        String       key;
316        Iterator     keys;
317        int             length;
318        Object         object;
319        StringBuffer sb = new StringBuffer();
320        String       tagName;
321        String       value;
322
323// Emit <tagName
324
325        tagName = ja.getString(0);
326        XML.noSpace(tagName);
327        tagName = XML.escape(tagName);
328        sb.append('<');
329        sb.append(tagName);
330
331        object = ja.opt(1);
332        if (object instanceof JSONObject) {
333            i = 2;
334            jo = (JSONObject)object;
335
336// Emit the attributes
337
338            keys = jo.keys();
339            while (keys.hasNext()) {
340                key = keys.next().toString();
341                XML.noSpace(key);
342                value = jo.optString(key);
343                if (value != null) {
344                    sb.append(' ');
345                    sb.append(XML.escape(key));
346                    sb.append('=');
347                    sb.append('"');
348                    sb.append(XML.escape(value));
349                    sb.append('"');
350                }
351            }
352        } else {
353            i = 1;
354        }
355
356//Emit content in body
357
358        length = ja.length();
359        if (i >= length) {
360            sb.append('/');
361            sb.append('>');
362        } else {
363            sb.append('>');
364            do {
365                object = ja.get(i);
366                i += 1;
367                if (object != null) {
368                    if (object instanceof String) {
369                        sb.append(XML.escape(object.toString()));
370                    } else if (object instanceof JSONObject) {
371                        sb.append(toString((JSONObject)object));
372                    } else if (object instanceof JSONArray) {
373                        sb.append(toString((JSONArray)object));
374                    }
375                }
376            } while (i < length);
377            sb.append('<');
378            sb.append('/');
379            sb.append(tagName);
380            sb.append('>');
381        }
382        return sb.toString();
383    }
384
385    /**
386     * Reverse the JSONML transformation, making an XML text from a JSONObject.
387     * The JSONObject must contain a "tagName" property. If it has children,
388     * then it must have a "childNodes" property containing an array of objects.
389     * The other properties are attributes with string values.
390     * @param jo A JSONObject.
391     * @return An XML string.
392     * @throws JSONException
393     */
394    public static String toString(JSONObject jo) throws JSONException {
395        StringBuffer sb = new StringBuffer();
396        int          i;
397        JSONArray    ja;
398        String       key;
399        Iterator     keys;
400        int          length;
401        Object         object;
402        String       tagName;
403        String       value;
404
405//Emit <tagName
406
407        tagName = jo.optString("tagName");
408        if (tagName == null) {
409            return XML.escape(jo.toString());
410        }
411        XML.noSpace(tagName);
412        tagName = XML.escape(tagName);
413        sb.append('<');
414        sb.append(tagName);
415
416//Emit the attributes
417
418        keys = jo.keys();
419        while (keys.hasNext()) {
420            key = keys.next().toString();
421            if (!"tagName".equals(key) && !"childNodes".equals(key)) {
422                XML.noSpace(key);
423                value = jo.optString(key);
424                if (value != null) {
425                    sb.append(' ');
426                    sb.append(XML.escape(key));
427                    sb.append('=');
428                    sb.append('"');
429                    sb.append(XML.escape(value));
430                    sb.append('"');
431                }
432            }
433        }
434
435//Emit content in body
436
437        ja = jo.optJSONArray("childNodes");
438        if (ja == null) {
439            sb.append('/');
440            sb.append('>');
441        } else {
442            sb.append('>');
443            length = ja.length();
444            for (i = 0; i < length; i += 1) {
445                object = ja.get(i);
446                if (object != null) {
447                    if (object instanceof String) {
448                        sb.append(XML.escape(object.toString()));
449                    } else if (object instanceof JSONObject) {
450                        sb.append(toString((JSONObject)object));
451                    } else if (object instanceof JSONArray) {
452                        sb.append(toString((JSONArray)object));
453                    } else {
454                        sb.append(object.toString());
455                    }
456                }
457            }
458            sb.append('<');
459            sb.append('/');
460            sb.append(tagName);
461            sb.append('>');
462        }
463        return sb.toString();
464    }
465}