Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Obj --> JSON -->Obj


  • Please log in to reply
8 replies to this topic
rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011
Searching for an efficient way convert a JSON string to an AutoHotkey object, I found these two functions buried in the support section. I am finding them very useful, so I am re-posting them here.

Note: To get ParseJson(), or any other script that is based on the ScriptControl COM object, to work under 64-bit Windows you need to run ComSurrogate in the background. A compiled version of ComSurrogate is available here.
  • BuildJson(Obj) converts an AutoHotkey object into a JSON string.
  • ParseJson(jsonstr) converts a JSON string into an AutoHotkey object.
All credits go to Coco and Getfree
 
/****************************************************************************************
    Function: BuildJson(obj) 
        Builds a JSON string from an AutoHotkey object

    Parameters:
        obj - An AutoHotkey array or object, which can include nested objects.

    Remarks:
        Originally Obj2Str() by Coco,
        http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/page-2#entry588373
        
        Modified to use double quotes instead of single quotes and to leave numeric values
        unquoted.

    Returns:
        The JSON string
*/
BuildJson(obj) 
{
    str := "" , array := true
    for k in obj {
        if (k == A_Index)
            continue
        array := false
        break
    }
    for a, b in obj
        str .= (array ? "" : """" a """: ") . (IsObject(b) ? BuildJson(b) : IsNumber(b) ? b : """" b """") . ", "	
    str := RTrim(str, " ,")
    return (array ? "[" str "]" : "{" str "}")
}

/****************************************************************************************
    Function: ParseJson(jsonStr)
        Converts a JSON string into an AutoHotkey object

    Parameters:
        jsonstr - the JSON string to convert

    Remarks:
        Originally by Getfree,
        http://www.autohotkey.com/board/topic/93300-what-format-to-store-settings-in/#entry588268

    Returns:
        The AutoHotkey object.
*/
ParseJson(jsonStr)
{
    SC := ComObjCreate("ScriptControl") 
    SC.Language := "JScript"
    ComObjError(false)
    jsCode =
    (
    function arrangeForAhkTraversing(obj){
        if(obj instanceof Array){
            for(var i=0 ; i<obj.length ; ++i)
                obj[i] = arrangeForAhkTraversing(obj[i]) ;
            return ['array',obj] ;
        }else if(obj instanceof Object){
            var keys = [], values = [] ;
            for(var key in obj){
                keys.push(key) ;
                values.push(arrangeForAhkTraversing(obj[key])) ;
            }
            return ['object',[keys,values]] ;
        }else
            return [typeof obj,obj] ;
    }
    )
    SC.ExecuteStatement(jsCode "; obj=" jsonStr)
    return convertJScriptObjToAhks( SC.Eval("arrangeForAhkTraversing(obj)") )
}

/*!
    Function: convertJScriptObjToAhks(jsObj)
        Used by ParseJson()
*/
convertJScriptObjToAhks(jsObj)
{
    if(jsObj[0]="object"){
        obj := {}, keys := jsObj[1][0], values := jsObj[1][1]
        loop % keys.length
            obj[keys[A_INDEX-1]] := convertJScriptObjToAhks( values[A_INDEX-1] )
        return obj
    }else if(jsObj[0]="array"){
        array := []
        loop % jsObj[1].length
            array.insert(convertJScriptObjToAhks( jsObj[1][A_INDEX-1] ))
        return array
    }else
        return jsObj[1]
}

/*!
    Function: IsNumber(Num)
        Checks if Num is a number.

    Returns:
        True if Num is a number, false if not
*/
IsNumber(Num)
{
    if Num is number
        return true
    else
        return false
}

My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!


Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Edit: I just wrote both of these. Both do the same as the above.
jsonAHK(s){
	static o:=comobjcreate("scriptcontrol")
	o.language:="jscript"
	return o.eval("(" s ")")
}
jsonBuild(j) { 
	for x,y in j
		s.=((a:=(j.setcapacity(0)=(j.maxindex()-j.minindex()+1)))?"":x ":")(isobject(y)?jsonBuild(y):y/y||y==0?y:"'" y "'") ","	
		;s.=x ":" (isobject(y)?jsonBuild(y):y/y||y==0?y:"'" y "'") ","
	return (a?"[" rtrim(s,",") "]":"{" rtrim(s,",") "}")
	;return ("{" rtrim(s,",") "}")
}
jsonGet(s,k){
	static o:=comobjcreate("scriptcontrol")
	o.language:="jscript"
	return o.eval("(" s ")." k)
}
  • jsonAHK() returns an AHK object from a JSON string.
  • jsonBuild() is based off of the one you posted and returns a JSON string from an AHK object.
    As is, if the object appears to be an array, it'll format it as such.
    To format arrays as objects, see here, switch the commented lines.
  • jsonGet() returns an value from a JSON string.
Examples:
string={hello:'world',its:{over:9000},foo:['bar']}
msgbox,% jsonGet(string,"hello")
msgbox,% jsonGet(string,"its.over")
msgbox,% jsonGet(string,"foo[0]")
obj:={hello:'world',its:{over:9000},foo:['bar']}
msgbox,% jsonBuild(obj)
string={hello:'world',its:{over:9000},foo:['bar']}
obj:=jsonAHK(string)
msgbox,% obj.hello
msgbox,% obj.its.over
msgbox,% obj.foo.0

3nL8f.png


Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Double post. Sorry.

EDIT: Might as well use it for something... Is there any way I can "detach" the result of jsonAHK() from the COM object?

Look at this code, for example:
string={hello:"world",foo:["bar"],a:0}

obj:=jsonAHK(string)

back2string:=jsonBuild(obj)
You'll see that the function call jsonBuild() results in an error because obj is still acting as a COM object because of the return o.eval("(" s ")") in jsonAHK().

3nL8f.png


tmplinshi
  • Members
  • 245 posts
  • Last active: Mar 12 2015 02:29 PM
  • Joined: 06 Apr 2012
Hi, Wicked. The result isn't right:
jsonString =
(LTrim Join
	{
		"id"  : "123",
		"file": [
			{
				"name": "1.txt",
				"size": 100
			},
			{
				"name": "2.txt",
				"size": 200,
				"time": {
					"create"  :	2013,
					"modified":	2015
				}
			}
		]
	}
)

obj := jsonAHK(jsonString)
MsgBox, % obj.file.1.name         ; It returns "2.txt", but the correct one should be "1.txt".


Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
AHK is the only language (that I know of) where the index of an array begins at 1 by default. In JSON/JavaScript, where index starts at 0, obj.file.1 is 2.txt.

3nL8f.png


tmplinshi
  • Members
  • 245 posts
  • Last active: Mar 12 2015 02:29 PM
  • Joined: 06 Apr 2012

AHK is the only language (that I know of) where the index of an array begins at 1 by default. In JSON/JavaScript, where index starts at 0, obj.file.1 is 2.txt.


I see. Thanks.

rbrtryn
  • Members
  • 1177 posts
  • Last active: Sep 11 2013 08:04 PM
  • Joined: 22 Jun 2011

AHK is the only language (that I know of) where the index of an array begins at 1 by default. In JSON/JavaScript, where index starts at 0, obj.file.1 is 2.txt.


This is not exactly correct. AutoHotkey arrays have no default minimum index. This is perfectly possible: MyArray[0] := "first index"


Added the following note to the OP:

To get ParseJson(), or any other script that is based on the ScriptControl COM object, to work under 64-bit Windows you need to run ComSurrogate in the background.


My Scripts are written for the latest released version of AutoHotkey.

Need a secure, accessible place to backup your stuff? Use Dropbox!


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

"Array begins at 1 by default" does not mean "arrays must begin at 1".  It is correct to say that AutoHotkey's arrays begin at 1 by default.  This includes Object (using Object.Insert(value) or [a,b,c]) and pseudo-arrays created by commands like StringSplit.  Since JavaScript allows array[-1] = whatever, would you say that JavaScript arrays don't begin at 0 by default?



Wicked
  • Members
  • 504 posts
  • Last active: Nov 18 2018 02:17 AM
  • Joined: 07 Jun 2008
Lexikos, perhaps you' be able to answer the question I had:
http://www.autohotke...bj/#entry600445

Sorry if I'm just having a brain fart.

3nL8f.png