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