JSONUtils

From Unify Community Wiki
Revision as of 14:07, 6 March 2012 by Messu (Talk | contribs)

Jump to: navigation, search

Contents

JSONUtils.js

This page is more or less the same as the one of JSONParse.

What is it?

It's a JSON parser written in UnityScript ("UnityJS"). I found JSONParse which was really good but I was expecting some other features. JSONUtils is a JSON parser which allow some other things like serialize to JSON for some data types like Hashtable, Array, numbers, booleans and strings.

What is different from JSONParse ?

The first and more important thing : this script parse JSON "object" into Hashtable, not Object. Some functions let you serialize your data into JSON if it contains only following data types : Array, Object, Hashtable, number (int, float, double), boolean or String.

How to use JSONUtils ?

Parse JSON

  • Put the script in the Plugins folder.
  • Call JSONUtils.ParseJSON( JSONText ) to get an Hashtable according your JSON.

Serialized to JSON

Call JSONUtils.ObjectToJSON(object) of JSONUtils.HashtableToJSON(hashtable) to get a string from your object/hashtable.

Who do I contact for help / questions?

Feel free to email me if you upgrade/clean/adapt this code.

Indiana MAGNIEZ

The code

The plugin script

/*
 
JSONUtils.js
A JSON Parser for the Unity Game Engine
 
Based on JSONParse.js by Philip Peterson (which is based on json_parse by Douglas Crockford)
 
Modified by Indiana MAGNIEZ
 
*/
 
class JSONUtils
{
	private static var at : int;
 
	private static var ch : String;
 
	private static var escapee = {
	            "\"": "\"",
	            "\\": "\\",
	            "/": "/",
	            "b": "b",
	            "f": "\f",
	            "n": "\n",
	            "r": "\r",
	            "t": "\t"
	            };
 
	private static var text : String;
 
	private static function error (m) : void
	{
	    throw new System.Exception("SyntaxError: \nMessage: "+m+
	                        "\nAt: "+at+
	                        "\nText: "+text);
	}
 
	private static function next (c) : String
	{
	    if(c && c != ch) {
	        error("Expected '" + c + "' instead of '" + ch + "'");
	    }
 
 
	    if(text.length >= at+1) {
	        ch = text.Substring(at, 1);
	    }
	    else {
	        ch = "";
	    }
 
	    at++;
	    return ch;
	}
 
	private static function next () : String
	{
	    return next(null);
	}
 
	private static function number () : Number
	{
	    var number;
	    var string = "";
 
	    if(ch == "-")
	    {
	        string = "-";
	        next("-");
	    }
	    while(ch in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
	    {
	        string += ch;
	        next();
	    }
	    if(ch == ".")
	    {
	        string += ".";
	        while(next() && ch in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
	        {
	            string += ch;
	        }
	    }
	    if(ch == "e" || ch == "E")
	    {
	        string += ch;
	        next();
	        if(ch == "-" || ch == "+")
	        {
	            string += ch;
	            next();
	        }
	        while(ch in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
	        {
	            string += ch;
	            next();
	        }
	    }
	    number = Number.Parse(string);
 
	    if( System.Double.IsNaN(number) )
	    {
	        error("Bad number");
	    }
	    else
	    {
	        return number;
	    }
	}
 
 
	private static function string () : System.String
	{
	    var hex : int;
	    var i : int;
	    var string : String = "";
	    var uffff : int;
 
	    if(ch == "\"")
	    {
	        while( next() )
	        {
	            if(ch == "\"")
	            {
	                next();
	                return string;
	            }
	            else if (ch == "\\")
	            {
	                next();
	                if(ch == "u")
	                {
	                    uffff = 0;
	                    for(i = 0; i < 4; i++)
	                    {
	                        hex = System.Convert.ToInt32(next(), 16);
	                        if (hex == Mathf.Infinity || hex == Mathf.NegativeInfinity)
	                        {
	                            break;
	                        }
	                        uffff = uffff * 16 + hex;
	                    }
	                    var m : char = uffff;
	                    string += m;
	                }
	                else if(ch in escapee)
	                {
	                    string += escapee[ch];
	                }
	                else
	                {
	                    break;
	                }
	            }
	            else
	            {
	                string += ch;
	            }
	        }
	    }
	    error("Bad string");
	}
 
 
 
	private static function white () : void
	{
	    while(ch && (ch.length >= 1 && ch.Chars[0] <= 32)) { // if it's whitespace
	        next();
	    }   
	}
 
	private static function value () : System.Object
	{
	    white();
	    // Again, we have to pass on the switch() statement.
 
	    if(ch == "{") {
//	        return object();
	        return hashtable();
	    } else if(ch == "[") {
	        return array();
	    } else if(ch == "\"") {
	        return string();
	    } else if(ch == "-") {
	        return number();
	    } else {
	        return (ch in ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]) ? number() : word();
	    }
 
	}
 
	private static function word ()
	{
	    // We don't use a switch() statement because
	    // otherwise Unity will complain about
	    // unreachable code (in reality it's not unreachable).
 
	    if(ch == "t") {
	        next("t");
	        next("r");
	        next("u");
	        next("e");
	        return true;
	    } else if (ch == "f") {
	        next("f");
	        next("a");
	        next("l");
	        next("s");
	        next("e");
	        return false;
	    } if(ch == "T") {
	        next("T");
	        next("r");
	        next("u");
	        next("e");
	        return true;
	    } else if (ch == "F") {
	        next("F");
	        next("a");
	        next("l");
	        next("s");
	        next("e");
	        return false;
	    } else if (ch == "n") {
	        next("n");
	        next("u");
	        next("l");
	        next("l");
	        return null;
	    } else if (ch == "N") {
	        next("N");
	        next("u");
	        next("l");
	        next("l");
	        return null;
	    } else if (ch == "") { 
	        return null; // Todo: why is it doing this?
	    }
 
	    error("Unexpected '" + ch + "'");
	}
 
	private static function array () : Array
	{
	    var array : Array = new Array();
 
	    if(ch == "[")
	    {
	        next("[");
	        white();
	        if(ch == "]")
	        {
	            next("]");
	            return array; // empty array
	        }
	        while(ch)
	        {
	            array.Push(value());
	            white();
	            if(ch == "]")
	            {
	                next("]");
	                return array;
	            }
	            next(",");
	            white();
	        }
	    }
	    error("Bad array");
	}
 
//	private static function object () : Object
//	{
//	    var key;
//	    var object = {};
//	    
//	    if(ch == "{")
//	    {
//	        next("{");
//	        white();
//	        if(ch == "}")
//	        {
//	            next("}");
//	            return object; // empty object
//	        }
//	        while(ch)
//	        {
//	            key = string();
//	            white();
//	            next(":");
//	            object[key] = value();
//	            white();
//	            if (ch == "}")
//	            {
//	                next("}");
//	                return object;
//	            }
//	            next(",");
//	            white();
//	        }
//	    }
//	    error("Bad object");
//	}
 
	private static function hashtable () : Hashtable
	{
	    white();
 
	    var key : String;
	    var object = new Hashtable();
 
	    if(ch == "{")
	    {
	        next("{");
	        white();
	        if(ch == "}")
	        {
	            next("}");
	            return object; // empty object
	        }
	        while(ch)
	        {
	            key = string();
	            white();
	            next(":");
	            object.Add( key, value() );
	            white();
	            if (ch == "}")
	            {
	                next("}");
	                return object;
	            }
	            next(",");
	            white();
	        }
	    }
	    error("Bad hashtable");
	}
 
 
 
	public static function ParseJSON ( source:String ):Hashtable
	{
	    var result:Hashtable;
 
	    text = source;
	    at = 0;
	    ch = " ";
	    result = hashtable();
	    white();
	    if (ch)
	    {
	        error("Syntax error");
	    }
	    return result;
	}
 
	/**
	 * Nom : EscapeString
	 * Description :
	 * Cette fonction traite les chaînes de caractère en échappant les anti-slashes et les double-guillements.
	 * @param string:String
	 * 		La chaîne de caractère qui doit être traitée.
	 * @return String
	 * 		La chaîne traitée avec les caractère échappés.
	 **/
	public static function EscapeString(string:String):String
	{
		return string.Replace("\\","\\\\").Replace("\"","\\\"").Replace("\n","\\n");
	}
 
	/**
	 * Nom : Vector3ToHashtable
	 * Description :
	 * 		Cette fonction transforme un Vector3 en Hashtable avec comme clés x, y et z.
	 * @param vector3:Vector3
	 * 		Le Vector3 à transformer en Hashtable.
	 * @return Hashtable
	 * 		La Hashtable correspondant au vecteur {"x":1;"y":1;"z":1}.
	 **/
	public static function Vector3ToHashtable(vector3:Vector3):Hashtable
	{
		var retour:Hashtable = new Hashtable();
		retour.Add("x",vector3.x);
		retour.Add("y",vector3.y);
		retour.Add("z",vector3.z);
		return retour;
	}
 
	/**
	 * Nom : HashtableToVector3
	 * Description :
	 * 		Cette fonction transforme une Hashtable avec comme clés x, y et z en Vector3.
	 * @param hashtable:Hashtable
	 * 		La Hastable à retransformer en Vector3.
	 * @return Vector3
	 * 		Le Vector3 correspondant à la Hashtable de la forme {"x":1;"y":1;"z":1}.
	 **/
	public static function HashtableToVector3(hashtable:Hashtable):Vector3
	{
		var xParse:float = float.Parse(hashtable["x"].ToString());
		var yParse:float = float.Parse(hashtable["y"].ToString());
		var zParse:float = float.Parse(hashtable["z"].ToString());
		return Vector3(xParse,yParse,zParse);
	}
 
	/**
	 * Nom : HashtableToJSON
	 * Description :
	 * Cette fonction transforme une Hashtable en chaîne de caractère pour l'écriture d'un fichier JSON.
	 * @param hashtable:Hashtable
	 * 		La Hashtable à transformer en string.
	 * @return String
	 * 		La chaîne de caractère correspondant à la Hashtable.
	 **/
	public static function HashtableToJSON(hashtable:Hashtable):String
	{
		var retour:Array = new Array();
		for(var key in hashtable.Keys)
		{
			var tempValue = hashtable[key];
			if( typeof(tempValue) == typeof(Hashtable) )
			{
				retour.Add('"'+key+'" : '+HashtableToJSON(tempValue as Hashtable));
			}
			else if( typeof(tempValue) == typeof(Array) )
			{
				retour.Add('"'+key+'" : '+ArrayToJSON(tempValue as Array));
			}
			else if( typeof(tempValue) == typeof(String) )
			{
				retour.Add('"'+key+'" : "'+EscapeString(tempValue.ToString())+'"');
			}
			else if( IsNumeric(tempValue) )
			{
				retour.Add('"'+key+'" : '+tempValue.ToString());
			}
			else if( typeof(tempValue) == typeof(boolean) )
			{
				retour.Add('"'+key+'" : '+tempValue.ToString().ToLower());
			}
			else if( typeof(tempValue) == typeof(Object) )
			{
				retour.Add('"'+key+'" : '+ObjectToJSON(tempValue as Object));
			}
			else if( typeof(tempValue) == typeof(Boo.Lang.Hash) )
			{
				retour.Add('"'+key+'" : '+HashtableToJSON(tempValue));
			}
			else if( typeof(tempValue) == typeof(Boo.Lang.Hash[]) )
			{
				retour.Add('"'+key+'" : '+ArrayToJSON(new Array(tempValue)));
			}
			else
			{
//				Debug.Log("HashtableToJSON "+tempValue.ToString()+" of type "+typeof(tempValue));
//				retour.Add('"'+key+'" : "'+EscapeString(tempValue.ToString())+'"');
			}
		}
		return "{"+retour.Join(",")+"}";
	}
 
	/**
	 * Nom : Object
	 * Description :
	 * Cette fonction transforme un Object en chaîne de caractère pour l'écriture d'un fichier JSON.
	 * @param object:Object
	 * 		L'objet à transformer en string.
	 * @return String
	 * 		La chaîne de caractère correspondant à l'objet.
	 **/
	public static function ObjectToJSON( object ):String
	{
		var retour:Array = new Array();
		var objectForJSON = {};
		objectForJSON = object;
		for(var key in objectForJSON.Keys)
		{
			var tempValue = objectForJSON[key];
			if( typeof(tempValue) == typeof(Hashtable) )
			{
				retour.Add('"'+key+'" : '+HashtableToJSON(tempValue as Hashtable));
			}
			else if( typeof(tempValue) == typeof(Array) )
			{
				retour.Add('"'+key+'" : '+ArrayToJSON(tempValue as Array));
			}
			else if( typeof(tempValue) == typeof(String) )
			{
				retour.Add('"'+key+'" : "'+EscapeString(tempValue.ToString())+'"');
			}
			else if( IsNumeric(tempValue) )
			{
				retour.Add('"'+key+'" : '+tempValue.ToString());
			}
			else if( typeof(tempValue) == typeof(boolean) )
			{
				retour.Add('"'+key+'" : '+tempValue.ToString().ToLower());
			}
			else if( typeof(tempValue) == typeof(Object) )
			{
				retour.Add('"'+key+'" : '+ObjectToJSON(tempValue as Object));
			}
			else if( typeof(tempValue) == typeof(Boo.Lang.Hash) )
			{
				retour.Add('"'+key+'" : '+HashtableToJSON(tempValue));
			}
			else if( typeof(tempValue) == typeof(Boo.Lang.Hash[]) )
			{
				retour.Add('"'+key+'" : '+ArrayToJSON(new Array(tempValue)));
			}
			else
			{
//				Debug.Log("ObjectToJSON "+tempValue.ToString()+" of type "+typeof(tempValue));
//				retour.Add('"'+key+'" : "'+EscapeString(tempValue.ToString())+'"');
			}
		}
		return "{"+retour.Join(",")+"}";
	}
 
	/**
	 * Nom : ArrayToJSON
	 * Description :
	 * Cette fonction transforme un Array en chaîne de caractère pour l'écriture d'un fichier JSON.
	 * @param array:Array 
	 * 		Le Array à transformer en string.
	 * @return String
	 * 		La chaîne de caractère correspondant à l'Array.
	 **/
	public static function ArrayToJSON(array:Array):String
	{
		var retour:Array = new Array();
		for(var tempValue in array)
		{
			if( typeof(tempValue) == typeof(Hashtable) )
			{
				retour.Add(HashtableToJSON(tempValue as Hashtable));
			}
			else if( typeof(tempValue) == typeof(Array) )
			{
				retour.Add(ArrayToJSON(tempValue as Array));
			}
			else if( typeof(tempValue) == typeof(String) )
			{
				retour.Add('"'+EscapeString(tempValue.ToString())+'"');
			}
			else if( IsNumeric(tempValue) )
			{
				retour.Add(tempValue.ToString());
			}
			else if( typeof(tempValue) == typeof(boolean) )
			{
				retour.Add(tempValue.ToString().ToLower());
			}
			else if( typeof(tempValue) == typeof(Object) )
			{
				retour.Add(ObjectToJSON(tempValue as Object));
			}
			else if( typeof(tempValue) == typeof(Boo.Lang.Hash) )
			{
				retour.Add(HashtableToJSON(tempValue));
			}
			else if( typeof(tempValue) == typeof(Boo.Lang.Hash[]) )
			{
				retour.Add(ArrayToJSON(new Array(tempValue)));
			}
			else
			{
//				Debug.Log("ArrayToJSON "+tempValue.ToString()+" of type "+typeof(tempValue));
//				retour.Add('"'+EscapeString(tempValue.ToString())+'"');
			}
		}
		return "["+retour.Join(",")+"]";
	}
 
	public static function IsNumeric( tempValue )
	{
		return typeof(tempValue) == typeof(int) || typeof(tempValue) == typeof(float) || typeof(tempValue) == typeof(double);
	}
}

The code for testing

You can use this script adding it on an object in your scene after addition of GUIUtils.js and JSONUtils.js to your project (ideally in Plugins).

This testing script is using one of my others Utils scripts : GUIUtils.

public var textBefore:String = "";
public var textAfter:String = "";
 
function OnGUI()
{
	textBefore = GUI.TextField( GUIUtils.Vector4ToRect_CTWH(Vector4(0.5,0,1,0.45)), textBefore );
	if( GUI.Button( GUIUtils.Vector4ToRect_RTWH(Vector4(1.0,0.45,0.5,0.1)), "Parse" ) )
	{
		var temp:Hashtable = JSONUtils.ParseJSON( textBefore );
		Debug.Log( "Keys : " + temp.Keys.Count );
		textAfter = JSONUtils.HashtableToJSON( temp );
	}
	if( GUI.Button( GUIUtils.Vector4ToRect_LTWH(Vector4(0.0,0.45,0.5,0.1)), "Serialize" ) )
	{
		SerializeObject();
	}
	GUI.TextField( GUIUtils.Vector4ToRect_LBWH( Vector4(0,1,1,0.45) ), textAfter );
}
 
function SerializeObject()
{
	var object = {
		"sequence" : [
			{
				"parallel" : [
					{
						"functionType" : "iTween",
						"functionName" : "MoveFrom",
						"functionParameters" : {
								"y" : 5.0,
								"easeType" : "easeInCubic",
								"isLocal" : true,
								"time" : 1.0,
								"delay" : 0.0
							}
						},
					{
						"functionType" : "self",
						"functionName" : "SendMessageUpwards",
						"functionParameters" : {
							"message" : "WaitAndDust",
							"delay" : 0.0
							}
						},
					{
						"functionType" : "self",
						"functionName" : "PlayAnimation",
						"functionParameters" : {
							"animationName" : "Fall",
							"ownerTag" : "ROBOT",
							"waitTime" : 1.0,
							"delay" : 0.8
							}
						}
					]
				},
			{
				"functionType" : "self",
				"functionName" : "PlayAnimation",
				"functionParameters" : {
					"animationName" : "Spin",
					"ownerTag" : "ROBOT",
					"waitTime" : 2.0,
					"delay" : 0.0
					}
				}
		]
	};
	Debug.Log( "object : "+object );
	Debug.Log( "keys : "+object.Keys );
	for( var test in object.Keys )
	{
		Debug.Log( "Object["+test+"] : "+object[test] );
	}
	textAfter = JSONUtils.ObjectToJSON( object );
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox