Clover icon

Coverage Report

  1. Project Clover database Thu Aug 13 2020 12:04:21 BST
  2. Package org.json

File JSONML.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
56% of files have more coverage

Code metrics

118
202
11
1
542
302
76
0.38
18.36
11
6.91

Classes

Class Line # Actions
JSONML 35 202 76
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    package org.json;
2   
3    /*
4    Copyright (c) 2008 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    /**
28    * This provides static methods to convert an XML text into a JSONArray or
29    * JSONObject, and to covert a JSONArray or JSONObject into an XML text using
30    * the JsonML transform.
31    *
32    * @author JSON.org
33    * @version 2016-01-30
34    */
 
35    public class JSONML {
36    /**
37    * Parse XML values and store them in a JSONArray.
38    * @param x The XMLTokener containing the source string.
39    * @param arrayForm true if array form, false if object form.
40    * @param ja The JSONArray that is containing the current tag or null
41    * if we are at the outermost level.
42    * @param keepStrings Don't type-convert text nodes and attribute values
43    * @return A JSONArray if the value is the outermost tag, otherwise null.
44    * @throws JSONException
45    */
 
46  0 toggle private static Object parse(
47    XMLTokener x,
48    boolean arrayForm,
49    JSONArray ja,
50    boolean keepStrings
51    ) throws JSONException {
52  0 String attribute;
53  0 char c;
54  0 String closeTag = null;
55  0 int i;
56  0 JSONArray newja = null;
57  0 JSONObject newjo = null;
58  0 Object token;
59  0 String tagName = null;
60   
61    // Test for and skip past these forms:
62    // <!-- ... -->
63    // <![ ... ]]>
64    // <! ... >
65    // <? ... ?>
66   
67  0 while (true) {
68  0 if (!x.more()) {
69  0 throw x.syntaxError("Bad XML");
70    }
71  0 token = x.nextContent();
72  0 if (token == XML.LT) {
73  0 token = x.nextToken();
74  0 if (token instanceof Character) {
75  0 if (token == XML.SLASH) {
76   
77    // Close tag </
78   
79  0 token = x.nextToken();
80  0 if (!(token instanceof String)) {
81  0 throw new JSONException(
82    "Expected a closing name instead of '" +
83    token + "'.");
84    }
85  0 if (x.nextToken() != XML.GT) {
86  0 throw x.syntaxError("Misshaped close tag");
87    }
88  0 return token;
89  0 } else if (token == XML.BANG) {
90   
91    // <!
92   
93  0 c = x.next();
94  0 if (c == '-') {
95  0 if (x.next() == '-') {
96  0 x.skipPast("-->");
97    } else {
98  0 x.back();
99    }
100  0 } else if (c == '[') {
101  0 token = x.nextToken();
102  0 if (token.equals("CDATA") && x.next() == '[') {
103  0 if (ja != null) {
104  0 ja.put(x.nextCDATA());
105    }
106    } else {
107  0 throw x.syntaxError("Expected 'CDATA['");
108    }
109    } else {
110  0 i = 1;
111  0 do {
112  0 token = x.nextMeta();
113  0 if (token == null) {
114  0 throw x.syntaxError("Missing '>' after '<!'.");
115  0 } else if (token == XML.LT) {
116  0 i += 1;
117  0 } else if (token == XML.GT) {
118  0 i -= 1;
119    }
120  0 } while (i > 0);
121    }
122  0 } else if (token == XML.QUEST) {
123   
124    // <?
125   
126  0 x.skipPast("?>");
127    } else {
128  0 throw x.syntaxError("Misshaped tag");
129    }
130   
131    // Open tag <
132   
133    } else {
134  0 if (!(token instanceof String)) {
135  0 throw x.syntaxError("Bad tagName '" + token + "'.");
136    }
137  0 tagName = (String)token;
138  0 newja = new JSONArray();
139  0 newjo = new JSONObject();
140  0 if (arrayForm) {
141  0 newja.put(tagName);
142  0 if (ja != null) {
143  0 ja.put(newja);
144    }
145    } else {
146  0 newjo.put("tagName", tagName);
147  0 if (ja != null) {
148  0 ja.put(newjo);
149    }
150    }
151  0 token = null;
152  0 for (;;) {
153  0 if (token == null) {
154  0 token = x.nextToken();
155    }
156  0 if (token == null) {
157  0 throw x.syntaxError("Misshaped tag");
158    }
159  0 if (!(token instanceof String)) {
160  0 break;
161    }
162   
163    // attribute = value
164   
165  0 attribute = (String)token;
166  0 if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) {
167  0 throw x.syntaxError("Reserved attribute.");
168    }
169  0 token = x.nextToken();
170  0 if (token == XML.EQ) {
171  0 token = x.nextToken();
172  0 if (!(token instanceof String)) {
173  0 throw x.syntaxError("Missing value");
174    }
175  0 newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token));
176  0 token = null;
177    } else {
178  0 newjo.accumulate(attribute, "");
179    }
180    }
181  0 if (arrayForm && newjo.length() > 0) {
182  0 newja.put(newjo);
183    }
184   
185    // Empty tag <.../>
186   
187  0 if (token == XML.SLASH) {
188  0 if (x.nextToken() != XML.GT) {
189  0 throw x.syntaxError("Misshaped tag");
190    }
191  0 if (ja == null) {
192  0 if (arrayForm) {
193  0 return newja;
194    }
195  0 return newjo;
196    }
197   
198    // Content, between <...> and </...>
199   
200    } else {
201  0 if (token != XML.GT) {
202  0 throw x.syntaxError("Misshaped tag");
203    }
204  0 closeTag = (String)parse(x, arrayForm, newja, keepStrings);
205  0 if (closeTag != null) {
206  0 if (!closeTag.equals(tagName)) {
207  0 throw x.syntaxError("Mismatched '" + tagName +
208    "' and '" + closeTag + "'");
209    }
210  0 tagName = null;
211  0 if (!arrayForm && newja.length() > 0) {
212  0 newjo.put("childNodes", newja);
213    }
214  0 if (ja == null) {
215  0 if (arrayForm) {
216  0 return newja;
217    }
218  0 return newjo;
219    }
220    }
221    }
222    }
223    } else {
224  0 if (ja != null) {
225  0 ja.put(token instanceof String
226  0 ? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token)
227    : token);
228    }
229    }
230    }
231    }
232   
233   
234    /**
235    * Convert a well-formed (but not necessarily valid) XML string into a
236    * JSONArray using the JsonML transform. Each XML tag is represented as
237    * a JSONArray in which the first element is the tag name. If the tag has
238    * attributes, then the second element will be JSONObject containing the
239    * name/value pairs. If the tag contains children, then strings and
240    * JSONArrays will represent the child tags.
241    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
242    * @param string The source string.
243    * @return A JSONArray containing the structured data from the XML string.
244    * @throws JSONException Thrown on error converting to a JSONArray
245    */
 
246  0 toggle public static JSONArray toJSONArray(String string) throws JSONException {
247  0 return (JSONArray)parse(new XMLTokener(string), true, null, false);
248    }
249   
250   
251    /**
252    * Convert a well-formed (but not necessarily valid) XML string into a
253    * JSONArray using the JsonML transform. Each XML tag is represented as
254    * a JSONArray in which the first element is the tag name. If the tag has
255    * attributes, then the second element will be JSONObject containing the
256    * name/value pairs. If the tag contains children, then strings and
257    * JSONArrays will represent the child tags.
258    * As opposed to toJSONArray this method does not attempt to convert
259    * any text node or attribute value to any type
260    * but just leaves it as a string.
261    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
262    * @param string The source string.
263    * @param keepStrings If true, then values will not be coerced into boolean
264    * or numeric values and will instead be left as strings
265    * @return A JSONArray containing the structured data from the XML string.
266    * @throws JSONException Thrown on error converting to a JSONArray
267    */
 
268  0 toggle public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException {
269  0 return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings);
270    }
271   
272   
273    /**
274    * Convert a well-formed (but not necessarily valid) XML string into a
275    * JSONArray using the JsonML transform. Each XML tag is represented as
276    * a JSONArray in which the first element is the tag name. If the tag has
277    * attributes, then the second element will be JSONObject containing the
278    * name/value pairs. If the tag contains children, then strings and
279    * JSONArrays will represent the child content and tags.
280    * As opposed to toJSONArray this method does not attempt to convert
281    * any text node or attribute value to any type
282    * but just leaves it as a string.
283    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
284    * @param x An XMLTokener.
285    * @param keepStrings If true, then values will not be coerced into boolean
286    * or numeric values and will instead be left as strings
287    * @return A JSONArray containing the structured data from the XML string.
288    * @throws JSONException Thrown on error converting to a JSONArray
289    */
 
290  0 toggle public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException {
291  0 return (JSONArray)parse(x, true, null, keepStrings);
292    }
293   
294   
295    /**
296    * Convert a well-formed (but not necessarily valid) XML string into a
297    * JSONArray using the JsonML transform. Each XML tag is represented as
298    * a JSONArray in which the first element is the tag name. If the tag has
299    * attributes, then the second element will be JSONObject containing the
300    * name/value pairs. If the tag contains children, then strings and
301    * JSONArrays will represent the child content and tags.
302    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
303    * @param x An XMLTokener.
304    * @return A JSONArray containing the structured data from the XML string.
305    * @throws JSONException Thrown on error converting to a JSONArray
306    */
 
307  0 toggle public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
308  0 return (JSONArray)parse(x, true, null, false);
309    }
310   
311   
312    /**
313    * Convert a well-formed (but not necessarily valid) XML string into a
314    * JSONObject using the JsonML transform. Each XML tag is represented as
315    * a JSONObject with a "tagName" property. If the tag has attributes, then
316    * the attributes will be in the JSONObject as properties. If the tag
317    * contains children, the object will have a "childNodes" property which
318    * will be an array of strings and JsonML JSONObjects.
319   
320    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
321    * @param string The XML source text.
322    * @return A JSONObject containing the structured data from the XML string.
323    * @throws JSONException Thrown on error converting to a JSONObject
324    */
 
325  0 toggle public static JSONObject toJSONObject(String string) throws JSONException {
326  0 return (JSONObject)parse(new XMLTokener(string), false, null, false);
327    }
328   
329   
330    /**
331    * Convert a well-formed (but not necessarily valid) XML string into a
332    * JSONObject using the JsonML transform. Each XML tag is represented as
333    * a JSONObject with a "tagName" property. If the tag has attributes, then
334    * the attributes will be in the JSONObject as properties. If the tag
335    * contains children, the object will have a "childNodes" property which
336    * will be an array of strings and JsonML JSONObjects.
337   
338    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
339    * @param string The XML source text.
340    * @param keepStrings If true, then values will not be coerced into boolean
341    * or numeric values and will instead be left as strings
342    * @return A JSONObject containing the structured data from the XML string.
343    * @throws JSONException Thrown on error converting to a JSONObject
344    */
 
345  0 toggle public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException {
346  0 return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings);
347    }
348   
349   
350    /**
351    * Convert a well-formed (but not necessarily valid) XML string into a
352    * JSONObject using the JsonML transform. Each XML tag is represented as
353    * a JSONObject with a "tagName" property. If the tag has attributes, then
354    * the attributes will be in the JSONObject as properties. If the tag
355    * contains children, the object will have a "childNodes" property which
356    * will be an array of strings and JsonML JSONObjects.
357   
358    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
359    * @param x An XMLTokener of the XML source text.
360    * @return A JSONObject containing the structured data from the XML string.
361    * @throws JSONException Thrown on error converting to a JSONObject
362    */
 
363  0 toggle public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
364  0 return (JSONObject)parse(x, false, null, false);
365    }
366   
367   
368    /**
369    * Convert a well-formed (but not necessarily valid) XML string into a
370    * JSONObject using the JsonML transform. Each XML tag is represented as
371    * a JSONObject with a "tagName" property. If the tag has attributes, then
372    * the attributes will be in the JSONObject as properties. If the tag
373    * contains children, the object will have a "childNodes" property which
374    * will be an array of strings and JsonML JSONObjects.
375   
376    * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
377    * @param x An XMLTokener of the XML source text.
378    * @param keepStrings If true, then values will not be coerced into boolean
379    * or numeric values and will instead be left as strings
380    * @return A JSONObject containing the structured data from the XML string.
381    * @throws JSONException Thrown on error converting to a JSONObject
382    */
 
383  0 toggle public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException {
384  0 return (JSONObject)parse(x, false, null, keepStrings);
385    }
386   
387   
388    /**
389    * Reverse the JSONML transformation, making an XML text from a JSONArray.
390    * @param ja A JSONArray.
391    * @return An XML string.
392    * @throws JSONException Thrown on error converting to a string
393    */
 
394  0 toggle public static String toString(JSONArray ja) throws JSONException {
395  0 int i;
396  0 JSONObject jo;
397  0 int length;
398  0 Object object;
399  0 StringBuilder sb = new StringBuilder();
400  0 String tagName;
401   
402    // Emit <tagName
403   
404  0 tagName = ja.getString(0);
405  0 XML.noSpace(tagName);
406  0 tagName = XML.escape(tagName);
407  0 sb.append('<');
408  0 sb.append(tagName);
409   
410  0 object = ja.opt(1);
411  0 if (object instanceof JSONObject) {
412  0 i = 2;
413  0 jo = (JSONObject)object;
414   
415    // Emit the attributes
416   
417    // Don't use the new entrySet API to maintain Android support
418  0 for (final String key : jo.keySet()) {
419  0 final Object value = jo.opt(key);
420  0 XML.noSpace(key);
421  0 if (value != null) {
422  0 sb.append(' ');
423  0 sb.append(XML.escape(key));
424  0 sb.append('=');
425  0 sb.append('"');
426  0 sb.append(XML.escape(value.toString()));
427  0 sb.append('"');
428    }
429    }
430    } else {
431  0 i = 1;
432    }
433   
434    // Emit content in body
435   
436  0 length = ja.length();
437  0 if (i >= length) {
438  0 sb.append('/');
439  0 sb.append('>');
440    } else {
441  0 sb.append('>');
442  0 do {
443  0 object = ja.get(i);
444  0 i += 1;
445  0 if (object != null) {
446  0 if (object instanceof String) {
447  0 sb.append(XML.escape(object.toString()));
448  0 } else if (object instanceof JSONObject) {
449  0 sb.append(toString((JSONObject)object));
450  0 } else if (object instanceof JSONArray) {
451  0 sb.append(toString((JSONArray)object));
452    } else {
453  0 sb.append(object.toString());
454    }
455    }
456  0 } while (i < length);
457  0 sb.append('<');
458  0 sb.append('/');
459  0 sb.append(tagName);
460  0 sb.append('>');
461    }
462  0 return sb.toString();
463    }
464   
465    /**
466    * Reverse the JSONML transformation, making an XML text from a JSONObject.
467    * The JSONObject must contain a "tagName" property. If it has children,
468    * then it must have a "childNodes" property containing an array of objects.
469    * The other properties are attributes with string values.
470    * @param jo A JSONObject.
471    * @return An XML string.
472    * @throws JSONException Thrown on error converting to a string
473    */
 
474  0 toggle public static String toString(JSONObject jo) throws JSONException {
475  0 StringBuilder sb = new StringBuilder();
476  0 int i;
477  0 JSONArray ja;
478  0 int length;
479  0 Object object;
480  0 String tagName;
481  0 Object value;
482   
483    //Emit <tagName
484   
485  0 tagName = jo.optString("tagName");
486  0 if (tagName == null) {
487  0 return XML.escape(jo.toString());
488    }
489  0 XML.noSpace(tagName);
490  0 tagName = XML.escape(tagName);
491  0 sb.append('<');
492  0 sb.append(tagName);
493   
494    //Emit the attributes
495   
496    // Don't use the new entrySet API to maintain Android support
497  0 for (final String key : jo.keySet()) {
498  0 if (!"tagName".equals(key) && !"childNodes".equals(key)) {
499  0 XML.noSpace(key);
500  0 value = jo.opt(key);
501  0 if (value != null) {
502  0 sb.append(' ');
503  0 sb.append(XML.escape(key));
504  0 sb.append('=');
505  0 sb.append('"');
506  0 sb.append(XML.escape(value.toString()));
507  0 sb.append('"');
508    }
509    }
510    }
511   
512    //Emit content in body
513   
514  0 ja = jo.optJSONArray("childNodes");
515  0 if (ja == null) {
516  0 sb.append('/');
517  0 sb.append('>');
518    } else {
519  0 sb.append('>');
520  0 length = ja.length();
521  0 for (i = 0; i < length; i += 1) {
522  0 object = ja.get(i);
523  0 if (object != null) {
524  0 if (object instanceof String) {
525  0 sb.append(XML.escape(object.toString()));
526  0 } else if (object instanceof JSONObject) {
527  0 sb.append(toString((JSONObject)object));
528  0 } else if (object instanceof JSONArray) {
529  0 sb.append(toString((JSONArray)object));
530    } else {
531  0 sb.append(object.toString());
532    }
533    }
534    }
535  0 sb.append('<');
536  0 sb.append('/');
537  0 sb.append(tagName);
538  0 sb.append('>');
539    }
540  0 return sb.toString();
541    }
542    }