View Javadoc
1   package org.json;
2   
3   /*
4    Copyright (c) 2002 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  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>&nbsp;<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>&nbsp;<small>(comma)</small>
57   * elision.</li>
58   * <li>Strings may be quoted with <code>'</code>&nbsp;<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>&nbsp;<small>(left
139 	 *            bracket)</small> and ends with <code>]</code>&nbsp;<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>&nbsp;<small>(left
702 	 *         bracket)</small> and ending with <code>]</code>&nbsp;<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 }