Hi Steve,
I'm not sure how you are getting on with this, but I tried the JPARSE function out of interest, and came up with the following code that works on most of the JSON samples I have on hand:
PROGRAM JS.TEST2
$INCLUDE Q.INCLUDES QB.COMMON.H
CRT CLR.SCR:'JSON Testing'
CRT
CALL Q.DIR.LIST('S', 'C:\Temp', 'F':@AM:'*.json', dirlist, emsg)
IF (emsg NE '') THEN
CRT emsg
STOP
END
args = 'JSON files':@AM:'Select file:'
filelist = dirlist<1>
afile = filelist<1, 1>
CALL Q.LISTBOX(dirlist<1>, args, afile, '', '')
IF (afile EQ ESC) THEN STOP
IF (afile EQ '') THEN STOP
fn = 'C:\Temp\':afile
OSREAD json FROM fn ELSE
CRT 'Cannot read file: ':fn
STOP
END
xpos = 41
oktypes = '1,2,3,5'
js = JPARSE(json)
names = ENUMERATE(js)
dcn = DCOUNT(names, @AM)
FOR nno = 1 TO dcn
path = names<nno>
node = js{path}
GOSUB node.parse(path, node)
NEXT nno
STOP
LOCAL SUBROUTINE node.parse((path), (node))
PRIVATE vt
vt = VARTYPE(node)
BEGIN CASE
CASE (LISTINDEX(oktypes, ',', vt))
CRT path:@(xpos):node
CASE (vt EQ VT$NULLVALUE)
CRT path:@(xpos):'null'
CASE (vt EQ VT$COLLECTION)
GOSUB node.parse.collection(path, node)
CASE (vt EQ VT$ARRAY)
GOSUB node.parse.array(path, node)
CASE (1)
CRT path:@(xpos):'Type: ':vt
END CASE
RETURN
END
LOCAL SUBROUTINE node.parse.array((path), (node))
PRIVATE apath, elcnt, elem, elno, eltype
elcnt = INMAT(node)
FOR elno = 1 TO elcnt
elem = node{elno}
apath = path:'[':elno:']'
eltype = VARTYPE(elem)
BEGIN CASE
CASE (LISTINDEX(oktypes, ',', eltype))
CRT apath:@(xpos):elem
CASE (eltype EQ VT$NULLVALUE)
CRT apath:@(xpos):'null'
CASE (eltype EQ VT$COLLECTION)
GOSUB node.parse.collection(apath, elem)
CASE (eltype EQ VT$ARRAY)
GOSUB node.parse.array(apath, elem)
CASE (1)
CRT path:@(xpos):'Type: ':eltype
END CASE
NEXT elno
RETURN
END
LOCAL SUBROUTINE node.parse.collection((path), (node))
PRIVATE cnames, cname, cno, cnode, cpath, ctype, dcc
cnames = ENUMERATE(node)
dcc = DCOUNT(cnames, @AM)
FOR cno = 1 TO dcc
cname = cnames<cno>
cpath = path:'/':cname
cnode = node{cname}
ctype = VARTYPE(cnode)
BEGIN CASE
CASE (LISTINDEX(oktypes, ',', ctype))
CRT cpath:@(xpos):cnode
CASE (ctype EQ VT$NULLVALUE)
CRT cpath:@(xpos):'null'
CASE (ctype EQ VT$COLLECTION)
GOSUB node.parse.collection(cpath, cnode)
CASE (ctype EQ VT$ARRAY)
GOSUB node.parse.array(cpath, cnode)
CASE (1)
CRT path:@(xpos):'Type: ':ctype
END CASE
NEXT cno
RETURN
END
END
You can largely ignore the first 25 lines. That is just getting the list of json files, and getting the user to select one of them. Just make sure you $INCLUDE the SYSCOM KEYS.H file.
You will find (if you haven't found out already), that the collection gets returned in alphabetic order - which is NOT the order of the data contained in the json item.
Hope this helps,
Brian
On Friday 9 February 2024 at 12:15:40 UTC+13 Steve Trimble wrote: