Clover icon

Coverage Report

  1. Project Clover database Mon Nov 11 2024 17:27:16 GMT
  2. Package org.json

File JSONML.java

 

Coverage histogram

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

Code metrics

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