example.txt includes:
Code: Select all
[{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
Code: Select all
FileRead, exampleFile, ../example.txt
MsgBox % exampleFile
Code: Select all
[{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
Code: Select all
FileRead, exampleFile, ../example.txt
MsgBox % exampleFile
Code: Select all
Fileread, var, example.txt
msgbox % var ; var contains a string
obj := Jxon_load(var) ; Jxon_Load loads the string into an AHK object
msgbox % obj[1].container.spec1 " , but " obj[1].container.spec2
; Coco's Jxon_Load function: https://github.com/cocobelgica/AutoHotkey-JSON/blob/master/Jxon.ahk
Jxon_Load(ByRef src, args*)
{
static q := Chr(34)
key := "", is_key := false
stack := [ tree := [] ]
is_arr := { (tree): 1 }
next := q . "{[01234567890-tfn"
pos := 0
while ( (ch := SubStr(src, ++pos, 1)) != "" )
{
if InStr(" `t`n`r", ch)
continue
if !InStr(next, ch, true)
{
ln := ObjLength(StrSplit(SubStr(src, 1, pos), "`n"))
col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1))
msg := Format("{}: line {} col {} (char {})"
, (next == "") ? ["Extra data", ch := SubStr(src, pos)][1]
: (next == "'") ? "Unterminated string starting at"
: (next == "\") ? "Invalid \escape"
: (next == ":") ? "Expecting ':' delimiter"
: (next == q) ? "Expecting object key enclosed in double quotes"
: (next == q . "}") ? "Expecting object key enclosed in double quotes or object closing '}'"
: (next == ",}") ? "Expecting ',' delimiter or object closing '}'"
: (next == ",]") ? "Expecting ',' delimiter or array closing ']'"
: [ "Expecting JSON value(string, number, [true, false, null], object or array)"
, ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1]
, ln, col, pos)
throw Exception(msg, -1, ch)
}
is_array := is_arr[obj := stack[1]]
if i := InStr("{[", ch)
{
val := (proto := args[i]) ? new proto : {}
is_array? ObjPush(obj, val) : obj[key] := val
ObjInsertAt(stack, 1, val)
is_arr[val] := !(is_key := ch == "{")
next := q . (is_key ? "}" : "{[]0123456789-tfn")
}
else if InStr("}]", ch)
{
ObjRemoveAt(stack, 1)
next := stack[1]==tree ? "" : is_arr[stack[1]] ? ",]" : ",}"
}
else if InStr(",:", ch)
{
is_key := (!is_array && ch == ",")
next := is_key ? q : q . "{[0123456789-tfn"
}
else ; string | number | true | false | null
{
if (ch == q) ; string
{
i := pos
while i := InStr(src, q,, i+1)
{
val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C")
static end := A_AhkVersion<"2" ? 0 : -1
if (SubStr(val, end) != "\")
break
}
if !i ? (pos--, next := "'") : 0
continue
pos := i ; update pos
val := StrReplace(val, "\/", "/")
, val := StrReplace(val, "\" . q, q)
, val := StrReplace(val, "\b", "`b")
, val := StrReplace(val, "\f", "`f")
, val := StrReplace(val, "\n", "`n")
, val := StrReplace(val, "\r", "`r")
, val := StrReplace(val, "\t", "`t")
i := 0
while i := InStr(val, "\",, i+1)
{
if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0
continue 2
; \uXXXX - JSON unicode escape sequence
xxxx := Abs("0x" . SubStr(val, i+2, 4))
if (A_IsUnicode || xxxx < 0x100)
val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6)
}
if is_key
{
key := val, next := ":"
continue
}
}
else ; number | true | false | null
{
val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos)
; For numerical values, numerify integers and keep floats as is.
; I'm not yet sure if I should numerify floats in v2.0-a ...
static number := "number", integer := "integer"
if val is %number%
{
if val is %integer%
val += 0
}
; in v1.1, true,false,A_PtrSize,A_IsUnicode,A_Index,A_EventInfo,
; SOMETIMES return strings due to certain optimizations. Since it
; is just 'SOMETIMES', numerify to be consistent w/ v2.0-a
else if (val == "true" || val == "false")
val := %value% + 0
; AHK_H has built-in null, can't do 'val := %value%' where value == "null"
; as it would raise an exception in AHK_H(overriding built-in var)
else if (val == "null")
val := ""
; any other values are invalid, continue to trigger error
else if (pos--, next := "#")
continue
pos += i-1
}
is_array? ObjPush(obj, val) : obj[key] := val
next := obj==tree ? "" : is_array ? ",]" : ",}"
}
}
return tree[1]
}
Code: Select all
JSON = [{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
arr := JsonToAhkObj(JSON)
MsgBox, % arr[1].container.spec2
JsonToAhkObj(json, flag := "") {
static doc, JS := JsonToAhkObj("")
if (json = "") {
doc := ComObjCreate("htmlfile")
doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
JS := doc.parentWindow
JScript =
(
Object.prototype.GetKeys = function () {
var keys = []
for (var k in this)
if (this.hasOwnProperty(k))
keys.push(k)
return keys
}
Object.prototype.IsArray = function () {
var toStandardString = {}.toString
return toStandardString.call(this) == '[object Array]'
}
)
JS.eval.(JScript)
Return JS
}
else if !flag {
try jsObj := JS.eval("(" json ")")
catch {
MsgBox, Wrong JSON string:`n`n%json%
Return
}
Return JsonToAhkObj(jsObj, true)
}
else {
res := json.IsArray()
if (res = "")
Return json
else if (res = -1) {
obj := []
Loop % json.length
obj[A_Index] := JsonToAhkObj(json[A_Index - 1], true)
}
else if (res = 0) {
obj := {}
keys := json.GetKeys()
Loop % keys.length
k := keys[A_Index - 1], obj[k] := JsonToAhkObj(json[k], true)
}
Return obj
}
}
Can you provide a more simple example to demonstrate an error?
Code: Select all
JsonToAHK(json, rec := false) {
static doc := ComObjCreate("htmlfile")
, __ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
, JS := doc.parentWindow
if !rec
obj := %A_ThisFunc%(JS.eval("(" . json . ")"), true)
else if !IsObject(json)
obj := json
else if JS.Object.prototype.toString.call(json) == "[object Array]" {
obj := []
Loop % json.length
obj.Push( %A_ThisFunc%(json[A_Index - 1], true) )
}
else {
obj := {}
keys := JS.Object.keys(json)
Loop % keys.length {
k := keys[A_Index - 1]
obj[k] := %A_ThisFunc%(json[k], true)
}
}
Return obj
}
Code: Select all
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
JSON = [{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
arr := JsonToAhkObj(JSON)
MsgBox, % arr[1].container.spec2
json= [[["schlank os gut","slim os good",null,null,3,null,null,[[],[]],[[["1814a2c300f02f227bcb04312cd2671a","tea_pt_en_2019q4.md"]],[["4d5e201a34474a12730540dc3bfae9fd","tea_en_de_2020q1.md"]]]]],null,"pt",null,null,[["slim os good",null,[["schlank os gut",0,true,false]],[[0,12]],"slim os good",0,0]],0.6054487,[],[["pt"],null,[0.6054487],["pt"]]]
arr := JsonToAhkObj(JSON)
MsgBox, % arr.1.1.1
JsonToAhkObj(json, flag := "") {
static doc, JS := JsonToAhkObj("")
if (json = "") {
doc := ComObjCreate("htmlfile")
doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
JS := doc.parentWindow
JScript =
(
Object.prototype.GetKeys = function () {
var keys = []
for (var k in this)
if (this.hasOwnProperty(k))
keys.push(k)
return keys
}
Object.prototype.IsArray = function () {
var toStandardString = {}.toString
return toStandardString.call(this) == '[object Array]'
}
)
JS.eval.(JScript)
Return JS
}
else if !flag {
try jsObj := JS.eval("(" json ")")
catch {
MsgBox, Wrong JSON string:`n`n%json%
Return
}
Return JsonToAhkObj(jsObj, true)
}
else {
res := json.IsArray()
if (res = "")
Return json
else if (res = -1) {
obj := []
Loop % json.length
obj[A_Index] := JsonToAhkObj(json[A_Index - 1], true)
}
else if (res = 0) {
obj := {}
keys := json.GetKeys()
Loop % keys.length
k := keys[A_Index - 1], obj[k] := JsonToAhkObj(json[k], true)
}
Return obj
}
}
Code: Select all
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
JSON = [{"container":{"spec1":"this is spec 1", "spec2":"this is spec2"}}]
arr := JsonToAhk(JSON)
MsgBox, % arr[1].container.spec2
json= [[["schlank os gut","slim os good",null,null,3,null,null,[[],[]],[[["1814a2c300f02f227bcb04312cd2671a","tea_pt_en_2019q4.md"]],[["4d5e201a34474a12730540dc3bfae9fd","tea_en_de_2020q1.md"]]]]],null,"pt",null,null,[["slim os good",null,[["schlank os gut",0,true,false]],[[0,12]],"slim os good",0,0]],0.6054487,[],[["pt"],null,[0.6054487],["pt"]]]
arr := JsonToAhk(JSON)
MsgBox, % arr.1.1.1
JsonToAHK(json, rec := false) {
static doc := ComObjCreate("htmlfile")
, __ := doc.write("<meta http-equiv=""X-UA-Compatible"" content=""IE=9"">")
, JS := doc.parentWindow
if !rec
obj := %A_ThisFunc%(JS.eval("(" . json . ")"), true)
else if !IsObject(json)
obj := json
else if JS.Object.prototype.toString.call(json) == "[object Array]" {
obj := []
Loop % json.length
obj.Push( %A_ThisFunc%(json[A_Index - 1], true) )
}
else {
obj := {}
keys := JS.Object.keys(json)
Loop % keys.length {
k := keys[A_Index - 1]
obj[k] := %A_ThisFunc%(json[k], true)
}
}
Return obj
}