diff --git a/CDL.java b/CDL.java index 0fc3cf828..38b3407f4 100755 --- a/CDL.java +++ b/CDL.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/Cookie.java b/Cookie.java index 9cf5ce2c5..5556b395f 100755 --- a/Cookie.java +++ b/Cookie.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/CookieList.java b/CookieList.java index 7f4fe0751..a1232f4c8 100755 --- a/CookieList.java +++ b/CookieList.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/HTTP.java b/HTTP.java index 43d04a804..0ddfcb50e 100755 --- a/HTTP.java +++ b/HTTP.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/HTTPTokener.java b/HTTPTokener.java index ed41744a0..d99a6c668 100755 --- a/HTTPTokener.java +++ b/HTTPTokener.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/JSONArray.java b/JSONArray.java index 673a91927..d1d77c881 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/JSONException.java b/JSONException.java index 971547e63..aeaf7aec9 100755 --- a/JSONException.java +++ b/JSONException.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /** * The JSONException is thrown by the JSON.org classes when things are amiss. diff --git a/JSONML.java b/JSONML.java index 4be686351..aec7c291b 100755 --- a/JSONML.java +++ b/JSONML.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2008 JSON.org diff --git a/JSONObject.java b/JSONObject.java index 5ca5a45bc..92d4c20bc 100755 --- a/JSONObject.java +++ b/JSONObject.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org @@ -30,47 +30,49 @@ of this software and associated documentation files (the "Software"), to deal import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * A JSONObject is an unordered collection of name/value pairs. Its external * form is a string wrapped in curly braces with colons between the names and * values, and commas between the values and names. The internal form is an - * object having get and opt methods for accessing - * the values by name, and put methods for adding or replacing - * values by name. The values can be any of these types: Boolean, - * JSONArray, JSONObject, Number, - * String, or the JSONObject.NULL object. A - * JSONObject constructor can be used to convert an external form JSON text - * into an internal form whose values can be retrieved with the - * get and opt methods, or to convert values into a - * JSON text using the put and toString methods. A - * get method returns a value if one can be found, and throws an - * exception if one cannot be found. An opt method returns a - * default value instead of throwing an exception, and so is useful for - * obtaining optional values. + * object having get and opt methods for accessing the + * values by name, and put methods for adding or replacing values + * by name. The values can be any of these types: Boolean, + * JSONArray , JSONObject, Number, + * String, or the JSONObject.NULL object. A JSONObject + * constructor can be used to convert an external form JSON text into an + * internal form whose values can be retrieved with the get and + * opt methods, or to convert values into a JSON text using the + * put and toString methods. A get method + * returns a value if one can be found, and throws an exception if one cannot be + * found. An opt method returns a default value instead of throwing + * an exception, and so is useful for obtaining optional values. *

* The generic get() and opt() methods return an * object, which you can cast or query for type. There are also typed * get and opt methods that do type checking and type - * coercion for you. The opt methods differ from the get methods in that they - * do not throw. Instead, they return a specified value, such as null. + * coercion for you. The opt methods differ from the get methods in that they do + * not throw. Instead, they return a specified value, such as null. *

- * The put methods add or replace values in an object. For - * example, - * + * The put methods add or replace values in an object. For example, + * *

- * myString = new JSONObject()
- *         .put("JSON", "Hello, World!").toString();
+ * myString = new JSONObject().put("JSON", "Hello, World!").toString();
  * 
- * + * * produces the string {"JSON": "Hello, World"}. *

* The texts produced by the toString methods strictly conform to @@ -79,16 +81,16 @@ of this software and associated documentation files (the "Software"), to deal *

- * + * * @author JSON.org * @version 2013-06-17 */ @@ -101,9 +103,9 @@ public class JSONObject { private static final class Null { /** - * There is only intended to be a single instance of the NULL object, - * so the clone method returns itself. - * + * There is only intended to be a single instance of the NULL object, so + * the clone method returns itself. + * * @return NULL. */ protected final Object clone() { @@ -112,7 +114,7 @@ protected final Object clone() { /** * A Null object is equal to the null value and to itself. - * + * * @param object * An object to test for nullness. * @return true if the object parameter is the JSONObject.NULL object or @@ -124,7 +126,7 @@ public boolean equals(Object object) { /** * Get the "null" string value. - * + * * @return The string "null". */ public String toString() { @@ -156,7 +158,7 @@ public JSONObject() { * Construct a JSONObject from a subset of another JSONObject. An array of * strings is used to identify the keys that should be copied. Missing keys * are ignored. - * + * * @param jo * A JSONObject. * @param names @@ -178,7 +180,7 @@ public JSONObject(JSONObject jo, String[] names) { /** * Construct a JSONObject from a JSONTokener. - * + * * @param x * A JSONTokener object containing the source string. * @throws JSONException @@ -187,6 +189,15 @@ public JSONObject(JSONObject jo, String[] names) { */ public JSONObject(JSONTokener x) throws JSONException { this(); + parse(x); + setSearchByPathChars('.', '[', ']'); + } + + public void parse(String jsonString) { + parse(new JSONTokener(jsonString)); + } + + public void parse(JSONTokener x) { char c; String key; @@ -205,7 +216,7 @@ public JSONObject(JSONTokener x) throws JSONException { key = x.nextValue().toString(); } -// The key is followed by ':'. + // The key is followed by ':'. c = x.nextClean(); if (c != ':') { @@ -213,7 +224,7 @@ public JSONObject(JSONTokener x) throws JSONException { } this.putOnce(key, x.nextValue()); -// Pairs are separated by ','. + // Pairs are separated by ','. switch (x.nextClean()) { case ';': @@ -233,7 +244,7 @@ public JSONObject(JSONTokener x) throws JSONException { /** * Construct a JSONObject from a Map. - * + * * @param map * A map object that can be used to initialize the contents of * the JSONObject. @@ -260,16 +271,16 @@ public JSONObject(Map map) { * "is" followed by an uppercase letter, the method is invoked, * and a key and the value returned from the getter method are put into the * new JSONObject. - * + * * The key is formed by removing the "get" or "is" * prefix. If the second remaining character is not upper case, then the * first character is converted to lower case. - * + * * For example, if an object has a method named "getName", and * if the result of calling object.getName() is * "Larry Fine", then the JSONObject will contain * "name": "Larry Fine". - * + * * @param bean * An object that has getter methods that should be used to make * a JSONObject. @@ -285,7 +296,7 @@ public JSONObject(Object bean) { * the names array, and the values will be the field values associated with * those keys in the object. If a key is not found or not visible, then it * will not be copied into the new JSONObject. - * + * * @param object * An object that has fields that should be used to make a * JSONObject. @@ -308,9 +319,9 @@ public JSONObject(Object object, String names[]) { /** * Construct a JSONObject from a source JSON text string. This is the most * commonly used JSONObject constructor. - * + * * @param source - * A string beginning with { (left + * A string beginning with {  (left * brace) and ending with } *  (right brace). * @exception JSONException @@ -323,7 +334,7 @@ public JSONObject(String source) throws JSONException { /** * Construct a JSONObject from a ResourceBundle. - * + * * @param baseName * The ResourceBundle base name. * @param locale @@ -336,16 +347,20 @@ public JSONObject(String baseName, Locale locale) throws JSONException { ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, Thread.currentThread().getContextClassLoader()); -// Iterate through the keys in the bundle. + // Iterate through the keys in the bundle. Enumeration keys = bundle.getKeys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); if (key instanceof String) { -// Go through the path, ensuring that there is a nested JSONObject for each -// segment except the last. Add the value using the last segment's name into -// the deepest nested JSONObject. + // Go through the path, ensuring that there + // is a nested + // JSONObject for each + // segment except the last. Add the value + // using the last + // segment's name into + // the deepest nested JSONObject. String[] path = ((String) key).split("\\."); int last = path.length - 1; @@ -370,11 +385,11 @@ public JSONObject(String baseName, Locale locale) throws JSONException { * is stored under the key to hold all of the accumulated values. If there * is already a JSONArray, then the new value is appended to it. In * contrast, the put method replaces the previous value. - * + * * If only one value is accumulated that is not a JSONArray, then the result * will be the same as using put. But if multiple values are accumulated, * then the result will be like append. - * + * * @param key * A key string. * @param value @@ -403,7 +418,7 @@ public JSONObject accumulate(String key, Object value) throws JSONException { * JSONObject, then the key is put in the JSONObject with its value being a * JSONArray containing the value parameter. If the key was already * associated with a JSONArray, then the value parameter is appended to it. - * + * * @param key * A key string. * @param value @@ -430,7 +445,7 @@ public JSONObject append(String key, Object value) throws JSONException { /** * Produce a string from a double. The string "null" will be returned if the * number is not finite. - * + * * @param d * A double. * @return A String. @@ -440,7 +455,8 @@ public static String doubleToString(double d) { return "null"; } -// Shave off trailing zeros and decimal point, if possible. + // Shave off trailing zeros and decimal point, if + // possible. String string = Double.toString(d); if (string.indexOf('.') > 0 && string.indexOf('e') < 0 @@ -457,10 +473,69 @@ public static String doubleToString(double d) { /** * Get the value object associated with a key. - * + * * @param key - * A key string. - * @return The object associated with the key. + * A key string or a search path.

key

+ *

+ * When a key is used the associated object is directly returned. + *

search path

+ *

+ * When a search path is used, determined by dots or brackets in + * the key, a more thorough and traversal search is performed. + *

+ * Typical is that the first object that match is the one that is + * returned, regardless of if there are more available that also + * match. + *

+ * It is possible to search among objects by dot notation like + * this: jsonObject.get("parent.child.child"); + *

+ * In case of arrays this syntax can be used: + * jsonObject.get("parentArray[elementName==value].childArray[child.element!=value].child"); + *

+ * Consider that this JSON has been used: + *

+ * + *

+     *            {
+     *              parent: {
+     *                  child: {
+     *                      child: {
+     *                          element: "value"
+     *                      }
+     *                  }
+     *              },
+     *              parentArray: [
+     *                  {
+     *                      elementName: "value",
+     *                      childArray: [
+     *                          {
+     *                              child: {
+     *                                  element: "value"
+     *                              }
+     *                          }
+     *                      ]
+     *                  }
+     *              ]
+     *            }
+     * 
+ * + * These test operands can be used: + * + * @return The object associated with the key or search path. * @throws JSONException * if the key is not found. */ @@ -477,13 +552,15 @@ public Object get(String key) throws JSONException { /** * Get the boolean value associated with a key. - * + * * @param key - * A key string. + * A key string or search path. For explanation on search path + * see {@link JSONObject#get(String)}. * @return The truth. * @throws JSONException * if the value is not a Boolean or the String "true" or * "false". + * @see JSONObject#get(String) */ public boolean getBoolean(String key) throws JSONException { Object object = this.get(key); @@ -502,9 +579,10 @@ public boolean getBoolean(String key) throws JSONException { /** * Get the double value associated with a key. - * + * * @param key - * A key string. + * A key string or search path. For explanation on search path + * see {@link JSONObject#get(String)}. * @return The numeric value. * @throws JSONException * if the key is not found or if the value is not a Number @@ -523,9 +601,10 @@ public double getDouble(String key) throws JSONException { /** * Get the int value associated with a key. - * + * * @param key - * A key string. + * A key string or search path. For explanation on search path + * see {@link JSONObject#get(String)}. * @return The integer value. * @throws JSONException * if the key is not found or if the value cannot be converted @@ -544,9 +623,10 @@ public int getInt(String key) throws JSONException { /** * Get the JSONArray value associated with a key. - * + * * @param key - * A key string. + * A key string or search path. For explanation on search path + * see {@link JSONObject#get(String)}. * @return A JSONArray which is the value. * @throws JSONException * if the key is not found or if the value is not a JSONArray. @@ -562,9 +642,10 @@ public JSONArray getJSONArray(String key) throws JSONException { /** * Get the JSONObject value associated with a key. - * + * * @param key - * A key string. + * A key string or search path. For explanation on search path + * see {@link JSONObject#get(String)}. * @return A JSONObject which is the value. * @throws JSONException * if the key is not found or if the value is not a JSONObject. @@ -580,9 +661,10 @@ public JSONObject getJSONObject(String key) throws JSONException { /** * Get the long value associated with a key. - * + * * @param key - * A key string. + * A key string or search path. For explanation on search path + * see {@link JSONObject#get(String)}. * @return The long value. * @throws JSONException * if the key is not found or if the value cannot be converted @@ -601,7 +683,7 @@ public long getLong(String key) throws JSONException { /** * Get an array of field names from a JSONObject. - * + * * @return An array of field names, or null if there are no names. */ public static String[] getNames(JSONObject jo) { @@ -621,7 +703,7 @@ public static String[] getNames(JSONObject jo) { /** * Get an array of field names from an Object. - * + * * @return An array of field names, or null if there are no names. */ public static String[] getNames(Object object) { @@ -643,7 +725,7 @@ public static String[] getNames(Object object) { /** * Get the string associated with a key. - * + * * @param key * A key string. * @return A string which is the value. @@ -660,20 +742,29 @@ public String getString(String key) throws JSONException { /** * Determine if the JSONObject contains a specific key. - * + * * @param key * A key string. * @return true if the key exists in the JSONObject. */ public boolean has(String key) { - return this.map.containsKey(key); + if (key.indexOf(delimiter) != -1 || key.indexOf(leftBracket) != -1) { + try { + get(key); + return true; + } catch (JSONException e) { + return false; + } + } else { + return this.map.containsKey(key); + } } /** * Increment a property of a JSONObject. If there is no such property, * create one with a value of 1. If there is such a property, and if it is * an Integer, Long, Double, or Float, then add one to it. - * + * * @param key * A key string. * @return this. @@ -702,7 +793,7 @@ public JSONObject increment(String key) throws JSONException { /** * Determine if the value associated with the key is null or if there is no * value. - * + * * @param key * A key string. * @return true if there is no value associated with the key or if the value @@ -714,7 +805,7 @@ public boolean isNull(String key) { /** * Get an enumeration of the keys of the JSONObject. - * + * * @return An iterator of the keys. */ public Iterator keys() { @@ -723,7 +814,7 @@ public Iterator keys() { /** * Get a set of keys of the JSONObject. - * + * * @return A keySet. */ public Set keySet() { @@ -732,7 +823,7 @@ public Set keySet() { /** * Get the number of keys stored in the JSONObject. - * + * * @return The number of keys in the JSONObject. */ public int length() { @@ -742,7 +833,7 @@ public int length() { /** * Produce a JSONArray containing the names of the elements of this * JSONObject. - * + * * @return A JSONArray containing the key strings, or null if the JSONObject * is empty. */ @@ -757,7 +848,7 @@ public JSONArray names() { /** * Produce a string from a Number. - * + * * @param number * A Number * @return A String. @@ -770,7 +861,8 @@ public static String numberToString(Number number) throws JSONException { } testValidity(number); -// Shave off trailing zeros and decimal point, if possible. + // Shave off trailing zeros and decimal point, if + // possible. String string = number.toString(); if (string.indexOf('.') > 0 && string.indexOf('e') < 0 @@ -784,22 +876,303 @@ public static String numberToString(Number number) throws JSONException { } return string; } + + private char delimiter = (char) 0; + private char leftBracket = (char) 0; + private char rightBracket = (char) 0; + + public void setSearchByPathChars(char delimiter, char leftBracket, char rightBracket) { + this.delimiter = delimiter; + this.leftBracket = leftBracket; + this.rightBracket = rightBracket; + } /** * Get an optional value associated with a key. - * + * * @param key * A key string. * @return An object which is the value, or null if there is no value. */ public Object opt(String key) { - return key == null ? null : this.map.get(key); + return key == null ? null + : (key.indexOf(delimiter) != -1 || key.indexOf(leftBracket) != -1) ? optSearchByPath(key) + : this.map.get(key); + } + + private enum Comparator { + EQ("=="), NE("!="), LT("<"), GT(">"), LE("<="), GE(">="), PO("*="), NP( + "!*"), SW("^="), NS("!^"), TW("$="), NT("!$"); + + private final String comparatorString; + + private Comparator(String comparatorString) { + this.comparatorString = comparatorString; + } + + public String getComparatorString() { + return comparatorString; + } + + public static final Comparator getMatchingComparator( + String comparatorString) { + for (Comparator comparator : Comparator.values()) { + if (comparator.getComparatorString().equals(comparatorString)) { + return comparator; + } + } + return null; + } + } + + /** + * This is a advanced search by path method that is integrated in the normal + * search of JSONObject in the opt(key) method. This means that it works for + * any of the normal get methods like getString, getInt and so fourth. + *

+ * Typical is that the first object that match is the one that is returned, + * regardless of if there are more available that also match. + *

+ * It is possible to search by dot notation like this: + * jsonObject.getString("first.second.third.string"); + *

+ * In case of arrays this syntax can be used: + * jsonObject.getString("first[element==value].second[element.element!=value].string"); + *

+ * These test operands can be used: + *

+ * + * @param path + * The path to the value requested. + * @return The object that match the path or null if not found. + */ + private Object optSearchByPath(String path) { + List pathList = new ArrayList(Arrays.asList(path + .split("\\"+delimiter))); + String key = getBracesCompleteKey(pathList); + Object object = null; + if (key.matches(".+\\" + leftBracket + ".+\\" + rightBracket)) { + object = getObjectFromArray(key); + } else { + object = opt(key); + } + if (pathList.size() > 1) { + if ((object instanceof JSONArray)) { + // throw new JSONException("The element '" + key + + // "' is a JSONArray and must be addressed with []."); + object = getJSONArray(key).get(0); + } + pathList.remove(0); + if (object != null && object instanceof JSONObject) { + JSONObject jsonObject = (JSONObject) object; + jsonObject.setSearchByPathChars(delimiter, leftBracket, rightBracket); + String restPath = joinList(pathList, delimiter); + return jsonObject.optSearchByPath(restPath); + } + } + return object; + } + + private String getBracesCompleteKey(List pathList) { + String first = pathList.get(0); + while (countOccurrance(leftBracket, first) != countOccurrance(rightBracket, first)) { + pathList.remove(0); + first = first + delimiter + pathList.get(0); + pathList.set(0, first); + } + return first; + } + + private int countOccurrance(char match, String string) { + int result = 0; + int from = 0; + while ((from = string.indexOf(match, from)) != -1) { + from++; + result++; + } + return result; + } + + private Object getObjectFromArray(String arrayKey) { + Pattern numeric = Pattern.compile("(.+)\\" + leftBracket + "(\\d+)\\" + rightBracket); + Pattern field = Pattern + .compile("([^\\" + leftBracket + "]+)\\" + leftBracket + "([^\\^\\$*=<>!]+)(==|\\*=|!\\*|\\^=|!\\^|\\$=|!\\$|<|>|<=|<=|!=)([^=]+)\\" + rightBracket); + Matcher numericMatcher = numeric.matcher(arrayKey); + Matcher fieldMatcher = field.matcher(arrayKey); + if (numericMatcher.matches()) { + String key = numericMatcher.group(1); + int index = Integer.parseInt(numericMatcher.group(2)); + JSONArray array = optJSONArray(key); + return array!=null?array.get(index):null; + } else if (fieldMatcher.matches()) { + String key = fieldMatcher.group(1); + JSONArray array = getJSONArray(key); + for (int i = 0; i < array.length(); i++) { + JSONObject jsonObject = array.getJSONObject(i); + jsonObject.setSearchByPathChars(delimiter, leftBracket, rightBracket); + if (match( + jsonObject, + fieldMatcher.group(2), + Comparator.getMatchingComparator(fieldMatcher.group(3)), + fieldMatcher.group(4))) { + return jsonObject; + } + } + } + return null; + } + + private boolean match(JSONObject parent, String key, Comparator comparator, + String testString) { + Object object = parent.opt(key); + if (object == null || object == JSONObject.NULL) { + return testString == null ? true : "null" + .equalsIgnoreCase(testString); + } + String[] testArray = testString.split("\\|"); + boolean negativeComparator = comparator.getComparatorString().startsWith("!"); + for (int index=0; index tst; + case LT: + return val < tst; + case GE: + return val >= tst; + case LE: + return val <= tst; + default: + object = numberToString(val); + } + } + if (object instanceof Double) { + double val = ((Double) object).doubleValue(); + double tst = Double.parseDouble(testString); + switch (comparator) { + case EQ: + return val == tst; + case NE: + return val != tst; + case GT: + return val > tst; + case LT: + return val < tst; + case GE: + return val >= tst; + case LE: + return val <= tst; + default: + object = numberToString(val); + } + } + } + // compare as string + switch (comparator) { + case EQ: + return object.toString().equals(testString); + case NE: + return !object.toString().equals(testString); + case PO: + return object.toString().contains(testString); + case NP: + return !object.toString().contains(testString); + case SW: + return object.toString().startsWith(testString); + case NS: + return !object.toString().startsWith(testString); + case TW: + return object.toString().endsWith(testString); + case NT: + return !object.toString().endsWith(testString); + case GT: + return object.toString().compareToIgnoreCase(testString) > 0; + case LT: + return object.toString().compareToIgnoreCase(testString) < 0; + case GE: + return object.toString().compareToIgnoreCase(testString) >= 0; + case LE: + return object.toString().compareToIgnoreCase(testString) <= 0; + default: + throw new JSONException("The comparatorString '" + comparator + + "' is unknown."); + } + } + + /** + * This helper method joins each element in the String list with the + * separator between. + * + * @param list + * The list of strings + * @param separator + * The separator + * @return The concatenated string. + */ + private String joinList(List list, char separator) { + StringBuffer result = new StringBuffer(); + for (int index = 0; index < list.size(); index++) { + if (index > 0) { + result.append(separator); + } + result.append(list.get(index)); + } + return result.toString(); } /** * Get an optional boolean associated with a key. It returns false if there * is no such key, or if the value is not Boolean.TRUE or the String "true". - * + * * @param key * A key string. * @return The truth. @@ -812,7 +1185,7 @@ public boolean optBoolean(String key) { * Get an optional boolean associated with a key. It returns the * defaultValue if there is no such key, or if it is not a Boolean or the * String "true" or "false" (case insensitive). - * + * * @param key * A key string. * @param defaultValue @@ -831,7 +1204,7 @@ public boolean optBoolean(String key, boolean defaultValue) { * Get an optional double associated with a key, or NaN if there is no such * key or if its value is not a number. If the value is a string, an attempt * will be made to evaluate it as a number. - * + * * @param key * A string which is the key. * @return An object which is the value. @@ -844,7 +1217,7 @@ public double optDouble(String key) { * Get an optional double associated with a key, or the defaultValue if * there is no such key or if its value is not a number. If the value is a * string, an attempt will be made to evaluate it as a number. - * + * * @param key * A key string. * @param defaultValue @@ -863,7 +1236,7 @@ public double optDouble(String key, double defaultValue) { * Get an optional int value associated with a key, or zero if there is no * such key or if the value is not a number. If the value is a string, an * attempt will be made to evaluate it as a number. - * + * * @param key * A key string. * @return An object which is the value. @@ -876,7 +1249,7 @@ public int optInt(String key) { * Get an optional int value associated with a key, or the default if there * is no such key or if the value is not a number. If the value is a string, * an attempt will be made to evaluate it as a number. - * + * * @param key * A key string. * @param defaultValue @@ -894,7 +1267,7 @@ public int optInt(String key, int defaultValue) { /** * Get an optional JSONArray associated with a key. It returns null if there * is no such key, or if its value is not a JSONArray. - * + * * @param key * A key string. * @return A JSONArray which is the value. @@ -907,7 +1280,7 @@ public JSONArray optJSONArray(String key) { /** * Get an optional JSONObject associated with a key. It returns null if * there is no such key, or if its value is not a JSONObject. - * + * * @param key * A key string. * @return A JSONObject which is the value. @@ -921,7 +1294,7 @@ public JSONObject optJSONObject(String key) { * Get an optional long value associated with a key, or zero if there is no * such key or if the value is not a number. If the value is a string, an * attempt will be made to evaluate it as a number. - * + * * @param key * A key string. * @return An object which is the value. @@ -934,7 +1307,7 @@ public long optLong(String key) { * Get an optional long value associated with a key, or the default if there * is no such key or if the value is not a number. If the value is a string, * an attempt will be made to evaluate it as a number. - * + * * @param key * A key string. * @param defaultValue @@ -953,7 +1326,7 @@ public long optLong(String key, long defaultValue) { * Get an optional string associated with a key. It returns an empty string * if there is no such key. If the value is not a string and is not null, * then it is converted to a string. - * + * * @param key * A key string. * @return A string which is the value. @@ -965,7 +1338,7 @@ public String optString(String key) { /** * Get an optional string associated with a key. It returns the defaultValue * if there is no such key. - * + * * @param key * A key string. * @param defaultValue @@ -980,7 +1353,8 @@ public String optString(String key, String defaultValue) { private void populateMap(Object bean) { Class klass = bean.getClass(); -// If klass is a System class then set includeSuperClass to false. + // If klass is a System class then set + // includeSuperClass to false. boolean includeSuperClass = klass.getClassLoader() != null; @@ -1025,7 +1399,7 @@ private void populateMap(Object bean) { /** * Put a key/boolean pair in the JSONObject. - * + * * @param key * A key string. * @param value @@ -1042,7 +1416,7 @@ public JSONObject put(String key, boolean value) throws JSONException { /** * Put a key/value pair in the JSONObject, where the value will be a * JSONArray which is produced from a Collection. - * + * * @param key * A key string. * @param value @@ -1057,7 +1431,7 @@ public JSONObject put(String key, Collection value) throws JSONException { /** * Put a key/double pair in the JSONObject. - * + * * @param key * A key string. * @param value @@ -1073,7 +1447,7 @@ public JSONObject put(String key, double value) throws JSONException { /** * Put a key/int pair in the JSONObject. - * + * * @param key * A key string. * @param value @@ -1089,7 +1463,7 @@ public JSONObject put(String key, int value) throws JSONException { /** * Put a key/long pair in the JSONObject. - * + * * @param key * A key string. * @param value @@ -1106,7 +1480,7 @@ public JSONObject put(String key, long value) throws JSONException { /** * Put a key/value pair in the JSONObject, where the value will be a * JSONObject which is produced from a Map. - * + * * @param key * A key string. * @param value @@ -1122,7 +1496,7 @@ public JSONObject put(String key, Map value) throws JSONException { /** * Put a key/value pair in the JSONObject. If the value is null, then the * key will be removed from the JSONObject if it is present. - * + * * @param key * A key string. * @param value @@ -1150,7 +1524,7 @@ public JSONObject put(String key, Object value) throws JSONException { * Put a key/value pair in the JSONObject, but only if the key and the value * are both non-null, and only if there is not already a member with that * name. - * + * * @param key * @param value * @return his. @@ -1170,7 +1544,7 @@ public JSONObject putOnce(String key, Object value) throws JSONException { /** * Put a key/value pair in the JSONObject, but only if the key and the value * are both non-null. - * + * * @param key * A key string. * @param value @@ -1193,7 +1567,7 @@ public JSONObject putOpt(String key, Object value) throws JSONException { * right places. A backslash will be inserted within * Warning: This method assumes that the data structure is acyclical. - * + * * @return a printable, displayable, portable, transmittable representation - * of the object, beginning with { (left + * of the object, beginning with {  (left * brace) and ending with } (right * brace). */ @@ -1404,11 +1779,11 @@ public String toString() { * Make a prettyprinted JSON text of this JSONObject. *

* Warning: This method assumes that the data structure is acyclical. - * + * * @param indentFactor * The number of spaces to add to each level of indentation. * @return a printable, displayable, portable, transmittable representation - * of the object, beginning with { (left + * of the object, beginning with {  (left * brace) and ending with } (right * brace). * @throws JSONException @@ -1432,15 +1807,15 @@ public String toString(int indentFactor) throws JSONException { * JSONObject will be made from it and its toJSONString method will be * called. Otherwise, the value's toString method will be called, and the * result will be quoted. - * + * *

* Warning: This method assumes that the data structure is acyclical. - * + * * @param value * The value to be serialized. * @return a printable, displayable, transmittable representation of the - * object, beginning with { (left - * brace) and ending with } (right + * object, beginning with {  (left + * brace) and ending with }  (right * brace). * @throws JSONException * If the value is or contains an invalid number. @@ -1487,7 +1862,7 @@ public static String valueToString(Object value) throws JSONException { * String, et al) then it is already wrapped. Otherwise, if it comes from * one of the java packages, turn it into a string. And if it doesn't, try * to wrap it in a JSONObject. If the wrapping fails, then null is returned. - * + * * @param object * The object to wrap * @return The wrapped value @@ -1535,7 +1910,7 @@ public static Object wrap(Object object) { * compactness, no whitespace is added. *

* Warning: This method assumes that the data structure is acyclical. - * + * * @return The writer. * @throws JSONException */ @@ -1587,7 +1962,7 @@ static final void indent(Writer writer, int indent) throws IOException { * compactness, no whitespace is added. *

* Warning: This method assumes that the data structure is acyclical. - * + * * @return The writer. * @throws JSONException */ diff --git a/JSONString.java b/JSONString.java index 1f2d77dd1..8f734db9e 100755 --- a/JSONString.java +++ b/JSONString.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /** * The JSONString interface allows a toJSONString() * method so that a class can change the behavior of diff --git a/JSONStringer.java b/JSONStringer.java index 25c2e5d78..0fd002095 100755 --- a/JSONStringer.java +++ b/JSONStringer.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2006 JSON.org diff --git a/JSONTokener.java b/JSONTokener.java index 13c84f1f5..96255c60b 100644 --- a/JSONTokener.java +++ b/JSONTokener.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; import java.io.BufferedReader; import java.io.IOException; diff --git a/JSONWriter.java b/JSONWriter.java index 855b2bdb1..abb8b7ec2 100755 --- a/JSONWriter.java +++ b/JSONWriter.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; import java.io.IOException; import java.io.Writer; diff --git a/Kim.java b/Kim.java index d4770b566..0f249296e 100644 --- a/Kim.java +++ b/Kim.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* diff --git a/Property.java b/Property.java index dbbd7ef7e..342fde4ee 100644 --- a/Property.java +++ b/Property.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/README b/README deleted file mode 100755 index b77c71a21..000000000 --- a/README +++ /dev/null @@ -1,68 +0,0 @@ -JSON in Java [package org.json] - -Douglas Crockford -douglas@crockford.com - -2011-02-02 - - -JSON is a light-weight, language independent, data interchange format. -See http://www.JSON.org/ - -The files in this package implement JSON encoders/decoders in Java. -It also includes the capability to convert between JSON and XML, HTTP -headers, Cookies, and CDL. - -This is a reference implementation. There is a large number of JSON packages -in Java. Perhaps someday the Java community will standardize on one. Until -then, choose carefully. - -The license includes this restriction: "The software shall be used for good, -not evil." If your conscience cannot live with that, then choose a different -package. - -The package compiles on Java 1.2 thru Java 1.4. - - -JSONObject.java: The JSONObject can parse text from a String or a JSONTokener -to produce a map-like object. The object provides methods for manipulating its -contents, and for producing a JSON compliant object serialization. - -JSONArray.java: The JSONObject can parse text from a String or a JSONTokener -to produce a vector-like object. The object provides methods for manipulating -its contents, and for producing a JSON compliant array serialization. - -JSONTokener.java: The JSONTokener breaks a text into a sequence of individual -tokens. It can be constructed from a String, Reader, or InputStream. - -JSONException.java: The JSONException is the standard exception type thrown -by this package. - - -JSONString.java: The JSONString interface requires a toJSONString method, -allowing an object to provide its own serialization. - -JSONStringer.java: The JSONStringer provides a convenient facility for -building JSON strings. - -JSONWriter.java: The JSONWriter provides a convenient facility for building -JSON text through a writer. - - -CDL.java: CDL provides support for converting between JSON and comma -delimited lists. - -Cookie.java: Cookie provides support for converting between JSON and cookies. - -CookieList.java: CookieList provides support for converting between JSON and -cookie lists. - -HTTP.java: HTTP provides support for converting between JSON and HTTP headers. - -HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers. - -XML.java: XML provides support for converting between JSON and XML. - -JSONML.java: JSONML provides support for converting between JSONML and XML. - -XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text. diff --git a/README.md b/README.md new file mode 100755 index 000000000..8b8d081e1 --- /dev/null +++ b/README.md @@ -0,0 +1,200 @@ +# JSON Java fork + +This is a fork of the original JSON Java implementation made by Douglas Crockford. + +## Enhancements + +With this fork it is possible to find an object or type using a path to the type instead of just a key. +This gives means to find a single string from a complex JSON structure in just one line. +The nodes are separated with a (dot) and array index surrounded by square braces. +The array selection can even be an expression giving the possibility to find a particular object and +a type within. + +## Example + +For all examples below this is the JSON we are using and it is parsed into a JSONObject called jsonObject: + + { + "array": [ + { + "id": 12, + "address": { + "zip": 12345 + }, + "name": "value1" + }, + { + "id": 2, + "name": "value2" + }, + { + "id": 1, + "address": { + "zip": 45678 + }, + "name": "value3" + } + ] + } + +#### Find the name of the first object in the array + + String name = jsonObject.getString("array[0].name"); + +_Name contains "value1" after the statement has been run._ + +#### Find the id of the third object + + int id = jsonObject.getInt("array[2].id"); + +_The variable id contains 1 after this statement._ + +#### Find the name of the first object which address zip code is larger than 20000 + + String name = jsonObject.getString("array[address.zip>20000].name"); + +_Name contains "value3" after the statement has been run._ + +#### Find the name of the first found object that has a zip code not equal to 12345 + + String name = jsonObject.getString("array[address.zip!=12345].name"); + +_Name contains "value3" after the statement has been run._ + +#### Find the name of the object in the array which id equals 2 + + String name = jsonObject.getString("array[id==2].name"); + + + +## Possible operands to use in array object selections + +In case of arrays this syntax can be used: + +`jsonObject.getString("first[element**operand**value].second[element.element**operand**value].string");` + +These test operands can be used: + + == : Equality test + != : Not equal test + < : Less than test + > : Greater than test + <= : Less than or equal test + >= : Greater than or equal test + *= : Contains text test + !* : Not contains text test + ^= : Starts with text test + !^ : Not starts with text test + $= : Ends with text test + !$ : Not ends with text test + +The value used after the operand can have the pipe (|) character to separate several alternatives. +Maybe this doesn't make sense with the comparators <, >, <=, >=, ^= and $= but for the others +it's a quite neat feature. + +#### Find the id of the object that doesn't have the name value1 or value3 + + int id = jsonObject.getInt("array[name!=value1|value3].id"); + +_The variable id contains 2 after this statement._ + +#### Find the name of the object that doesn't have the id 1 or 2 + + String name = jsonObject.getString("array[id!=1|2].name"); + +_The variable name contains value1 after this statement._ + + +## What if the JSON keys contains dot or brackets + +Some times you could come across JSON data which has keys that contains a dot or brackets. +You can solve that by using the new setter for the path search specific characters: + + jsonObject.setSearchByPathChars('/', '{', '}'); + String name = jsonObject.getString("array{id!=1|2}/name"); + +_The characters can be changed to any valid chars_ + +#### This is for instance a valid case +The only important thing to know is that the characters you choose does not exist in any key and that they has to be different from each other. + + jsonObject.setSearchByPathChars('§', '`', '\''); + String value = jsonObject.getString("array.json`0'§crazy{}/key"); + + + + + + + + +# Original Douglas Crockford README + + JSON in Java [package org.json] + + Douglas Crockford + douglas@crockford.com + + 2011-02-02 + + + JSON is a light-weight, language independent, data interchange format. + See http://www.JSON.org/ + + The files in this package implement JSON encoders/decoders in Java. + It also includes the capability to convert between JSON and XML, HTTP + headers, Cookies, and CDL. + + This is a reference implementation. There is a large number of JSON packages + in Java. Perhaps someday the Java community will standardize on one. Until + then, choose carefully. + + The license includes this restriction: "The software shall be used for good, + not evil." If your conscience cannot live with that, then choose a different + package. + + The package compiles on Java 1.2 thru Java 1.4. + + + JSONObject.java: The JSONObject can parse text from a String or a JSONTokener + to produce a map-like object. The object provides methods for manipulating its + contents, and for producing a JSON compliant object serialization. + + JSONArray.java: The JSONObject can parse text from a String or a JSONTokener + to produce a vector-like object. The object provides methods for manipulating + its contents, and for producing a JSON compliant array serialization. + + JSONTokener.java: The JSONTokener breaks a text into a sequence of individual + tokens. It can be constructed from a String, Reader, or InputStream. + + JSONException.java: The JSONException is the standard exception type thrown + by this package. + + + JSONString.java: The JSONString interface requires a toJSONString method, + allowing an object to provide its own serialization. + + JSONStringer.java: The JSONStringer provides a convenient facility for + building JSON strings. + + JSONWriter.java: The JSONWriter provides a convenient facility for building + JSON text through a writer. + + + CDL.java: CDL provides support for converting between JSON and comma + delimited lists. + + Cookie.java: Cookie provides support for converting between JSON and cookies. + + CookieList.java: CookieList provides support for converting between JSON and + cookie lists. + + HTTP.java: HTTP provides support for converting between JSON and HTTP headers. + + HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers. + + XML.java: XML provides support for converting between JSON and XML. + + JSONML.java: JSONML provides support for converting between JSONML and XML. + + XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text. diff --git a/XML.java b/XML.java index d49784d6d..ace77e5db 100755 --- a/XML.java +++ b/XML.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/XMLTokener.java b/XMLTokener.java index be15ebeba..33e3dba06 100755 --- a/XMLTokener.java +++ b/XMLTokener.java @@ -1,4 +1,4 @@ -package org.json; +package org.jsonfork; /* Copyright (c) 2002 JSON.org diff --git a/zip/BitInputStream.java b/zip/BitInputStream.java index 7864ce150..39d8fd570 100644 --- a/zip/BitInputStream.java +++ b/zip/BitInputStream.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; import java.io.IOException; import java.io.InputStream; diff --git a/zip/BitOutputStream.java b/zip/BitOutputStream.java index 526ad6111..92f08ee2e 100644 --- a/zip/BitOutputStream.java +++ b/zip/BitOutputStream.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; import java.io.IOException; import java.io.OutputStream; diff --git a/zip/BitReader.java b/zip/BitReader.java index 1987729b8..403241843 100644 --- a/zip/BitReader.java +++ b/zip/BitReader.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; import java.io.IOException; diff --git a/zip/BitWriter.java b/zip/BitWriter.java index 83eb7e314..f8ad5aa31 100644 --- a/zip/BitWriter.java +++ b/zip/BitWriter.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; import java.io.IOException; diff --git a/zip/Compressor.java b/zip/Compressor.java index 6dddff420..8c53be4ef 100644 --- a/zip/Compressor.java +++ b/zip/Compressor.java @@ -1,14 +1,14 @@ -package org.json.zip; +package org.jsonfork.zip; import java.io.IOException; import java.util.Collection; import java.util.Iterator; import java.util.Map; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.Kim; +import org.jsonfork.JSONArray; +import org.jsonfork.JSONException; +import org.jsonfork.JSONObject; +import org.jsonfork.Kim; /* Copyright (c) 2013 JSON.org diff --git a/zip/Decompressor.java b/zip/Decompressor.java index 108a2e2c1..1bde59910 100644 --- a/zip/Decompressor.java +++ b/zip/Decompressor.java @@ -1,11 +1,11 @@ -package org.json.zip; +package org.jsonfork.zip; import java.io.UnsupportedEncodingException; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.Kim; +import org.jsonfork.JSONArray; +import org.jsonfork.JSONException; +import org.jsonfork.JSONObject; +import org.jsonfork.Kim; /* Copyright (c) 2012 JSON.org diff --git a/zip/Huff.java b/zip/Huff.java index 2e1d1c925..afcc203af 100644 --- a/zip/Huff.java +++ b/zip/Huff.java @@ -1,6 +1,6 @@ -package org.json.zip; +package org.jsonfork.zip; -import org.json.JSONException; +import org.jsonfork.JSONException; /* Copyright (c) 2013 JSON.org diff --git a/zip/JSONzip.java b/zip/JSONzip.java index 2128742c2..fc30ddfec 100644 --- a/zip/JSONzip.java +++ b/zip/JSONzip.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; /* diff --git a/zip/Keep.java b/zip/Keep.java index 377e344e2..8d1804551 100644 --- a/zip/Keep.java +++ b/zip/Keep.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; /* diff --git a/zip/MapKeep.java b/zip/MapKeep.java index 1374e08d3..7e5d163a1 100644 --- a/zip/MapKeep.java +++ b/zip/MapKeep.java @@ -1,8 +1,8 @@ -package org.json.zip; +package org.jsonfork.zip; import java.util.HashMap; -import org.json.Kim; +import org.jsonfork.Kim; /* Copyright (c) 2013 JSON.org diff --git a/zip/None.java b/zip/None.java index 818e68d8f..73d4c8b09 100644 --- a/zip/None.java +++ b/zip/None.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; /** * None is an interface that makes the constant none (short for diff --git a/zip/PostMortem.java b/zip/PostMortem.java index 22416d700..2fb7b0900 100644 --- a/zip/PostMortem.java +++ b/zip/PostMortem.java @@ -1,4 +1,4 @@ -package org.json.zip; +package org.jsonfork.zip; /* Copyright (c) 2013 JSON.org diff --git a/zip/TrieKeep.java b/zip/TrieKeep.java index dcb13c7a0..175021a57 100644 --- a/zip/TrieKeep.java +++ b/zip/TrieKeep.java @@ -1,6 +1,6 @@ -package org.json.zip; +package org.jsonfork.zip; -import org.json.Kim; +import org.jsonfork.Kim; /* Copyright (c) 2013 JSON.org