1 package org.json;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import java.text.ParseException;
28 import java.util.ArrayList;
29 import java.util.Collection;
30 import java.util.NoSuchElementException;
31
32 /**
33 * A JSONArray is an ordered sequence of values. Its external form is a string
34 * wrapped in square brackets with commas between the values. The internal form
35 * is an object having get() and opt() methods for accessing the values by
36 * index, and put() methods for adding or replacing values. The values can be
37 * any of these types: Boolean, JSONArray, JSONObject, Number, String, or the
38 * JSONObject.NULL object.
39 * <p>
40 * The constructor can convert a JSON external form string into an internal form
41 * Java object. The toString() method creates an external form string.
42 * <p>
43 * A get() method returns a value if one can be found, and throws an exception
44 * if one cannot be found. An opt() method returns a default value instead of
45 * throwing an exception, and so is useful for obtaining optional values.
46 * <p>
47 * The generic get() and opt() methods return an object which you can cast or
48 * query for type. There are also typed get() and opt() methods that do typing
49 * checking and type coersion for you.
50 * <p>
51 * The texts produced by the toString() methods are very strict. The
52 * constructors are more forgiving in the texts they will accept.
53 * <ul>
54 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
55 * before the closing bracket.</li>
56 * <li>The null value will be inserted when there is <code>,</code> <small>(comma)</small>
57 * elision.</li>
58 * <li>Strings may be quoted with <code>'</code> <small>(single quote)</small>.</li>
59 * <li>Strings do not need to be quoted at all if they do not begin with a
60 * quote or single quote, and if they do not contain leading or trailing spaces,
61 * and if they do not contain any of these characters:
62 * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
63 * if they are not the reserved words <code>true</code>, <code>false</code>,
64 * or <code>null</code>.</li>
65 * <li>Values can be followed by <code>;</code> as well as by <code>,</code></li>
66 * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
67 * <code>0x-</code> <small>(hex)</small> prefix.</li>
68 * <li>Line comments can begin with <code>#</code></li>
69 * </ul>
70 *
71 * @author JSON.org
72 * @version 1
73 */
74 public class JSONArray {
75
76 /**
77 * The getArrayList where the JSONArray's properties are kept.
78 */
79 private ArrayList myArrayList;
80
81 /**
82 * Construct an empty JSONArray.
83 */
84 public JSONArray() {
85 myArrayList = new ArrayList();
86 }
87
88 /**
89 * Construct a JSONArray from a JSONTokener.
90 *
91 * @exception ParseException
92 * A JSONArray must start with '['
93 * @exception ParseException
94 * Expected a ',' or ']'
95 * @param x
96 * A JSONTokener
97 */
98 @SuppressWarnings("unchecked")
99 public JSONArray(JSONTokener x) throws ParseException {
100 this();
101 if (x.nextClean() != '[') {
102 throw x.syntaxError("A JSONArray must start with '['");
103 }
104 if (x.nextClean() == ']') {
105 return;
106 }
107 x.back();
108 while (true) {
109 if (x.nextClean() == ',') {
110 x.back();
111 myArrayList.add(null);
112 } else {
113 x.back();
114 myArrayList.add(x.nextValue());
115 }
116 switch (x.nextClean()) {
117 case ';':
118 case ',':
119 if (x.nextClean() == ']') {
120 return;
121 }
122 x.back();
123 break;
124 case ']':
125 return;
126 default:
127 throw x.syntaxError("Expected a ',' or ']'");
128 }
129 }
130 }
131
132 /**
133 * Construct a JSONArray from a source string.
134 *
135 * @exception ParseException
136 * The string must conform to JSON syntax.
137 * @param string
138 * A string that begins with <code>[</code> <small>(left
139 * bracket)</small> and ends with <code>]</code> <small>(right
140 * bracket)</small>.
141 */
142 public JSONArray(String string) throws ParseException {
143 this(new JSONTokener(string));
144 }
145
146 /**
147 * Construct a JSONArray from a Collection.
148 *
149 * @param collection
150 * A Collection.
151 */
152 @SuppressWarnings("unchecked")
153 public JSONArray(Collection collection) {
154 myArrayList = new ArrayList(collection);
155 }
156
157 /**
158 * Get the object value associated with an index.
159 *
160 * @exception NoSuchElementException
161 * @param index
162 * The index must be between 0 and length() - 1.
163 * @return An object value.
164 */
165 public Object get(int index) throws NoSuchElementException {
166 Object o = opt(index);
167 if (o == null) {
168 throw new NoSuchElementException("JSONArray[" + index
169 + "] not found.");
170 }
171 return o;
172 }
173
174 /**
175 * Get the ArrayList which is holding the elements of the JSONArray.
176 *
177 * @return The ArrayList.
178 */
179 ArrayList getArrayList() {
180 return myArrayList;
181 }
182
183 /**
184 * Get the boolean value associated with an index. The string values "true"
185 * and "false" are converted to boolean.
186 *
187 * @exception NoSuchElementException
188 * if the index is not found
189 * @exception ClassCastException
190 * @param index
191 * The index must be between 0 and length() - 1.
192 * @return The truth.
193 */
194 public boolean getBoolean(int index) throws ClassCastException,
195 NoSuchElementException {
196 Object o = get(index);
197 if (o.equals(Boolean.FALSE)
198 || (o instanceof String && ((String) o)
199 .equalsIgnoreCase("false"))) {
200 return false;
201 } else if (o.equals(Boolean.TRUE)
202 || (o instanceof String && ((String) o)
203 .equalsIgnoreCase("true"))) {
204 return true;
205 }
206 throw new ClassCastException("JSONArray[" + index + "] not a Boolean.");
207 }
208
209 /**
210 * Get the double value associated with an index.
211 *
212 * @exception NoSuchElementException
213 * if the key is not found
214 * @exception NumberFormatException
215 * if the value cannot be converted to a number.
216 *
217 * @param index
218 * The index must be between 0 and length() - 1.
219 * @return The value.
220 */
221 public double getDouble(int index) throws NoSuchElementException,
222 NumberFormatException {
223 Object o = get(index);
224 if (o instanceof Number) {
225 return ((Number) o).doubleValue();
226 }
227 if (o instanceof String) {
228 return new Double((String) o).doubleValue();
229 }
230 throw new NumberFormatException("JSONObject[" + index
231 + "] is not a number.");
232 }
233
234 /**
235 * Get the int value associated with an index.
236 *
237 * @exception NoSuchElementException
238 * if the key is not found
239 * @exception NumberFormatException
240 * if the value cannot be converted to a number.
241 *
242 * @param index
243 * The index must be between 0 and length() - 1.
244 * @return The value.
245 */
246 public int getInt(int index) throws NoSuchElementException,
247 NumberFormatException {
248 Object o = get(index);
249 return o instanceof Number ? ((Number) o).intValue()
250 : (int) getDouble(index);
251 }
252
253 /**
254 * Get the JSONArray associated with an index.
255 *
256 * @exception NoSuchElementException
257 * if the index is not found or if the value is not a
258 * JSONArray
259 * @param index
260 * The index must be between 0 and length() - 1.
261 * @return A JSONArray value.
262 */
263 public JSONArray getJSONArray(int index) throws NoSuchElementException {
264 Object o = get(index);
265 if (o instanceof JSONArray) {
266 return (JSONArray) o;
267 }
268 throw new NoSuchElementException("JSONArray[" + index
269 + "] is not a JSONArray.");
270 }
271
272 /**
273 * Get the JSONObject associated with an index.
274 *
275 * @exception NoSuchElementException
276 * if the index is not found or if the value is not a
277 * JSONObject
278 * @param index
279 * subscript
280 * @return A JSONObject value.
281 */
282 public JSONObject getJSONObject(int index) throws NoSuchElementException {
283 Object o = get(index);
284 if (o instanceof JSONObject) {
285 return (JSONObject) o;
286 }
287 throw new NoSuchElementException("JSONArray[" + index
288 + "] is not a JSONObject.");
289 }
290
291 /**
292 * Get the string associated with an index.
293 *
294 * @exception NoSuchElementException
295 * @param index
296 * The index must be between 0 and length() - 1.
297 * @return A string value.
298 */
299 public String getString(int index) throws NoSuchElementException {
300 return get(index).toString();
301 }
302
303 /**
304 * Determine if the value is null.
305 *
306 * @param index
307 * The index must be between 0 and length() - 1.
308 * @return true if the value at the index is null, or if there is no value.
309 */
310 public boolean isNull(int index) {
311 Object o = opt(index);
312 return o == null || o.equals(null);
313 }
314
315 /**
316 * Make a string from the contents of this JSONArray. The separator string
317 * is inserted between each element. Warning: This method assumes that the
318 * data structure is acyclical.
319 *
320 * @param separator
321 * A string that will be inserted between the elements.
322 * @return a string.
323 */
324 public String join(String separator) {
325 StringBuffer sb = new StringBuffer();
326 for (int i = 0; i < myArrayList.size(); i += 1) {
327 if (i > 0) {
328 sb.append(separator);
329 }
330 sb.append(JSONObject.valueToString(myArrayList.get(i)));
331 }
332 return sb.toString();
333 }
334
335 /**
336 * Get the length of the JSONArray.
337 *
338 * @return The length (or size).
339 */
340 public int length() {
341 return myArrayList.size();
342 }
343
344 /**
345 * Get the optional object value associated with an index.
346 *
347 * @param index
348 * The index must be between 0 and length() - 1.
349 * @return An object value, or null if there is no object at that index.
350 */
351 public Object opt(int index) {
352 return index < 0 || index >= length() ? null : myArrayList.get(index);
353 }
354
355 /**
356 * Get the optional boolean value associated with an index. It returns false
357 * if there is no value at that index, or if the value is not Boolean.TRUE
358 * or the String "true".
359 *
360 * @param index
361 * The index must be between 0 and length() - 1.
362 * @return The truth.
363 */
364 public boolean optBoolean(int index) {
365 return optBoolean(index, false);
366 }
367
368 /**
369 * Get the optional boolean value associated with an index. It returns the
370 * defaultValue if there is no value at that index or if it is not a Boolean
371 * or the String "true" or "false" (case insensitive).
372 *
373 * @param index
374 * The index must be between 0 and length() - 1.
375 * @param defaultValue
376 * A boolean default.
377 * @return The truth.
378 */
379 public boolean optBoolean(int index, boolean defaultValue) {
380 Object o = opt(index);
381 if (o != null) {
382 if (o.equals(Boolean.FALSE)
383 || (o instanceof String && ((String) o)
384 .equalsIgnoreCase("false"))) {
385 return false;
386 } else if (o.equals(Boolean.TRUE)
387 || (o instanceof String && ((String) o)
388 .equalsIgnoreCase("true"))) {
389 return true;
390 }
391 }
392 return defaultValue;
393 }
394
395 /**
396 * Get the optional double value associated with an index. NaN is returned
397 * if the index is not found, or if the value is not a number and cannot be
398 * converted to a number.
399 *
400 * @param index
401 * The index must be between 0 and length() - 1.
402 * @return The value.
403 */
404 public double optDouble(int index) {
405 return optDouble(index, Double.NaN);
406 }
407
408 /**
409 * Get the optional double value associated with an index. The defaultValue
410 * is returned if the index is not found, or if the value is not a number
411 * and cannot be converted to a number.
412 *
413 * @param index
414 * subscript
415 * @param defaultValue
416 * The default value.
417 * @return The value.
418 */
419 public double optDouble(int index, double defaultValue) {
420 Object o = opt(index);
421 if (o != null) {
422 if (o instanceof Number) {
423 return ((Number) o).doubleValue();
424 }
425 try {
426 return new Double((String) o).doubleValue();
427 } catch (Exception e) {
428 }
429 }
430 return defaultValue;
431 }
432
433 /**
434 * Get the optional int value associated with an index. Zero is returned if
435 * the index is not found, or if the value is not a number and cannot be
436 * converted to a number.
437 *
438 * @param index
439 * The index must be between 0 and length() - 1.
440 * @return The value.
441 */
442 public int optInt(int index) {
443 return optInt(index, 0);
444 }
445
446 /**
447 * Get the optional int value associated with an index. The defaultValue is
448 * returned if the index is not found, or if the value is not a number and
449 * cannot be converted to a number.
450 *
451 * @param index
452 * The index must be between 0 and length() - 1.
453 * @param defaultValue
454 * The default value.
455 * @return The value.
456 */
457 public int optInt(int index, int defaultValue) {
458 Object o = opt(index);
459 if (o != null) {
460 if (o instanceof Number) {
461 return ((Number) o).intValue();
462 }
463 try {
464 return Integer.parseInt((String) o);
465 } catch (Exception e) {
466 }
467 }
468 return defaultValue;
469 }
470
471 /**
472 * Get the optional JSONArray associated with an index.
473 *
474 * @param index
475 * subscript
476 * @return A JSONArray value, or null if the index has no value, or if the
477 * value is not a JSONArray.
478 */
479 public JSONArray optJSONArray(int index) {
480 Object o = opt(index);
481 return o instanceof JSONArray ? (JSONArray) o : null;
482 }
483
484 /**
485 * Get the optional JSONObject associated with an index. Null is returned if
486 * the key is not found, or null if the index has no value, or if the value
487 * is not a JSONObject.
488 *
489 * @param index
490 * The index must be between 0 and length() - 1.
491 * @return A JSONObject value.
492 */
493 public JSONObject optJSONObject(int index) {
494 Object o = opt(index);
495 return o instanceof JSONObject ? (JSONObject) o : null;
496 }
497
498 /**
499 * Get the optional string value associated with an index. It returns an
500 * empty string if there is no value at that index. If the value is not a
501 * string and is not null, then it is coverted to a string.
502 *
503 * @param index
504 * The index must be between 0 and length() - 1.
505 * @return A String value.
506 */
507 public String optString(int index) {
508 return optString(index, "");
509 }
510
511 /**
512 * Get the optional string associated with an index. The defaultValue is
513 * returned if the key is not found.
514 *
515 * @param index
516 * The index must be between 0 and length() - 1.
517 * @param defaultValue
518 * The default value.
519 * @return A String value.
520 */
521 public String optString(int index, String defaultValue) {
522 Object o = opt(index);
523 return o != null ? o.toString() : defaultValue;
524 }
525
526 /**
527 * Append a boolean value.
528 *
529 * @param value
530 * A boolean value.
531 * @return this.
532 */
533 public JSONArray put(boolean value) {
534 put(Boolean.valueOf(value));
535 return this;
536 }
537
538 /**
539 * Append a double value.
540 *
541 * @param value
542 * A double value.
543 * @return this.
544 */
545 public JSONArray put(double value) {
546 put(new Double(value));
547 return this;
548 }
549
550 /**
551 * Append an int value.
552 *
553 * @param value
554 * An int value.
555 * @return this.
556 */
557 public JSONArray put(int value) {
558 put(new Integer(value));
559 return this;
560 }
561
562 /**
563 * Append an object value.
564 *
565 * @param value
566 * An object value. The value should be a Boolean, Double,
567 * Integer, JSONArray, JSObject, or String, or the
568 * JSONObject.NULL object.
569 * @return this.
570 */
571 @SuppressWarnings("unchecked")
572 public JSONArray put(Object value) {
573 myArrayList.add(value);
574 return this;
575 }
576
577 /**
578 * Put or replace a boolean value in the JSONArray.
579 *
580 * @exception NoSuchElementException
581 * The index must not be negative.
582 * @param index
583 * subscript The subscript. If the index is greater than the
584 * length of the JSONArray, then null elements will be added as
585 * necessary to pad it out.
586 * @param value
587 * A boolean value.
588 * @return this.
589 */
590 public JSONArray put(int index, boolean value) {
591 put(index, Boolean.valueOf(value));
592 return this;
593 }
594
595 /**
596 * Put or replace a double value.
597 *
598 * @exception NoSuchElementException
599 * The index must not be negative.
600 * @param index
601 * subscript The subscript. If the index is greater than the
602 * length of the JSONArray, then null elements will be added as
603 * necessary to pad it out.
604 * @param value
605 * A double value. return this.
606 */
607 public JSONArray put(int index, double value) {
608 put(index, new Double(value));
609 return this;
610 }
611
612 /**
613 * Put or replace an int value.
614 *
615 * @exception NoSuchElementException
616 * The index must not be negative.
617 * @param index
618 * subscript The subscript. If the index is greater than the
619 * length of the JSONArray, then null elements will be added as
620 * necessary to pad it out.
621 * @param value
622 * An int value.
623 * @return this.
624 */
625 public JSONArray put(int index, int value) {
626 put(index, new Integer(value));
627 return this;
628 }
629
630 /**
631 * Put or replace an object value in the JSONArray.
632 *
633 * @exception NoSuchElementException
634 * The index must not be negative.
635 * @param index
636 * The subscript. If the index is greater than the length of the
637 * JSONArray, then null elements will be added as necessary to
638 * pad it out.
639 * @param value
640 * An object value. return this.
641 */
642 @SuppressWarnings("unchecked")
643 public JSONArray put(int index, Object value)
644 throws NoSuchElementException, NullPointerException {
645 if (index < 0) {
646 throw new NoSuchElementException("JSONArray[" + index
647 + "] not found.");
648 } else if (value == null) {
649 throw new NullPointerException();
650 } else if (index < length()) {
651 myArrayList.set(index, value);
652 } else {
653 while (index != length()) {
654 put(null);
655 }
656 put(value);
657 }
658 return this;
659 }
660
661 /**
662 * Produce a JSONObject by combining a JSONArray of names with the values of
663 * this JSONArray.
664 *
665 * @param names
666 * A JSONArray containing a list of key strings. These will be
667 * paired with the values.
668 * @return A JSONObject, or null if there are no names or if this JSONArray
669 * has no values.
670 */
671 public JSONObject toJSONObject(JSONArray names) {
672 if (names == null || names.length() == 0 || length() == 0) {
673 return null;
674 }
675 JSONObject jo = new JSONObject();
676 for (int i = 0; i < names.length(); i += 1) {
677 jo.put(names.getString(i), this.opt(i));
678 }
679 return jo;
680 }
681
682 /**
683 * Make an JSON external form string of this JSONArray. For compactness, no
684 * unnecessary whitespace is added. Warning: This method assumes that the
685 * data structure is acyclical.
686 *
687 * @return a printable, displayable, transmittable representation of the
688 * array.
689 */
690 public String toString() {
691 return '[' + join(",") + ']';
692 }
693
694 /**
695 * Make a prettyprinted JSON string of this JSONArray. Warning: This method
696 * assumes that the data structure is non-cyclical.
697 *
698 * @param indentFactor
699 * The number of spaces to add to each level of indentation.
700 * @return a printable, displayable, transmittable representation of the
701 * object, beginning with <code>[</code> <small>(left
702 * bracket)</small> and ending with <code>]</code> <small>(right
703 * bracket)</small>.
704 */
705 public String toString(int indentFactor) {
706 return toString(indentFactor, 0);
707 }
708
709 /**
710 * Make a prettyprinted string of this JSONArray. Warning: This method
711 * assumes that the data structure is non-cyclical.
712 *
713 * @param indentFactor
714 * The number of spaces to add to each level of indentation.
715 * @param indent
716 * The indention of the top level.
717 * @return a printable, displayable, transmittable representation of the
718 * array.
719 */
720 String toString(int indentFactor, int indent) {
721 int len = length();
722 if (len == 0) {
723 return "[]";
724 }
725 int i;
726 StringBuffer sb = new StringBuffer("[");
727 if (len == 1) {
728 sb.append(JSONObject.valueToString(myArrayList.get(0),
729 indentFactor, indent));
730 } else {
731 int newindent = indent + indentFactor;
732 sb.append('\n');
733 for (i = 0; i < len; i += 1) {
734 if (i > 0) {
735 sb.append(",\n");
736 }
737 for (int j = 0; j < newindent; j += 1) {
738 sb.append(' ');
739 }
740 sb.append(JSONObject.valueToString(myArrayList.get(i),
741 indentFactor, newindent));
742 }
743 sb.append('\n');
744 for (i = 0; i < indent; i += 1) {
745 sb.append(' ');
746 }
747 }
748 sb.append(']');
749 return sb.toString();
750 }
751 }