using System; using System.Collections; using System.Text; namespace Nii.JSON { /// /// /// A JSONArray is an ordered sequence of values. Its external form is a string /// wrapped in square brackets with commas between the values. The internal form /// is an object having get() and opt() methods for accessing the values by /// index, and put() methods for adding or replacing values. The values can be /// any of these types: Boolean, JSONArray, JSONObject, Number, String, or the /// JSONObject.NULL object. /// /// /// The constructor can convert a JSON external form string into an /// internal form Java object. The toString() method creates an external /// form string. /// /// /// 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 typing /// checking and type coersion for you. /// /// /// The texts produced by the toString() methods are very strict. /// The constructors are more forgiving in the texts they will accept. /// /// /// /// An extra comma may appear just before the closing bracket. /// Strings may be quoted with single quotes. /// Strings do not need to be quoted at all if they do not contain leading /// or trailing spaces, and if they do not contain any of these characters: /// { } [ ] / \ : , /// Numbers may have the 0- (octal) or 0x- (hex) prefix. /// /// /// /// Public Domain 2002 JSON.org /// @author JSON.org /// @version 0.1 /// /// Ported to C# by Are Bjolseth, teleplan.no /// TODO: /// 1. Implement Custom exceptions /// 2. Add indexer JSONObject[i] = object, and object = JSONObject[i]; /// 3. Add indexer JSONObject["key"] = object, and object = JSONObject["key"] /// 4. Add unit testing /// 5. Add log4net /// 6. Make get/put methods private, to force use of indexer instead? /// public class JSONArray { /// The ArrayList where the JSONArray's properties are kept. private ArrayList myArrayList; #region JSONArray Constructors /// /// Construct an empty JSONArray /// public JSONArray() { myArrayList = new ArrayList(); } /// /// Construct a JSONArray from a JSONTokener. /// /// A JSONTokener public JSONArray(JSONTokener x) : this() { if (x.nextClean() != '[') { throw new Exception("A JSONArray must start with '['"); } if (x.nextClean() == ']') { return; } x.back(); while (true) { myArrayList.Add(x.nextObject()); switch (x.nextClean()) { case ',': if (x.nextClean() == ']') { return; } x.back(); break; case ']': return; default: throw new Exception("Expected a ',' or ']'"); } } } /// /// Construct a JSONArray from a source string. /// /// A string that begins with '[' and ends with ']'. public JSONArray(string s) : this(new JSONTokener(s)) { } /// /// Construct a JSONArray from a Collection. /// /// A Collection. public JSONArray(ICollection collection) { myArrayList = new ArrayList(collection); } #endregion #region C# extensions. Indexer and property /// /// Alternate to Java get/put method, by using indexer /// public object this[int i] { get { return opt(i); } set { //myArrayList[i] = value; put(i, value); } } /// /// Alternativ to Java, getArrayList, by using propery /// public IList List { get { return myArrayList; } } #endregion #region Getters for a value associated with an index. /// /// Get the object value associated with an index. /// Use indexer instead!!! Added to be true to the original Java implementation /// /// index subscript. The index must be between 0 and length()-1 /// An object value. public object getValue(int i) { object obj = opt(i); if (obj == null) { string msg = string.Format("JSONArray[{0}] not found", i); throw new Exception(msg); } return obj; //return myArrayList[i]; } /// /// Get the ArrayList which is holding the elements of the JSONArray. /// Use the indexer instead!! Added to be true to the orignal Java src /// /// The ArrayList public IList getArrayList() { return myArrayList; } /// /// Get the boolean value associated with an index. /// The string values "true" and "false" are converted to boolean. /// /// index subscript /// The truth public bool getBoolean(int i) { object obj = getValue(i); if (obj is bool) { return (bool)obj; } string msg = string.Format("JSONArray[{0}]={1} not a Boolean", i, obj); throw new Exception(msg); } /// /// Get the double value associated with an index. /// /// index subscript /// A double value public double getDouble(int i) { object obj = getValue(i); if (obj is double) return (double)obj; if (obj is float) return (double)obj; if (obj is string) { return Convert.ToDouble(obj); } string msg = string.Format("JSONArray[{0}]={1} not a double", i, obj); throw new Exception(msg); } /// /// Get the int value associated with an index. /// /// index subscript /// The int value public int getInt(int i) { object obj = getValue(i); if (obj is int) return (int)obj; if (obj is string) { return Convert.ToInt32(obj); } string msg = string.Format("JSONArray[{0}]={1} not a int", i, obj); throw new Exception(msg); } /// /// Get the JSONArray associated with an index. /// /// index subscript /// A JSONArray value public JSONArray getJSONArray(int i) { object obj = getValue(i); if (obj is JSONArray) { return (JSONArray)obj; } string msg = string.Format("JSONArray[{0}]={1} not a JSONArray", i, obj); throw new Exception(msg); } /// /// Get the JSONObject associated with an index. /// /// index subscript /// A JSONObject value public JSONObject getJSONObject(int i) { object obj = getValue(i); if (obj is JSONObject) { return (JSONObject)obj; } string msg = string.Format("JSONArray[{0}]={1} not a JSONObject", i, obj); throw new Exception(msg); } /// /// Get the string associated with an index. /// /// index subscript /// A string value. public string getString(int i) { object obj = getValue(i); if (obj is string) { return (string)obj; } string msg = string.Format("JSONArray[{0}]={1} not a string", i, obj); throw new Exception(msg); } #endregion /// /// Determine if the value is null. /// /// index subscript /// true if the value at the index is null, or if there is no value. public bool isNull(int i) { object obj = opt(i); return (obj == null || obj.Equals(null)); } /// /// Make a string from the contents of this JSONArray. The separator string /// is inserted between each element. /// Warning: This method assumes that the data structure is acyclical. /// /// separator A string that will be inserted between the elements. /// A string. public string join(string separator) { object obj; StringBuilder sb = new StringBuilder(); for (int i=0; i 0) { sb.Append(separator); } obj = myArrayList[i]; if (obj == null) { sb.Append(""); } else if (obj is string) { sb.Append(JSONUtils.Enquote((string)obj)); } else if (obj is int) { sb.Append(((int)obj).ToString()); } else { sb.Append(obj.ToString()); } } return sb.ToString(); } /// /// Get the length of the JSONArray. /// Added to be true to the original Java implementation /// /// Number of JSONObjects in array public int Length() { return myArrayList.Count; } /// /// Get the length of the JSONArray. /// Using a propery instead of method /// public int Count { get { return myArrayList.Count; } } #region Get the optional value associated with an index. /// /// Get the optional object value associated with an index. /// /// index subscript /// object at that index. public object opt(int i) { if (i < 0 || i >= myArrayList.Count) throw new ArgumentOutOfRangeException("int i", i, "Index out of bounds!"); return myArrayList[i]; } /// /// Get the optional boolean value associated with an index. /// /// index subscript /// The truth public bool optBoolean(int i) { return optBoolean(i,false); } /// /// Get the optional boolean value associated with an index. /// It returns the defaultValue if there is no value at that index or if it is not /// a Boolean or the String "true" or "false". /// /// index subscript /// /// The truth. public bool optBoolean(int i, bool defaultValue) { object obj = opt(i); if (obj != null) { return (bool)obj; } return defaultValue; } /// /// Get the optional double value associated with an index. /// NaN is returned if the index is not found, /// or if the value is not a number and cannot be converted to a number. /// /// index subscript /// The double value object public double optDouble(int i) { return optDouble(i,double.NaN); } /// /// Get the optional double value associated with an index. /// NaN is returned if the index is not found, /// or if the value is not a number and cannot be converted to a number. /// /// index subscript /// /// The double value object public double optDouble(int i, double defaultValue) { object obj = opt(i); if (obj != null) { if (obj is double) return (double)obj; if (obj is float) return (float)obj; if (obj is string) { return Convert.ToDouble(obj); } string msg = string.Format("JSONArray[{0}]={1} not a double", i, obj); throw new Exception(msg); } return defaultValue; } /// /// Get the optional int value associated with an index. /// Zero is returned if the index is not found, /// or if the value is not a number and cannot be converted to a number. /// /// index subscript /// The int value object public int optInt(int i) { return optInt(i,0); } /// /// Get the optional int value associated with an index. /// The defaultValue is returned if the index is not found, /// or if the value is not a number and cannot be converted to a number. /// /// index subscript /// The default value /// The int value object public int optInt(int i, int defaultValue) { object obj = opt(i); if (obj != null) { if (obj is int) return (int)obj; if (obj is string) return Convert.ToInt32(obj); string msg = string.Format("JSONArray[{0}]={1} not a int", i, obj); throw new Exception(msg); } return defaultValue; } /// /// Get the optional JSONArray associated with an index. /// /// index subscript /// A JSONArray value, or null if the index has no value, or if the value is not a JSONArray. public JSONArray optJSONArray(int i) { object obj = opt(i); if (obj is JSONArray) return (JSONArray)obj; return null; } /// /// Get the optional JSONObject associated with an index. /// Null is returned if the key is not found, or null if the index has /// no value, or if the value is not a JSONObject. /// /// index subscript /// A JSONObject value public JSONObject optJSONObject(int i) { object obj = opt(i); if (obj is JSONObject) { return (JSONObject)obj; } return null; } /// /// Get the optional string value associated with an index. It returns an /// empty string if there is no value at that index. If the value /// is not a string and is not null, then it is coverted to a string. /// /// index subscript /// A String value public string optString(int i) { return optString(i, ""); } /// /// Get the optional string associated with an index. /// The defaultValue is returned if the key is not found. /// /// index subscript /// The default value /// A string value public string optString(int i, string defaultValue) { object obj = opt(i); if (obj != null) { return obj.ToString(); } return defaultValue; } #endregion #region Put methods - use indexer instead /** * OMITTED: * public JSONArray put(bool val) * public JSONArray put(double val) * public JSONArray put(int val) */ /// /// Append an object value. /// /// An object value. The value should be a Boolean, Double, Integer, JSONArray, JSObject, or String, or the JSONObject.NULL object /// this (JSONArray) public JSONArray put(object val) { myArrayList.Add(val); return this; } /* * OMITTED: * public JSONArray put(int index, boolean value) * public JSONArray put(int index, double value) * public JSONArray put(int index, int value) */ /// /// Put or replace a boolean value in the JSONArray. /// /// /// The subscript. If the index is greater than the length of /// the JSONArray, then null elements will be added as necessary to pad it out. /// /// An object value. /// this (JSONArray) public JSONArray put(int i, object val) { if (i < 0) { throw new ArgumentOutOfRangeException("i", i, "Negative indexes illegal"); } else if (val == null) { throw new ArgumentNullException("val", "Object cannt be null"); } else if (i < myArrayList.Count) { myArrayList.Insert(i, val); } // NOTE! Since i is >= Count, fill null vals before index i, then append new object at i else { while (i != myArrayList.Count) { myArrayList.Add(null); } myArrayList.Add(val); } return this; } #endregion /// /// Produce a JSONObject by combining a JSONArray of names with the values /// of this JSONArray. /// /// /// A JSONArray containing a list of key strings. These will be paired with the values. /// /// A JSONObject, or null if there are no names or if this JSONArray public JSONObject toJSONObject(JSONArray names) { if (names == null || names.Length() == 0 || this.Length() == 0) { return null; } JSONObject jo = new JSONObject(); for (int i=0; i /// Make an JSON external form string of this JSONArray. For compactness, no /// unnecessary whitespace is added. /// /// a printable, displayable, transmittable representation of the array. public override string ToString() { return '['+ join(",") + ']'; } } }