Page 1 of 1 1
Topic Options
#213332 - 2018-06-05 02:13 AM JSON parsing
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4350
Loc: New Jersey
Does anyone have any ideas about parsing JSON response strings in Kix?

The JScript libraries that I've looked at don't seem to provide what I'm looking for, or maybe I'm just misunderstanding how this works.

I get one of four data formats as a response -
  • A Status response with 3 values in 1 section,
  • A Data response with the same status data plus a data section with 1+ values,
  • An Array response, again with the same status data, plus 1 or more sets of data values,
  • A "complex" response that has the status and data sections, with one or more sub-sections, some of which can contain arrays of data sets.

The standard JSON library allows me to specify a section[:subsection:]Value and get the data for that one value. This seems like an awfully difficult way to parse the response. I'd like to get a single element (by name), a "business record" (array) - either the entire status or data record, a specific data record in an array of records, or - for an array response, a list of data fields for a specific matching field.

Any ideas would be appreciated!

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#213339 - 2018-06-05 01:33 PM Re: JSON parsing [Re: Glenn Barnas]
BradV Offline
Seasoned Scripter
****

Registered: 2006-08-16
Posts: 684
Loc: Maryland, USA
Hi Glenn,

Not in kixtart, but powershell could be the answer. ConvertFrom-JSON. I know in Linux python or perl are the recommended ways to manipulate JSON.

Regards,

Brad

Top
#213342 - 2018-06-05 06:33 PM Re: JSON parsing [Re: BradV]
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4350
Loc: New Jersey
Yeah - just had a conversation with our lead developer about this. Going to try that this afternoon - thanks! I'll need to re-think how I wanted to use the data a bit..

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#213346 - 2018-06-07 12:05 AM Re: JSON parsing [Re: Glenn Barnas]
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4350
Loc: New Jersey
Success - for my needs at least! I'm able to parse the JSON into an array of element IDs and data that I can easily read from Kix, using only native Kix functions. I can get a specific data item, an array of data from a business record, and an array of items from an array response.

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#213348 - 2018-06-07 01:55 PM Re: JSON parsing [Re: Glenn Barnas]
BradV Offline
Seasoned Scripter
****

Registered: 2006-08-16
Posts: 684
Loc: Maryland, USA
Would be interested to see how you achieved it?
Top
#213349 - 2018-06-07 04:08 PM Re: JSON parsing [Re: BradV]
Glenn Barnas Administrator Offline
KiX Supporter
*****

Registered: 2003-01-28
Posts: 4350
Loc: New Jersey
It's part of a proprietary application, so I can't post it fully, but the gist of the solution is converting the JSON input into a two-dimensional array, then parsing that array for a match.

Typical JSON is a collection of objects, referenced as "section.subsection.index.item" - subsection and index are optional and there can be multiple levels of subsections. "Index" represents an element in a sub-collection (an array of items) and can occur at any level.

Parsing the response, I turn it into a string in the first index of a 2-dimensional array - "root.computer.#.hostname", with the data in the second index - "My PC". I can then scan the array for an "object reference", which will return the data from the second index if the request is matched in the first index. - it returns a simple string with the data.

I can also make a request like "root.computer.*.hostname" and it will return a simple array of all the hostnames in the collection. It's smart enough to not match "root.computer.site2.*.hostname".

Finally, I can request the object reference "root.computer.3." - this will return a 2-dimensional array of Value:Data pairs - an entire business record - field name in the 0 index and data in the 1 index per row.

I don't think it can be considered "true" JSON parsing, but it gives me what I need in my application. I'm going to use a different function to return the structure, no data, if that becomes necessary. The part I struggled with is creating a true object reference. Once I saw how PowerShell was parsing it, I was able to develop a reasonable alternative.

Glenn
_________________________
Actually I am a Rocket Scientist! \:D

Top
#213352 - 2018-06-07 09:52 PM Re: JSON parsing [Re: Glenn Barnas]
Arend_ Moderator Offline
MM club member
*****

Registered: 2005-01-17
Posts: 1887
Loc: Hilversum, The Netherlands
This looks promising
Top
#213982 - 2021-03-22 05:34 AM Re: JSON parsing [Re: Arend_]
AndreLuiz Offline
Getting the hang of it

Registered: 2015-10-07
Posts: 89
Loc: Brasil, Joo pessoa
Sorry to be reliving an old post.

But I had found these vbs-json mentioned above these days, and I decided to try to use it in KiXtart, and working with it pure is a little bad, due to the arrays, it gives an error of expression.

But then I generated a simple function to manipulate the dictionary.
In conclusion, for reading Json, it works very well, all that is missing is an easy way to change the data contained in the dictionary.

If you want to modify the script, you can feel free.

 PHP:
Break on $=SetOption(Explicit, on) Global $__JsonClass__[1] Gosub Instance Main() quit 0 Function Main() Dim $JsonLocal $JsonLocal=' { "test1": "ola", "test2": { "hello": "world" }, "Peoples": [ { "Name": "Andre", "Age": 23, "Types": [ { "Value": 0 }, { "Value": 1 }, { "Value": 2.3 } ] }, { "Name": "Milca", "Age": 25, "Types": [ { "Value": true }, { "Value": null }, { "Value": [ { "v": "Esse o valor 1" }, { "v": "Esse o valor 2" } ] } ] } ] } ' dim $j, $t1, $t2, $t3, $t4, $t5, $t6, $t7, $t8, $t9 $j = JsonDecode($JsonLocal) ???? $t1 = #($j, 'test1') $t1'('VarTypeName($t1)')'? $t2 = #($j, 'test2.hello')? $t2'('VarTypeName($t2)')'? $t3 = #($j, 'Peoples[1].Name')? $t3'('VarTypeName($t3)')'? $t4 = #($j, 'Peoples[1].Types[0].Value')? $t4'('VarTypeName($t4)')'? $t5 = #($j, 'Peoples[1].Types[1].Value')? $t5'('VarTypeName($t5)')'? $t6 = #($j, 'Peoples[1].Types[2].Value[0].v')? $t6'('VarTypeName($t6)')'? $t7 = #($j, 'Peoples[1].Types[2].Value[1].v')? $t7'('VarTypeName($t7)')'? $t8 = #($j, 'Peoples[0].Age')? $t8'('VarTypeName($t8)')'? $t9 = #($j, 'Peoples[0].Types[2].Value')? $t9'('VarTypeName($t9)')'? Get$ EndFunction Function JsonDecode($JsonStr) $JsonDecode = $__JsonClass__[1].Decode($JsonStr) EndFunction Function JsonEncode($Obj) $JsonEncode = $__JsonClass__[1].Encode($Obj) EndFunction Function #($ObjectJson, optional $Path) Dim $Prop, $Propertys, $PartProperty[1] $Propertys = split($Path, '.') $PartProperty[0] = subStr($Propertys[0], 1, inStr($Propertys[0], '[')-1) $PartProperty[0] = iIf(trim($PartProperty[0]) = '', $Propertys[0],subStr($Propertys[0], 1, inStr($Propertys[0], '[')-1)) $PartProperty[1] = subStr($Propertys[0], inStr($Propertys[0], '[')) $# = $ObjectJson.item($PartProperty[0]) $Path = join($Propertys, '.') $Path = subStr($Path, inStr($Path, '.')+1) If (varTypeName($#) = "Variant[]") $=execute('$# = $#'+$PartProperty[1]) EndIf If (varTypeName($#) = "Object") $# = #($#, $Path) EndIf EndFunction :Instance $__JsonClass__[0] = CreateObject("ScriptControl") $__JsonClass__[0].Language = "VBScript" $__JsonClass__[0].AddCode( 'Class VbsJson REM Author: Demon REM Date: 2012/5/3 REM Website: http://demon.tw Private Whitespace, NumberRegex, StringChunk Private b, f, r, n, t Private Sub Class_Initialize Whitespace = " " & vbTab & vbCr & vbLf b = ChrW(8) f = vbFormFeed r = vbCr n = vbLf t = vbTab Set NumberRegex = New RegExp NumberRegex.Pattern = "(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?" NumberRegex.Global = False NumberRegex.MultiLine = True NumberRegex.IgnoreCase = True Set StringChunk = New RegExp StringChunk.Pattern = "([\s\S]*?)([""\\\x00-\x1f])" StringChunk.Global = False StringChunk.MultiLine = True StringChunk.IgnoreCase = True End Sub REM Return a JSON string representation of a VBScript data structure REM Supports the following objects and types REM +-------------------+---------------+ REM | VBScript | JSON | REM +===================+===============+ REM | Dictionary | object | REM +-------------------+---------------+ REM | Array | array | REM +-------------------+---------------+ REM | String | string | REM +-------------------+---------------+ REM | Number | number | REM +-------------------+---------------+ REM | True | true | REM +-------------------+---------------+ REM | False | false | REM +-------------------+---------------+ REM | Null | null | REM +-------------------+---------------+ Public Function Encode(ByRef obj) Dim buf, i, c, g Set buf = CreateObject("Scripting.Dictionary") Select Case VarType(obj) Case vbNull buf.Add buf.Count, "null" Case vbBoolean If obj Then buf.Add buf.Count, "true" Else buf.Add buf.Count, "false" End If Case vbInteger, vbLong, vbSingle, vbDouble buf.Add buf.Count, Replace(obj, ",", ".") Case vbString buf.Add buf.Count, """" For i = 1 To Len(obj) c = Mid(obj, i, 1) Select Case c Case """" buf.Add buf.Count, "\""" Case "\" buf.Add buf.Count, "\\" Case "/" buf.Add buf.Count, "/" Case b buf.Add buf.Count, "\b" Case f buf.Add buf.Count, "\f" Case r buf.Add buf.Count, "\r" Case n buf.Add buf.Count, "\n" Case t buf.Add buf.Count, "\t" Case Else If AscW(c) >= 0 And AscW(c) <= 31 Then c = Right("0" & Hex(AscW(c)), 2) buf.Add buf.Count, "\u00" & c Else buf.Add buf.Count, c End If End Select Next buf.Add buf.Count, """" Case vbArray + vbVariant g = True buf.Add buf.Count, "[" For Each i In obj If g Then g = False Else buf.Add buf.Count, "," buf.Add buf.Count, Encode(i) Next buf.Add buf.Count, "]" Case vbObject If TypeName(obj) = "Dictionary" Then g = True buf.Add buf.Count, "{" For Each i In obj If g Then g = False Else buf.Add buf.Count, "," buf.Add buf.Count, """" & i & """" & ":" & Encode(obj(i)) Next buf.Add buf.Count, "}" Else Err.Raise 8732,,"None dictionary object" End If Case Else buf.Add buf.Count, """" & CStr(obj) & """" End Select Encode = Join(buf.Items, "") End Function REM Return the VBScript representation of str( REM Performs the following translations in decoding REM +---------------+-------------------+ REM | JSON | VBScript | REM +===============+===================+ REM | object | Dictionary | REM +---------------+-------------------+ REM | array | Array | REM +---------------+-------------------+ REM | string | String | REM +---------------+-------------------+ REM | number | Double | REM +---------------+-------------------+ REM | true | True | REM +---------------+-------------------+ REM | false | False | REM +---------------+-------------------+ REM | null | Null | REM +---------------+-------------------+ Public Function Decode(ByRef str) Dim idx idx = SkipWhitespace(str, 1) If Mid(str, idx, 1) = "{" Then Set Decode = ScanOnce(str, 1) Else Decode = ScanOnce(str, 1) End If End Function Private Function ScanOnce(ByRef str, ByRef idx) Dim c, ms idx = SkipWhitespace(str, idx) c = Mid(str, idx, 1) If c = "{" Then idx = idx + 1 Set ScanOnce = ParseObject(str, idx) Exit Function ElseIf c = "[" Then idx = idx + 1 ScanOnce = ParseArray(str, idx) Exit Function ElseIf c = """" Then idx = idx + 1 ScanOnce = ParseString(str, idx) Exit Function ElseIf c = "n" And StrComp("null", Mid(str, idx, 4)) = 0 Then idx = idx + 4 ScanOnce = Null Exit Function ElseIf c = "t" And StrComp("true", Mid(str, idx, 4)) = 0 Then idx = idx + 4 ScanOnce = True Exit Function ElseIf c = "f" And StrComp("false", Mid(str, idx, 5)) = 0 Then idx = idx + 5 ScanOnce = False Exit Function End If Set ms = NumberRegex.Execute(Mid(str, idx)) If ms.Count = 1 Then idx = idx + ms(0).Length ScanOnce = Eval(ms(0)) Exit Function End If Err.Raise 8732,,"No JSON object could be ScanOnced" End Function Private Function ParseObject(ByRef str, ByRef idx) Dim c, key, value Set ParseObject = CreateObject("Scripting.Dictionary") idx = SkipWhitespace(str, idx) c = Mid(str, idx, 1) If c = "}" Then Exit Function ElseIf c <> """" Then Err.Raise 8732,,"Expecting property name" End If idx = idx + 1 Do key = ParseString(str, idx) idx = SkipWhitespace(str, idx) If Mid(str, idx, 1) <> ":" Then Err.Raise 8732,,"Expecting : delimiter" End If idx = SkipWhitespace(str, idx + 1) If Mid(str, idx, 1) = "{" Then Set value = ScanOnce(str, idx) Else value = ScanOnce(str, idx) End If ParseObject.Add key, value idx = SkipWhitespace(str, idx) c = Mid(str, idx, 1) If c = "}" Then Exit Do ElseIf c <> "," Then Err.Raise 8732,,"Expecting , delimiter" End If idx = SkipWhitespace(str, idx + 1) c = Mid(str, idx, 1) If c <> """" Then Err.Raise 8732,,"Expecting property name" End If idx = idx + 1 Loop idx = idx + 1 End Function Private Function ParseArray(ByRef str, ByRef idx) Dim c, values, value Set values = CreateObject("Scripting.Dictionary") idx = SkipWhitespace(str, idx) c = Mid(str, idx, 1) If c = "]" Then ParseArray = values.Items Exit Function End If Do idx = SkipWhitespace(str, idx) If Mid(str, idx, 1) = "{" Then Set value = ScanOnce(str, idx) Else value = ScanOnce(str, idx) End If values.Add values.Count, value idx = SkipWhitespace(str, idx) c = Mid(str, idx, 1) If c = "]" Then Exit Do ElseIf c <> "," Then Err.Raise 8732,,"Expecting , delimiter" End If idx = idx + 1 Loop idx = idx + 1 ParseArray = values.Items End Function Private Function ParseString(ByRef str, ByRef idx) Dim chunks, content, terminator, ms, esc, char Set chunks = CreateObject("Scripting.Dictionary") Do Set ms = StringChunk.Execute(Mid(str, idx)) If ms.Count = 0 Then Err.Raise 8732,,"Unterminated string starting" End If content = ms(0).Submatches(0) terminator = ms(0).Submatches(1) If Len(content) > 0 Then chunks.Add chunks.Count, content End If idx = idx + ms(0).Length If terminator = """" Then Exit Do ElseIf terminator <> "\" Then Err.Raise 8732,,"Invalid control character" End If esc = Mid(str, idx, 1) If esc <> "u" Then Select Case esc Case """" char = """" Case "\" char = "\" Case "/" char = "/" Case "b" char = b Case "f" char = f Case "n" char = n Case "r" char = r Case "t" char = t Case Else Err.Raise 8732,,"Invalid escape" End Select idx = idx + 1 Else char = ChrW("&H" & Mid(str, idx + 1, 4)) idx = idx + 5 End If chunks.Add chunks.Count, char Loop ParseString = Join(chunks.Items, "") End Function Private Function SkipWhitespace(ByRef str, ByVal idx) Do While idx <= Len(str) And _ InStr(Whitespace, Mid(str, idx, 1)) > 0 idx = idx + 1 Loop SkipWhitespace = idx End Function End Class') $__JsonClass__[1] = $__JsonClass__[0].Eval('new VbsJson') Return

Top
#213984 - 2021-03-24 06:23 AM Re: JSON parsing [Re: AndreLuiz]
NTDOC Administrator Offline
Administrator
*****

Registered: 2000-07-28
Posts: 11611
Loc: CA
Not something I have a personal current need for but I do thank you for your submission and feedback @andreluiz always good to have new discussions and it may very well be exactly what someone is looking for.
Top
Page 1 of 1 1


Moderator:  Jochen, Allen, Radimus, Glenn Barnas, ShaneEP, Ruud van Velsen, Arend_, Mart 
Hop to:
Shout Box

Who's Online
0 registered and 304 anonymous users online.
Newest Members
Praveer, Ollero, rayyo, Foxlicht, DonChild
17742 Registered Users

Generated in 0.035 seconds in which 0.013 seconds were spent on a total of 13 queries. Zlib compression enabled.

Search the board with:
superb Board Search
or try with google:
Google
Web kixtart.org