...and while we're on the subject.... below is a modified version of code in a previous reply on this thread. It adds an extra column for element type using a map lookup based on the Extender value types. Although I use Powershell a lot for Json parsing, nothing beats the Extender for iterating a Json tree. The script below works with a large web API Json return but the crTree() function has worked for me with several Json 'schemas' I wished to uncover before writing parsing code. Tony could easily send code for better tree output, but this all goes back to his initial response about understanding how the Extender works.
;Winbatch 2021C - Census Data - tests large json return
;uses WinHttp.WinHttpRequest.5.1 for JSON return
;Stan Littlefield, September 14, 2021
;Updated: September 18, 2021 - based on new Extender using array rather than delimited list
;======================================================================================================
IntControl(73,1,0,0,0)
Gosub udfs
AddExtender("ilcjs44i.dll", 0, "ilcjs64i.dll")
cUrl = "https://api.census.gov/data/2019/acs/acs1/variables.json"
BoxOpen("Parsing:":cUrl,"Please Wait...")
cFile = Dirscript():"CensusAPI.txt"
cJson = Dirscript():"CensusAPI.json"
If FileExist(cFile) Then FileDelete(cFile)
If FileExist(cJson) Then FileDelete(cJson)
request = Createobject("WinHttp.WinHttpRequest.5.1")
request.Open("GET", cUrl, @False )
request.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")
request.SetRequestHeader("Accept", "application/json")
request.Send()
jdata = request.ResponseText
request = 0
;persist .json file
FilePut(cJson,jdata) ;uncomment if needed
;=================================
If jsValid(jdata)
jstypes = crtypes() ;no need for map, not persisting node types
Object = jsParse(jdata)
Drop(jdata)
BoxTitle("Creating text Output ":cFile )
crTree()
;crObj() ;optional test, comment crTree and uncomment this
;results will be disappointing but helps with
;understanding how Extender functions work
jsConClose()
BoxShut()
Message("Json Tree Created",cFile)
Else
jsConClose()
Drop(jdata)
BoxShut()
Message(cJson,"Not Valid Json")
Endif
Exit
:WBERRORHANDLER
geterror()
Terminate(@TRUE,"Error Encountered",errmsg)
Exit
:udfs
#DefineSubRoutine geterror()
wberroradditionalinfo = wberrorarray[6]
lasterr = wberrorarray[0]
handlerline = wberrorarray[1]
textstring = wberrorarray[5]
linenumber = wberrorarray[8]
errmsg = "Error: ":lasterr:@LF:textstring:@LF:"Line (":linenumber:")":@LF:wberroradditionalinfo
Return(errmsg)
#EndSubRoutine
#DefineSubRoutine crTree()
Fx = FileOpen(cFile,"Write")
output = "node":@tab:"value":@tab:"type"
FileWrite(Fx,output)
tree =jsKeyPaths(Object,"")
;tree =jsKeyPaths(Object,"variables")
;just for test
;Message("Variable Type for tree",VarType(tree)) ;would not expect blank return
Cnt = Arrinfo(tree,1)
nMod = Int(Cnt/10)
i=1
ForEach item in tree
If jsValueType(Object,item) <> @JsonObj
output = item:@tab:jsValueGet(Object,item):@tab:jsValueType(Object,item):"(":MapKeyFind(jstypes, jsValueType(Object,item) , '<Unknown>'):")"
If (i mod nMod == 0) Then BoxText("Processing ":i:" of ":Cnt)
FileWrite(Fx,output)
i +=1
If i>10000 Then Break
Endif
Next
FileClose(Fx)
Drop(Fx)
Drop(tree)
Return(1)
#EndSubRoutine
#DefineSubRoutine crObj()
Fx = FileOpen(cFile,"Write")
output = "node":@tab:"value"
FileWrite(Fx,output)
tree =jsKeyPaths(Object,"")
Cnt = Arrinfo(tree,1)
nMod = Int(Cnt/10)
i=1
brk=@False
ForEach item in tree
If jsValueType(Object,item) == @JsonObj
subtree =jsKeyPaths(Object,item)
ForEach subitem in subtree
output = item:@tab:jsValueGet(Object,subitem)
FileWrite(Fx,output)
brk=@True
Next
Endif
If brk Then Break
Next
FileClose(Fx)
Drop(Fx)
Drop(tree)
Return(1)
#EndSubRoutine
#DefineSubRoutine crtypes()
maps = $"1,NULL
2,BOOL
4,NUMBER
8,STRING
16,ARRAY
32,OBJECT
$"
jstypes = MapCreate(maps,",",@lf)
Return(jstypes)
#EndSubRoutine
Return