Popular Post Ward Posted February 7, 2013 Popular Post Share Posted February 7, 2013 (edited) Introduction JSON (Javascript Object Notation) is a popular data-interchange format and supported by a lot of script languages. On AutoIt, there is already a >JSON UDF written by Gabriel Boehme. It is good but too slow, and not supports unicode and control characters very well. So I write a new one (and of course, fast one as usual). I use a machine code version of JSON parser called "jsmn". jsmn not only supports standard JSON, but also accepts some non-strict JSON string. See below for example. Important Update!! I rename the library from jsmn.au3 to json.au3. All function names are changed, too. Decoding Function Json_Decode($Json) $Json can be a standard or non-standard JSON string. For example, it accepts: { server: example.com port: 80 message: "this looks like a config file" } The most JSON data type will be decoded into corresponding AutoIt variable, including 1D array, string, number, true, false, and null. JSON object will be decoded into "Windows Scripting Dictionary Object" retuned from ObjCreate("Scripting.Dictionary"). AutoIt build-in functions like IsArray, IsBool, etc. can be used to check the returned data type. But for Object and Null, Json_IsObject() and Json_IsNull() should be used. If the input JSON string is invalid, @Error will be set to $JSMN_ERROR_INVAL. And if the input JSON string is not finish (maybe read from stream?), @Error will be set to $JSMN_ERROR_PART.Encoding Function Json_Encode($Data, $Option = 0, $Indent = "\t", $ArraySep = ",\r\n", $ObjectSep = ",\r\n", $ColonSep = ": ") $Data can be a string, number, bool, keyword(default or null), 1D arrry, or "Scripting.Dictionary" COM object. Ptr will be converted to number, Binary will be converted to string in UTF8 encoding. Other unsupported types like 2D array, dllstruct or object will be encoded into null. $Option is bitmask consisting following constant: $JSON_UNESCAPED_ASCII ; Don't escape ascii charcters between chr(1) ~ chr(0x1f) $JSON_UNESCAPED_UNICODE ; Encode multibyte Unicode characters literally $JSON_UNESCAPED_SLASHES ; Don't escape / $JSON_HEX_TAG ; All < and > are converted to \u003C and \u003E $JSON_HEX_AMP ; All &amp;amp;amp;s are converted to \u0026 $JSON_HEX_APOS ; All ' are converted to \u0027 $JSON_HEX_QUOT ; All " are converted to \u0022 $JSON_PRETTY_PRINT ; Use whitespace in returned data to format it $JSON_STRICT_PRINT ; Make sure returned JSON string is RFC4627 compliant $JSON_UNQUOTED_STRING ; Output unquoted string if possible (conflicting with $JSMN_STRICT_PRINT) Most encoding option have the same means like PHP's json_enocde() function. When $JSON_PRETTY_PRINT is set, output format can be change by other 4 parameters ($Indent, $ArraySep, $ObjectSep, and $ColonSep). Because these 4 output format parameters will be checked inside Jsmn_Encode() function, returned string will be always accepted by Jsmn_Decode(). $JSON_UNQUOTED_STRING can be used to output unquoted string that also accetped by Jsmn_Decode(). $JSON_STRICT_PRINT is used to check output format setting and avoid non-standard JSON output. So this option is conflicting with $JSON_UNQUOTED_STRING.Get and Put Functions Json_Put(ByRef $Var, $Notation, $Data, $CheckExists = False) Json_Get(ByRef $Var, $Notation) These functions helps user to access object or array more easily. Both dot notation and square bracket notation can be supported. Json_Put() by default will create non-exists objects and arrays. For example: Local $Obj Json_Put($Obj, ".foo", "foo") Json_Put($Obj, ".bar[0]", "bar") Json_Put($Obj, ".test[1].foo.bar[2].foo.bar", "Test") Local $Test = Json_Get($Obj, '["test"][1]["foo"]["bar"][2]["foo"]["bar"]') ; "Test" Object Help Functions Json_ObjCreate() Json_ObjPut(ByRef $Object, $Key, $Value) Json_ObjGet(ByRef $Object, $Key) Json_ObjDelete(ByRef $Object, $Key) Json_ObjExists(ByRef $Object, $Key) Json_ObjGetCount(ByRef $Object) Json_ObjGetKeys(ByRef $Object) Json_ObjClear(ByRef $Object) These functions are just warps of "Scripting.Dictionary" COM object. You can use these functions if you are not already familiar with it. == Update 2013/05/19 == * Add Jsmn_Encode() option "$JSMN_UNESCAPED_ASCII". Now the default output of Json_Encode() is exactly the same as PHP's json_encode() function (for example, chr(1) will be encoded into u0001). $JSON_UNESCAPED_ASCII ; Don't escape ascii charcters between chr(1) ~ chr(0x1f) == Update 2015/01/08 == * Rename the library from jsmn.au3 to json.au3. All function names are changed, too. * Add Json_Put() and Json_Get() * Add Null support * Using BinaryCall.au3 to loading the machine code. == Update 2018/01/13== (Jos) * Add JsonDump() to list all Json Keys and their values to easily figure out what they are. == Update 2018/10/01== (Jos) * Fixed JsonDump() some fields and values were not showing as discussed here - tnx @TheXman . == Update 2018/10/01b== (Jos) * Added Json_ObjGetItems, Tidied source and fixed au3check warnings - tnx @TheXman . == Update 2018/10/28== (Jos) * Added declaration for $value to avoid au3check warning - tnx @DerPensionist == Update 2018/12/16== (Jos) * Added another declaration for $value to avoid au3check warning and updated the version at the top - tnx @maniootek == Update 2018/12/29== (Jos) * Changed Json_ObjGet() and Json_ObjExists() to allow for multilevel object in string. == Update 2019/01/17== (Jos) * Added support for DOT notation in JSON functions. == Update 2019/07/15== (Jos) * Added support for reading keys with a dot inside when using a dot as separator (updated) == Update 2021/11/18== (TheXman) * Update details in below post: == Update 2021/11/20== (TheXman) * Minor RegEx update, no change to the functionality or result._Json(2021.11.20).zip Edited November 20, 2021 by Jos ValeryVal, shotiko, Skysnake and 30 others 27 6 新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了。 Link to comment Share on other sites More sharing options...
Mat Posted February 7, 2013 Share Posted February 7, 2013 Taz77 1 AutoIt Project Listing Link to comment Share on other sites More sharing options...
whizter Posted March 24, 2013 Share Posted March 24, 2013 Hey,thanks for the UDF, good work. But I have problems with a specific json source -> http://data.mtgox.com/api/1/BTCUSD/depthI 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 EndFuncIt works on every other API without problems, just not with this one. Taz77 1 Link to comment Share on other sites More sharing options...
Ward Posted March 28, 2013 Author Share Posted March 28, 2013 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. Taz77 1 新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了。 Link to comment Share on other sites More sharing options...
savain Posted April 11, 2013 Share Posted April 11, 2013 What for an impolite user! Thanks it works very fine! Randomly, I need it for Mt. Gox Too Taz77 1 Link to comment Share on other sites More sharing options...
mmscripting Posted May 18, 2013 Share Posted May 18, 2013 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" . 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 Taz77 1 Link to comment Share on other sites More sharing options...
Ward Posted May 18, 2013 Author Share Posted May 18, 2013 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) Taz77 1 新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了。 Link to comment Share on other sites More sharing options...
mmscripting Posted May 19, 2013 Share Posted May 19, 2013 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 ! Regards mmscripting Taz77 1 Link to comment Share on other sites More sharing options...
guinness Posted May 19, 2013 Share Posted May 19, 2013 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. Taz77 1 UDF List: _AdapterConnections() • _AlwaysRun() • _AppMon() • _AppMonEx() • _ArrayFilter/_ArrayReduce • _BinaryBin() • _CheckMsgBox() • _CmdLineRaw() • _ContextMenu() • _ConvertLHWebColor()/_ConvertSHWebColor() • _DesktopDimensions() • _DisplayPassword() • _DotNet_Load()/_DotNet_Unload() • _Fibonacci() • _FileCompare() • _FileCompareContents() • _FileNameByHandle() • _FilePrefix/SRE() • _FindInFile() • _GetBackgroundColor()/_SetBackgroundColor() • _GetConrolID() • _GetCtrlClass() • _GetDirectoryFormat() • _GetDriveMediaType() • _GetFilename()/_GetFilenameExt() • _GetHardwareID() • _GetIP() • _GetIP_Country() • _GetOSLanguage() • _GetSavedSource() • _GetStringSize() • _GetSystemPaths() • _GetURLImage() • _GIFImage() • _GoogleWeather() • _GUICtrlCreateGroup() • _GUICtrlListBox_CreateArray() • _GUICtrlListView_CreateArray() • _GUICtrlListView_SaveCSV() • _GUICtrlListView_SaveHTML() • _GUICtrlListView_SaveTxt() • _GUICtrlListView_SaveXML() • _GUICtrlMenu_Recent() • _GUICtrlMenu_SetItemImage() • _GUICtrlTreeView_CreateArray() • _GUIDisable() • _GUIImageList_SetIconFromHandle() • _GUIRegisterMsg() • _GUISetIcon() • _Icon_Clear()/_Icon_Set() • _IdleTime() • _InetGet() • _InetGetGUI() • _InetGetProgress() • _IPDetails() • _IsFileOlder() • _IsGUID() • _IsHex() • _IsPalindrome() • _IsRegKey() • _IsStringRegExp() • _IsSystemDrive() • _IsUPX() • _IsValidType() • _IsWebColor() • _Language() • _Log() • _MicrosoftInternetConnectivity() • _MSDNDataType() • _PathFull/GetRelative/Split() • _PathSplitEx() • _PrintFromArray() • _ProgressSetMarquee() • _ReDim() • _RockPaperScissors()/_RockPaperScissorsLizardSpock() • _ScrollingCredits • _SelfDelete() • _SelfRename() • _SelfUpdate() • _SendTo() • _ShellAll() • _ShellFile() • _ShellFolder() • _SingletonHWID() • _SingletonPID() • _Startup() • _StringCompact() • _StringIsValid() • _StringRegExpMetaCharacters() • _StringReplaceWholeWord() • _StringStripChars() • _Temperature() • _TrialPeriod() • _UKToUSDate()/_USToUKDate() • _WinAPI_Create_CTL_CODE() • _WinAPI_CreateGUID() • _WMIDateStringToDate()/_DateToWMIDateString() • Au3 script parsing • AutoIt Search • AutoIt3 Portable • AutoIt3WrapperToPragma • AutoItWinGetTitle()/AutoItWinSetTitle() • Coding • DirToHTML5 • FileInstallr • FileReadLastChars() • GeoIP database • GUI - Only Close Button • GUI Examples • GUICtrlDeleteImage() • GUICtrlGetBkColor() • GUICtrlGetStyle() • GUIEvents • GUIGetBkColor() • Int_Parse() & Int_TryParse() • IsISBN() • LockFile() • Mapping CtrlIDs • OOP in AutoIt • ParseHeadersToSciTE() • PasswordValid • PasteBin • Posts Per Day • PreExpand • Protect Globals • Queue() • Resource Update • ResourcesEx • SciTE Jump • Settings INI • SHELLHOOK • Shunting-Yard • Signature Creator • Stack() • Stopwatch() • StringAddLF()/StringStripLF() • StringEOLToCRLF() • VSCROLL • WM_COPYDATA • More Examples... Updated: 22/04/2018 Link to comment Share on other sites More sharing options...
Ward Posted May 23, 2013 Author Share Posted May 23, 2013 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: expandcollapse popup#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, Taz77 and Danyfirex 3 新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了。 Link to comment Share on other sites More sharing options...
Fly By Night Posted May 27, 2013 Share Posted May 27, 2013 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. Taz77 1 Link to comment Share on other sites More sharing options...
Ward Posted May 28, 2013 Author Share Posted May 28, 2013 Using Jsmn_Get(), it's easy. I will put this function into the UDF later. expandcollapse popup#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 Taz77 1 新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了。 Link to comment Share on other sites More sharing options...
Fly By Night Posted May 28, 2013 Share Posted May 28, 2013 (edited) 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 May 28, 2013 by Fly By Night Taz77 1 Link to comment Share on other sites More sharing options...
JRSmile Posted May 29, 2013 Share Posted May 29, 2013 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. Taz77 1 $a=StringSplit("547275737420796F757220546563686E6F6C75737421","") For $b=1 To UBound($a)+(-1*-1*-1)step(2^4/8);&$b+=1*2/40*µ&Asc(4) Assign("c",Eval("c")&Chr(Dec($a[$b]&$a[$b+1])));''Chr("a")&"HI" Next ;time_U&r34d,ths,U-may=get$the&c.l.u.e;b3st-regards,JRSmile; MsgBox(0x000000,"",Eval("c"));PiEs:d0nt+*b3.s4d.4ft3r.1st-try:-) Link to comment Share on other sites More sharing options...
robertcollier4 Posted May 29, 2013 Share Posted May 29, 2013 Can it be possible to use put and get via JSON Dot Notation? Taz77 1 Link to comment Share on other sites More sharing options...
Fly By Night Posted June 1, 2013 Share Posted June 1, 2013 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 Taz77 1 Link to comment Share on other sites More sharing options...
Ward Posted June 1, 2013 Author Share Posted June 1, 2013 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. Taz77 1 新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了。 Link to comment Share on other sites More sharing options...
Fly By Night Posted June 1, 2013 Share Posted June 1, 2013 (edited) 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 June 2, 2013 by Fly By Night Taz77 1 Link to comment Share on other sites More sharing options...
santaryan Posted July 6, 2013 Share Posted July 6, 2013 (edited) 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. expandcollapse popup; #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 July 6, 2013 by santaryan Taz77 1 Link to comment Share on other sites More sharing options...
level20peon Posted November 3, 2013 Share Posted November 3, 2013 (edited) 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 November 3, 2013 by level20peon Taz77 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now