• Announcements

A Non-Strict JSON UDF (JSMN)


45 posts in this topic




Posted · Report post

:thumbsup:

Share this post


Link to post
Share on other sites

Posted · Report post

Hey,

thanks for the UDF, good work. But I have problems with a specific json source -> http://data.mtgox.com/api/1/BTCUSD/depth
I can't extract the values. First I used the other JSON UDF from Gabriel Boehme and I have exactly the same problems.
I get an empty array with ~500 elements when I get into the asks or bids arrays.

This is what I'm doing to get the data:
Func getArrayFromJson($URI,$reqAuth,$post="")
$result = Jsmn_Decode(goxRequest($URI,_Iif($reqAuth>0,getNonce()&$post,"")))
$result = Jsmn_ObjTo2DArray($result)
If (Not IsArray($result) Or UBound($result) = 0) Then
MsgBox(0,"Error: "&$URI,$result)
Return 0
Else
If(NOT IsArray($result[2][1])) Then
MsgBox(0,$URI,$result[2][1])
Return 0
EndIf
Return $result[2][1]
EndIf
EndFunc


It works on every other API without problems, just not with this one.

Share this post


Link to post
Share on other sites

Posted · Report post

Try this code, then your will see every element is decoded succeed.
#Include "JSMN.au3"

Local $Json = BinaryToString(InetRead("http://data.mtgox.com/api/1/BTCUSD/depth"), 4)
Local $Obj = Jsmn_Decode($Json)

ConsoleWrite(Jsmn_Encode($Obj, $JSMN_PRETTY_PRINT))


Then why you got empty output?
Because in your code, "$result[2][1]" is an array, so you can't use MsgBox to output it.

Share this post


Link to post
Share on other sites

Posted · Report post

What for an impolite user!

Thanks it works very fine! Randomly, I need it for Mt. Gox Too ;)

Share this post


Link to post
Share on other sites

Posted · Report post

Hey Ward,

fist of all thanks for JSON extension! I appreciate the work you spent to help this community with your programming skills!

I am new to this forum and autoit is one of my personal interests so I would like to say "Hello everyone" :bye:.

Maybe someone can help me with my question?:

I want to query a JSON wheather service to get the actual wheater and for future use also the forecast.

For this I use OperWheatherMap API and build my JSON, e.g. for today in Berlin:

{"cod":"200","message":0.0268,"city":{"id":2950159,"name":"Berlin","coord":{"lon":13.41053,"lat":52.524368},"country":"DE","population":1000000},"cnt":1,"list":[{"dt":1368874800,"temp":{"day":13.22,"min":10.57,"max":13.22,"night":10.57,"eve":12.49,"morn":13.22},"pressure":1015.76,"humidity":100,"weather":[{"id":501,"main":"Rain","description":"mäßiger Regen","icon":"10"}],"speed":7.08,"deg":269,"clouds":92,"rain":7.75}]}

My special interest lays in the params "temp":{"day":13.22,"min":10.57,"max":13.22 ... and  "description":"mäßiger Regen" but I am not able to extract this information using JSMN.

My code:

#include <JSMN.au3>

; Anfrage von Wetter mit JSON Antwort: http://api.openweathermap.org/data/2.5/forecast/daily?q=Berlin&mode=json&units=metric&cnt=1&lang=de
local $Json1 = '{"cod":"200","message":0.0268,"city":{"id":2950159,"name":"Berlin","coord":{"lon":13.41053,"lat":52.524368},"country":"DE","population":1000000},"cnt":1,"list":[{"dt":1368874800,"temp":{"day":13.22,"min":10.57,"max":13.22,"night":10.57,"eve":12.49,"morn":13.22},"pressure":1015.76,"humidity":100,"weather":[{"id":501,"main":"Rain","description":"mäßiger Regen","icon":"10"}],"speed":7.08,"deg":269,"clouds":92,"rain":7.75}]}'

Local $objJson = Jsmn_Decode($Json1)
If (Jsmn_IsObject($objJson)) Then
	ConsoleWrite('Data1:' & Jsmn_ObjGetKeys($objJson) & @CRLF)
	ConsoleWrite('Data2:' & Jsmn_ObjGet($objJson, "message") & @CRLF)
	ConsoleWrite('Data3:' & Jsmn_ObjGetCount($objJson) & @CRLF)
	ConsoleWrite('Data4:' & Jsmn_ObjExists($objJson, "message") & @CRLF)
Else
	ConsoleWrite("Kein Objekt")
EndIf

The according console output:

Data1:
Data2:0.0268
Data3:5
Data4:True

So the first level was queried successfully but if I want to query the params mentioned above I get an empty result:

AutoIt:

#include <JSMN.au3>

; Anfrage von Wetter mit JSON Antwort: http://api.openweathermap.org/data/2.5/forecast/daily?q=Berlin&mode=json&units=metric&cnt=1&lang=de
local $Json1 = '{"cod":"200","message":0.0268,"city":{"id":2950159,"name":"Berlin","coord":{"lon":13.41053,"lat":52.524368},"country":"DE","population":1000000},"cnt":1,"list":[{"dt":1368874800,"temp":{"day":13.22,"min":10.57,"max":13.22,"night":10.57,"eve":12.49,"morn":13.22},"pressure":1015.76,"humidity":100,"weather":[{"id":501,"main":"Rain","description":"mäßiger Regen","icon":"10"}],"speed":7.08,"deg":269,"clouds":92,"rain":7.75}]}'
Local $objJson = Jsmn_Decode($Json1)
If (Jsmn_IsObject($objJson)) Then
	ConsoleWrite('Data1:' & Jsmn_ObjGetKeys($objJson) & @CRLF)
	ConsoleWrite('Data2:' & Jsmn_ObjGet($objJson, "day") & @CRLF)
	ConsoleWrite('Data3:' & Jsmn_ObjGetCount($objJson) & @CRLF)
	ConsoleWrite('Data4:' & Jsmn_ObjExists($objJson, "day") & @CRLF)
Else
	ConsoleWrite("Kein Objekt")
EndIf
Local $objJson2 = Jsmn_Decode($objJson)

Console:

Data1:
Data2:
Data3:6
Data4:True

Because this is my first contact with JSON I think that I am doing something wrong with the the function "Jsmn_ObjGet". But what am I doing wrong?

Regards

mmscripting

Share this post


Link to post
Share on other sites

Posted · Report post

Try this:

#include <JSMN.au3>

; Anfrage von Wetter mit JSON Antwort: http://api.openweathermap.org/data/2.5/forecast/daily?q=Berlin&mode=json&units=metric&cnt=1&lang=de
local $Json1 = '{"cod":"200","message":0.0268,"city":{"id":2950159,"name":"Berlin","coord":{"lon":13.41053,"lat":52.524368},"country":"DE","population":1000000},"cnt":1,"list":[{"dt":1368874800,"temp":{"day":13.22,"min":10.57,"max":13.22,"night":10.57,"eve":12.49,"morn":13.22},"pressure":1015.76,"humidity":100,"weather":[{"id":501,"main":"Rain","description":"mäßiger Regen","icon":"10"}],"speed":7.08,"deg":269,"clouds":92,"rain":7.75}]}'
Local $objJson = Jsmn_Decode($Json1)

Local $List = Jsmn_ObjGet($objJson, "list") ; "list" is an array
Local $objJson2 = $List[0]
Local $Temp = Jsmn_ObjGet($objJson2, "temp") ; "temp" is an object

ConsoleWrite(Jsmn_ObjGet($Temp, "day") & @LF)
ConsoleWrite(Jsmn_ObjGet($Temp, "min") & @LF)

Share this post


Link to post
Share on other sites

Posted · Report post

Hi Ward,

ahh ok now I understand: You have do know about the JSON structure and like an encapsulation take each part in an own list / array and at some point there is only a string left which can be queried for or values.

Before I thought that I can just query the whole JSON object and the function will give me the value in return. Is this also in other programming languages a common behaviour to "encapsulate" the whole JSON object or maybe is there a way to query the whole object for the needed string?

Anyway: Thanks for your very fast and efficient help :thumbsup: !

Regards

mmscripting

Share this post


Link to post
Share on other sites

Posted · Report post

Funny that I need such a UDF now. This has to be the best JSON UDF I've seen floating around the Forums. Thanks ward.

Share this post


Link to post
Share on other sites

Posted · Report post

I wrote a helper function to get specific element in nested array/object returned from Jsmn_Decode() more easily.

Here is the code and example:

#Include "JSMN.au3"

Local $Json = '{"key1" : "value1", "key2" : [true, ["a", "b"], {"key3", "obj_in_array"}]}'
Local $Obj = Jsmn_Decode($Json)
Jsmn_Get_ShowResult($Obj, '["key1"]')
Jsmn_Get_ShowResult($Obj, '["key2"][0]')
Jsmn_Get_ShowResult($Obj, '["key2"][1][0]')
Jsmn_Get_ShowResult($Obj, '["key2"][2]["key3"]')

Local $Json = '{"strange key []" : "uses \\uXXXX for unsupported char in the key", "key_nospace_1" : {"key_nospace_2" : "don''t need \" if the key has no space"} }'
Local $Obj = Jsmn_Decode($Json)
Jsmn_Get_ShowResult($Obj, '["strange key [\u005D"]')
Jsmn_Get_ShowResult($Obj, '[key_nospace_1][key_nospace_2]')

Jsmn_Get_ShowResult($Obj, '[error1]')
Jsmn_Get_ShowResult($Obj, '[error2')


Func Jsmn_Get_ShowResult($Var, $Key)
	Local $Ret = Jsmn_Get($Var, $Key)
	If @Error Then
		Switch @error
			Case 1
				ConsoleWrite("Error 1: key not exists" & @LF)
			Case 2
				ConsoleWrite("Error 2: syntax error" & @LF)
		EndSwitch

	Else
		ConsoleWrite($Key & " => " & VarGetType($Ret) & ": " & $Ret & @LF)
	EndIf
EndFunc

Func Jsmn_Get($Var, $Key)
	If Not $Key Then Return $Var

	Local $Match = StringRegExp($Key, "(^\[([^\]]+)\])", 3)
	If IsArray($Match) Then
		Local $Index = Jsmn_Decode($Match[1])
		$Key = StringTrimLeft($Key, StringLen($Match[0]))

		If IsString($Index) And Jsmn_IsObject($Var) And Jsmn_ObjExists($Var, $Index) Then
			Local $Ret = Jsmn_Get(Jsmn_ObjGet($Var, $Index), $Key)
			Return SetError(@Error, 0, $Ret)

		ElseIf IsNumber($Index) And IsArray($Var) And $Index >= 0 And $Index < UBound($Var) Then
			Local $Ret = Jsmn_Get($Var[$Index], $Key)
			Return SetError(@Error, 0, $Ret)

		Else
			Return SetError(1, 0, "")

		EndIf
	EndIf

	Return SetError(2, 0, "")
EndFunc

Siahtech and Danyfirex like this

Share this post


Link to post
Share on other sites

Posted · Report post

I'm trying to parse the data below,

{"events":[{"world_id":2012,"map_id":873,"event_id":"659149D4-43EC-4DCB-A6BB-0B2D402B537B","state":"Warmup"},
{"world_id":2012,"map_id":873,"event_id":"72F93CD8-94AC-4234-8D86-996CCAC76A46","state":"Warmup"},
{"world_id":2012,"map_id":873,"event_id":"81F89AC2-4764-49CB-A4F1-8B7546201DC7","state":"Active"},
{"world_id":2012,"map_id":873,"event_id":"FF71DE90-423B-4685-A343-83487A330C7A","state":"Active"}]}

The end result would be an array with 3 columns for map_id, event_id, and state filled with the relevant data.

By striping '{"events":[' and ']}' from either end i managed to get the values of the first line/object but how do extract further items? I can't work out how to loop into the next line(s).

Thanks for any help. My code isn't really worth showing hence no code example.

 

Share this post


Link to post
Share on other sites

Posted · Report post

Using Jsmn_Get(), it's easy.

I will put this function into the UDF later.

#Include "JSMN.au3"

Local $Json = '{"events":[{"world_id":2012,"map_id":873,"event_id":"659149D4-43EC-4DCB-A6BB-0B2D402B537B","state":"Warmup"},{"world_id":2012,"map_id":873,"event_id":"72F93CD8-94AC-4234-8D86-996CCAC76A46","state":"Warmup"},{"world_id":2012,"map_id":873,"event_id":"81F89AC2-4764-49CB-A4F1-8B7546201DC7","state":"Active"},{"world_id":2012,"map_id":873,"event_id":"FF71DE90-423B-4685-A343-83487A330C7A","state":"Active"}]}'
Local $Obj = Jsmn_Decode($Json)

ConsoleWrite(Jsmn_Get($Obj, '["events"][0]["world_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][0]["map_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][0]["event_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][0]["state"]') & @LF)

ConsoleWrite(Jsmn_Get($Obj, '["events"][1]["world_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][1]["map_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][1]["event_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][1]["state"]') & @LF)

ConsoleWrite(Jsmn_Get($Obj, '["events"][2]["world_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][2]["map_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][2]["event_id"]') & @LF)
ConsoleWrite(Jsmn_Get($Obj, '["events"][2]["state"]') & @LF)

Func Jsmn_Get($Var, $Key)
	If Not $Key Then Return $Var

	Local $Match = StringRegExp($Key, "(^\[([^\]]+)\])", 3)
	If IsArray($Match) Then
		Local $Index = Jsmn_Decode($Match[1])
		$Key = StringTrimLeft($Key, StringLen($Match[0]))

		If IsString($Index) And Jsmn_IsObject($Var) And Jsmn_ObjExists($Var, $Index) Then
			Local $Ret = Jsmn_Get(Jsmn_ObjGet($Var, $Index), $Key)
			Return SetError(@Error, 0, $Ret)

		ElseIf IsNumber($Index) And IsArray($Var) And $Index >= 0 And $Index < UBound($Var) Then
			Local $Ret = Jsmn_Get($Var[$Index], $Key)
			Return SetError(@Error, 0, $Ret)

		Else
			Return SetError(1, 0, "")

		EndIf
	EndIf

	Return SetError(2, 0, "")
EndFunc

Share this post


Link to post
Share on other sites

Posted (edited) · Report post

Thanks! Wow, it's easy to do once you know the correct syntax. Thanks again for the UDF and your code above really helps me understand it more now :)

Edited by Fly By Night

Share this post


Link to post
Share on other sites

Posted · Report post

Perfect, right at the time i thought of buying the $400 n/Software json Activex the native and free udf comes around, thank you very much.

Share this post


Link to post
Share on other sites

Posted · Report post

Can it be possible to use put and get via JSON Dot Notation?

Share this post


Link to post
Share on other sites

Posted · Report post

I'm searching through a long (>800) list looking for a specific value using the following code and my routine seems to be very slow compared to using a similar version just using _StringBetween on the raw JSON string.

I'm not sure if i can reduce the number of Jsmn_Get calls using the logic below. Is the While..Wend method below one to use or am i missing a better way to hunt for a value. Thanks again.

Func getEventstate($eventID)


; Search for a specific EventID and return it's state


Local $evState = "", $evFound = 0
Local $i = 0

	While ((Jsmn_Get($EventsObj, '["events"][' & $i & ']["event_id"]') <> "") And $evFound = 0)

		If Jsmn_Get($EventsObj, '["events"][' & $i & ']["event_id"]') == $eventID Then
			$evState = Jsmn_Get($EventsObj, '["events"][' & $i & ']["state"]')
			$evFound = 1
		EndIf

		$i = $i + 1
	WEnd

	Return ($evState)
EndFunc   ;==>getEventstate2

For reference, same using _StringBetween

Func getEventstate($eventID)

	$srcStr = '"event_id":"' & $eventID & '","state":"'
	$evState = _StringBetween($EventsJson, $srcStr, '"}')

	If $evState <> "" Then
		Return ($evState[0])
	EndIf
EndFunc   ;==>getEventstate

Share this post


Link to post
Share on other sites

Posted · Report post

You can optimize this code (and maybe any code) to avoid do the same thing everytime in the loop. For example, you can get '["events"]' object and reuse it in the loop. And then you can aslo try to modify the code to get "[' & $i & ']" only once when the $i was changed.

However, even you wrote the optimized code, I don't think it will run faster than _StringBetween. So don't try to compare with that. 

Share this post


Link to post
Share on other sites

Posted (edited) · Report post

If I wanted to load in the Events object and search through all the values of a key for a specific one, what method would you recommend? I wasn't sure how to do this optimally that is why i ended up just doing a While..Wend using the $i to increment onto the next key until i find the value i'm after. Also i wasn't sure if   '["events"][' & $i & ']["event_id"]') <> "" was the correct method to check for end of keys. I realise what i'm after is a Jsmn_Search function that looks for a value and returns how to obtain it via Jsmn_Get.

I did a test of copying key values into an array using Jsmn_Get then _StringBetween and Jsmn_Get was a lot faster on a test of about 1600 keys.

Edited by Fly By Night

Share this post


Link to post
Share on other sites

Posted (edited) · Report post

Here is the JSMN_Get function that Ward wrote in post #12 written to allow both delimiter notation (dot, comma, pipe, whatever notation) and JSON notation.

; #FUNCTION# ===================================================================
; Name:           	Jsmn_Get
; Description:    Retrieves a value from the scripting.dictionary key specified
;
; Parameter(s):
;						$Object 	Scripting dictionary object
;
;						$Key 		Key for the value you want to retrieve. Follows delimiter based or JSON based format depending on the notation parameter
;
;						$Notation
;										0 - Delimiter based - Key1.Key2
;										1 - JSON format based ["key1"]["key2"]
;
;						$Delim		If notation = 0 Then this is the delimiter between keys
;
; Requirement(s):   JSMN JSON library by Ward.
;
; Return Value(s):
;							On Success	Returns value from key
;
;							On Failure		Returns a blank string and an error value.
;									  			@error
;													1 - key does not exist
;													2 - notation syntax error
;												@Extended - Only used if notation = 0
;													See StringSplit error codes
;
; Author(s):    Ward (modified slightly by SantaRyan to add delimiter notation)
;===============================================================================
Func Jsmn_Get($Object, $Key, $Notation = 0, $Delim = ".")
	If Not $Key Then Return $Object
	If IsKeyword($Notation) Then $Notation = 0
	Local $Index, $Match, $Ret
	If $Notation = 0 Then
		$Match = StringSplit($Key, $Delim, 1)
		If IsArray($Match) Then
			$Index = $Match[1]
			$Key = ""
			For $i = 2 To $Match[0]
				$Key &= $Match[$i] & $Delim
			Next
			$Key = StringTrimRight($Key, 1)
		Else
			Return SetError(2, 0, "")
		EndIf
	ElseIf $Notation = 1 Then
		$Match = StringRegExp($Key, "(^\[([^\]]+)\])", 3)
		If IsArray($Match) Then
			$Index = Jsmn_Decode($Match[1])
			$Key = StringTrimLeft($Key, StringLen($Match[0]))
		Else
			Return SetError(2, 0, "")
		EndIf
	EndIf
	If IsString($Index) And Jsmn_IsObject($Object) And Jsmn_ObjExists($Object, $Index) Then
		$Ret = Jsmn_Get(Jsmn_ObjGet($Object, $Index), $Key, $Delim)
		Return SetError(@error, 0, $Ret)
	ElseIf IsNumber($Index) And IsArray($Object) And $Index >= 0 And $Index < UBound($Object) Then
		$Ret = Jsmn_Get($Object[$Index], $Key, $Delim)
		Return SetError(@error, 0, $Ret)
	Else
		Return SetError(1, 0, "")
	EndIf
EndFunc   ;==>Jsmn_Get
Edited by santaryan

Share this post


Link to post
Share on other sites

Posted (edited) · Report post

Hello,

thanks for this UDF, it has been really helpful so far. However, I got one JSON string that seems impossible to decode with this UDF (I validated it with a JSON validator, so does not seem to be invalid):

I doesn't work in this form:

#Include <JSMN.au3>

$JSON='{"a":{"742597609":{"v":673,"p":4.91,"lb":"test1","av":58,"sl":11.6},"534165346":{"v":777,"p":5.66,"lb":"test2","av":58,"sl":13.3}},"b":16092018}'

Local $objJson = Jsmn_Decode($JSON)

If Jsmn_IsObject($objJson) Then
	Local $auctions = Jsmn_ObjGet($objJson, "a")
	For $i = 0 To UBound($auctions)-1
		Local $objJson2 = $auctions[$i]
		ConsoleWrite(Jsmn_ObjGet($objJson2, "p"))
	Next
EndIf

When I transform the JSON string like this, it produces an output:

#Include <JSMN.au3>

$JSON='{"a":{"742597609":{"v":673,"p":4.91,"lb":"test1","av":58,"sl":11.6},"534165346":{"v":777,"p":5.66,"lb":"test2","av":58,"sl":13.3}},"b":16092018}'

;JSMN compatibility
$JSON=StringRegExpReplace($JSON,'"\d{9}":','')
$JSON=StringReplace($JSON,'{"a":{','{"a":[')
$JSON=StringReplace($JSON,'}},','}],')

;produces
;$JSON='{"a":[{"v":673,"p":4.91,"lb":"test1","av":58,"sl":11.6},{"v":777,"p":5.66,"lb":"test2","av":58,"sl":13.3}],"b":16092018}'

Local $objJson = Jsmn_Decode($JSON)

If Jsmn_IsObject($objJson) Then
	Local $auctions = Jsmn_ObjGet($objJson, "a")
	For $i = 0 To UBound($auctions)-1
		Local $objJson2 = $auctions[$i]
		ConsoleWrite(Jsmn_ObjGet($objJson2, "p"))
	Next
EndIf

What am I doing wrong ? Is it possible to get the auction details (like "p" in this example) without transforming the JSON string ?

Edited by level20peon

Share this post


Link to post
Share on other sites

Posted · Report post

The $auction you get from Jsmn_ObjGet($objJson, "a") is an object, not an array.

Your code should be modified like this:

#Include <JSMN.au3>

$JSON='{"a":{"742597609":{"v":673,"p":4.91,"lb":"test1","av":58,"sl":11.6},"534165346":{"v":777,"p":5.66,"lb":"test2","av":58,"sl":13.3}},"b":16092018}'

Local $objJson = Jsmn_Decode($JSON)

If Jsmn_IsObject($objJson) Then
    Local $auctions = Jsmn_ObjGet($objJson, "a")
	Local $Keys = Jsmn_ObjGetKeys($auctions)
	For $i = 0 To UBound($Keys) - 1
		Local $objJson2 = Jsmn_ObjGet($auctions, $Keys[$i])
		ConsoleWrite(Jsmn_ObjGet($objJson2, "p") & @LF)
	Next
EndIf

level20peon likes this

Share this post


Link to post
Share on other sites

Posted · Report post

I sometimes get this error:

JSMN.au3 (403) : ==> Error in expression.:
Return $Object.Item(String($Key))
Return ^ ERROR

I am trying to filter what is being decoded as JSON in the first place using StringRegExp on the input as well as using the Jsmn_IsObject function, but that sometimes doesn't seem to do the trick.

Does anyone know what could cause this error as well as what other error catching mechanism I could use to prevent it from happening ?

Share this post


Link to post
Share on other sites

Posted (edited) · Report post

 

I wrote a helper function to get specific element in nested array/object returned from Jsmn_Decode() more easily.

Here is the code and example:

#Include "JSMN.au3"

Local $Json = '{"key1" : "value1", "key2" : [true, ["a", "b"], {"key3", "obj_in_array"}]}'
Local $Obj = Jsmn_Decode($Json)
Jsmn_Get_ShowResult($Obj, '["key1"]')
Jsmn_Get_ShowResult($Obj, '["key2"][0]')
Jsmn_Get_ShowResult($Obj, '["key2"][1][0]')
Jsmn_Get_ShowResult($Obj, '["key2"][2]["key3"]')

Local $Json = '{"strange key []" : "uses \\uXXXX for unsupported char in the key", "key_nospace_1" : {"key_nospace_2" : "don''t need \" if the key has no space"} }'
Local $Obj = Jsmn_Decode($Json)
Jsmn_Get_ShowResult($Obj, '["strange key [\u005D"]')
Jsmn_Get_ShowResult($Obj, '[key_nospace_1][key_nospace_2]')

Jsmn_Get_ShowResult($Obj, '[error1]')
Jsmn_Get_ShowResult($Obj, '[error2')


Func Jsmn_Get_ShowResult($Var, $Key)
	Local $Ret = Jsmn_Get($Var, $Key)
	If @Error Then
		Switch @error
			Case 1
				ConsoleWrite("Error 1: key not exists" & @LF)
			Case 2
				ConsoleWrite("Error 2: syntax error" & @LF)
		EndSwitch

	Else
		ConsoleWrite($Key & " => " & VarGetType($Ret) & ": " & $Ret & @LF)
	EndIf
EndFunc

Func Jsmn_Get($Var, $Key)
	If Not $Key Then Return $Var

	Local $Match = StringRegExp($Key, "(^\[([^\]]+)\])", 3)
	If IsArray($Match) Then
		Local $Index = Jsmn_Decode($Match[1])
		$Key = StringTrimLeft($Key, StringLen($Match[0]))

		If IsString($Index) And Jsmn_IsObject($Var) And Jsmn_ObjExists($Var, $Index) Then
			Local $Ret = Jsmn_Get(Jsmn_ObjGet($Var, $Index), $Key)
			Return SetError(@Error, 0, $Ret)

		ElseIf IsNumber($Index) And IsArray($Var) And $Index >= 0 And $Index < UBound($Var) Then
			Local $Ret = Jsmn_Get($Var[$Index], $Key)
			Return SetError(@Error, 0, $Ret)

		Else
			Return SetError(1, 0, "")

		EndIf
	EndIf

	Return SetError(2, 0, "")
EndFunc

Old thread I just needed to say Thanks

I spent Days trying to decode and use my Json file. I found and used your Code and it worked =)

Thanks a TON!!!!

The json part in my script

#Include "JSMN.au3"
#Include "File.au3"
local $Json1_2
_FileReadToArray(@ScriptDir & "\DatabaseS.db",$Json1_2,0)
$json1_3 = _ArrayToString($Json1_2,"")
$Json2 = StringStripWS($Json1_3, 8)
Local $Obj1 = Jsmn_Decode($Json2)
$resault = Jsmn_Get($Obj1, '["response"]["prices"]["10"]["6"]["0"]["last_update"]')
ConsoleWrite($resault & @CRLF)

Func Jsmn_Get($Var, $Key)
    If Not $Key Then Return $Var

    Local $Match = StringRegExp($Key, "(^\[([^\]]+)\])", 3)
    If IsArray($Match) Then
        Local $Index = Jsmn_Decode($Match[1])
        $Key = StringTrimLeft($Key, StringLen($Match[0]))

        If IsString($Index) And Jsmn_IsObject($Var) And Jsmn_ObjExists($Var, $Index) Then
            Local $Ret = Jsmn_Get(Jsmn_ObjGet($Var, $Index), $Key)
            Return SetError(@Error, 0, $Ret)

        ElseIf IsNumber($Index) And IsArray($Var) And $Index >= 0 And $Index < UBound($Var) Then
            Local $Ret = Jsmn_Get($Var[$Index], $Key)
            Return SetError(@Error, 0, $Ret)

        Else
            Return SetError(1, 0, "")

        EndIf
    EndIf

    Return SetError(2, 0, "")
EndFunc
Edited by Siahtech

Share this post


Link to post
Share on other sites

Posted (edited) · Report post

I am completely unable to understand how to access arrays using the latest JSMN.au3 downloaded from the first post, Jsmn_Get from post #12 and dot notation. In fact, that Jsmn_Get doesn't seem to be working with old-style notation either. Can someone redo or recommend a way to access json information with dot notation that actually works?

 

#Include "JSMN.au3"

Local $Json = '{"events":[{"world_id":2012,"map_id":873,"event_id":"659149D4-43EC-4DCB-A6BB-0B2D402B537B","state":"Warmup"},{"world_id":2012,"map_id":873,"event_id":"72F93CD8-94AC-4234-8D86-996CCAC76A46","state":"Warmup"},{"world_id":2012,"map_id":873,"event_id":"81F89AC2-4764-49CB-A4F1-8B7546201DC7","state":"Active"},{"world_id":2012,"map_id":873,"event_id":"FF71DE90-423B-4685-A343-83487A330C7A","state":"Active"}]}'
Local $Obj = Jsmn_Decode($Json)

ConsoleWrite(Jsmn_Get($Obj, "events[0].world_id") & @CRLF) ;Doesn't work
ConsoleWrite(Jsmn_Get($Obj, '["events"][0]["world_id"]', 1) & @LF) ;Doesn't work

; #FUNCTION# ===================================================================
; Name:             Jsmn_Get
; Description:    Retrieves a value from the scripting.dictionary key specified
;
; Parameter(s):
;                       $Object     Scripting dictionary object
;
;                       $Key        Key for the value you want to retrieve. Follows delimiter based or JSON based format depending on the notation parameter
;
;                       $Notation
;                                       0 - Delimiter based - Key1.Key2
;                                       1 - JSON format based ["key1"]["key2"]
;
;                       $Delim      If notation = 0 Then this is the delimiter between keys
;
; Requirement(s):   JSMN JSON library by Ward.
;
; Return Value(s):
;                           On Success  Returns value from key
;
;                           On Failure      Returns a blank string and an error value.
;                                               @error
;                                                   1 - key does not exist
;                                                   2 - notation syntax error
;                                               @Extended - Only used if notation = 0
;                                                   See StringSplit error codes
;
; Author(s):    Ward (modified slightly by SantaRyan to add delimiter notation)
;===============================================================================
Func Jsmn_Get($Object, $Key, $Notation = 0, $Delim = ".")
    If Not $Key Then Return $Object
    If IsKeyword($Notation) Then $Notation = 0
    Local $Index, $Match, $Ret
    If $Notation = 0 Then
        $Match = StringSplit($Key, $Delim, 1)
        If IsArray($Match) Then
            $Index = $Match[1]
            $Key = ""
            For $i = 2 To $Match[0]
                $Key &= $Match[$i] & $Delim
            Next
            $Key = StringTrimRight($Key, 1)
        Else
            Return SetError(2, 0, "")
        EndIf
    ElseIf $Notation = 1 Then
        $Match = StringRegExp($Key, "(^\[([^\]]+)\])", 3)
        If IsArray($Match) Then
            $Index = Jsmn_Decode($Match[1])
            $Key = StringTrimLeft($Key, StringLen($Match[0]))
        Else
            Return SetError(2, 0, "")
        EndIf
    EndIf
    If IsString($Index) And Jsmn_IsObject($Object) And Jsmn_ObjExists($Object, $Index) Then
        $Ret = Jsmn_Get(Jsmn_ObjGet($Object, $Index), $Key, $Delim)
        Return SetError(@error, 0, $Ret)
    ElseIf IsNumber($Index) And IsArray($Object) And $Index >= 0 And $Index < UBound($Object) Then
        $Ret = Jsmn_Get($Object[$Index], $Key, $Delim)
        Return SetError(@error, 0, $Ret)
    Else
        Return SetError(1, 0, "")
    EndIf
EndFunc   ;==>Jsmn_Get
Edited by this-is-me

Share this post


Link to post
Share on other sites

Posted (edited) · Report post

24-hr bump. I really want to use dot notation to access JSON objects using JSMN. If someone can "fix" the existing code, or rewrite it I would appreciate it. I don't begin to understand what to do with it.

EDIT: After much trouble, I realise two problems with Jsmn_Get. First, the $Index was not being typecast as a number in the case of a dot notation. Therefore, I added a simple typecast.
 

$Index = $Match[1]
;Add the following
$Index = (StringIsInt($Index)=1?Number($Index):$Index)

Secondly, when the function was called by itself, it was called with improper parameters (missing the notation flag):
 

;OLD: $Ret = Jsmn_Get(Jsmn_ObjGet($Object, $Index), $Key, $Delim)
$Ret = Jsmn_Get(Jsmn_ObjGet($Object, $Index), $Key, $Notation, $Delim)

;OLD: $Ret = Jsmn_Get($Object[$Index], $Key, $Delim)
$Ret = Jsmn_Get($Object[$Index], $Key, $Notation, $Delim)

With these problems solved, everything works swimmingly.

Edited by this-is-me

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.