[SOLVED] How to work with JSON - can't wrap my head around nested struct/array of obj

Just starting out? Need help? Post your questions and find answers here.
User avatar
bembulak
Posts: 103
Joined: Wed Feb 26, 2014 9:53 am

[SOLVED] How to work with JSON - can't wrap my head around nested struct/array of obj

Post by bembulak »

Hi folks,

I hope, you can help me with working with a JSON-structure, as I do not quite understand how to work with the JSON-Library.

The setup:

I do have a PHP-endpoint, which returns the following JSON-object:

Code: Select all

{
    "Category AAA": [
        {
            "id" : 0,
            "Name": "Product A",
            "Punkte": 1,
            "Einheit": "g",
            "Menge": 100,
            "Notiz": "Foo Bar Braz"
        },
        {
            "id" : 1,
            "Name": "Product B",
            "Punkte": 2,
            "Einheit": "pcs",
            "Menge": 2,
            "Notiz": "Dang Ding Dong"
        },
        {
            "id" : 2,
            "Name": "Product C",
            "Punkte": 3,
            "Einheit": "ml",
            "Menge": 30,
            "Notiz": "Erl Ferl Gerl"
        }
    ],
    "Category BBB": [
        {
            "id" : 3,
            "Name": "Product D",
            "Punkte": 4,
            "Einheit": "g",
            "Menge": 10,
            "Notiz": "Hart Smart Fart"
        },
        {
            "id" : 4,
            "Name": "Product E",
            "Punkte": 5,
            "Einheit": "pcs",
            "Menge": 10,
            "Notiz": "Irre Quirre Schmock"
        },
        {
            "id" : 5,
            "Name": "Product F",
            "Punkte": 6,
            "Einheit": "ml",
            "Menge": 1000,
            "Notiz": "Junk Funk Skunk"
        }
    ]
}
I already can manage to retrieve the object with HTTPRequest(), but from there I can't find a way to work with the data.
If I work with very basic / single Key-Value pairs, it's not a problem, but the nesting drives me crazy.

Code: Select all

Enumeration
	#JSON_DATA
EndEndumeration

Procedure loadData(Success, Result$, UserData)
  If Success
    ParseJSON(#JSON_DATA, Result$)
    ObjectValue = JSONValue(#JSON_DATA)
    
    If (JSONMemberKey(ObjectValue) = "Category AAA") 
    ; ==== ????
    EndIf

 Else
    Debug "HTTPRequest(): Error"
 EndIf

EndProcedure

HTTPRequest(#PB_HTTP_Get, "http://test.local/get_data.php", "", @loadData())
How can I, for example, iterate over "Category AAA", not knowing how many products are in it? I assume it's an array, but I can't "debug" through it by the life of me. Any help is highly appreciated.

Edit: See last post for solution.
Last edited by bembulak on Tue Dec 02, 2025 6:01 pm, edited 1 time in total.
Kind regards,

bembulak



SpiderBasic 3.20 beta 2 on Win11, Intel Mac, MX Linux
the.weavster
Posts: 231
Joined: Sat Mar 01, 2014 3:02 pm

Re: How to work with JSON - can't wrap my head around nested struct/array of obj

Post by the.weavster »

How can I, for example, iterate over "Category AAA", not knowing how many products are in it?
I'm not in a position to test this right now but it should give you a pointer even if it's not quite right...

Code: Select all

nCount = JSONArraySize(JSONValue)
i = 0
While i < nCount
	nElement = GetJSONElement(JSONValue, i)
	ExamineJSONMembers(nElement)
	WhileNextJSONMember(nElement)
		Debug JSONMemberKey(nElement)
	Wend
	i + 1
Wend
User avatar
bembulak
Posts: 103
Joined: Wed Feb 26, 2014 9:53 am

Re: How to work with JSON - can't wrap my head around nested struct/array of obj

Post by bembulak »

the.weavster wrote: Sun Nov 30, 2025 9:04 pm
How can I, for example, iterate over "Category AAA", not knowing how many products are in it?
I'm not in a position to test this right now but it should give you a pointer even if it's not quite right...

Code: Select all

nCount = JSONArraySize(JSONValue)
i = 0
While i < nCount
	nElement = GetJSONElement(JSONValue, i)
	ExamineJSONMembers(nElement)
	WhileNextJSONMember(nElement)
		Debug JSONMemberKey(nElement)
	Wend
	i + 1
Wend
Thank you, the.weavster!
Your input was already very helpful. It just made it clear to me, that I have forgotten almost everything I'd ever learned about PB and SB, especially when it comes to basic loops. Note to my self: Yes, sir, you need to increment that i or j in your loops. :oops:

Nevertheless, I still can't wrap my head around it. I do have a XAMPP stack here on my dev-machine. I took the output from it (the original JSON value) and made the following example, to have everything in one place for anyone willing to test:

Code: Select all


Declare.s GetText()
ReturnedText$ = GetText()

Enumeration
  #JSON
EndEnumeration

; GetAnyValue (from Help)
Procedure.s GetAnyValue(Value)
    Select JSONType(Value)
      Case #PB_JSON_Null:    ProcedureReturn "null -> ???"
      Case #PB_JSON_String:  ProcedureReturn GetJSONString(Value)
      Case #PB_JSON_Number:  ProcedureReturn StrD(GetJSONDouble(Value))    
      Case #PB_JSON_Boolean: ProcedureReturn Str(GetJSONBoolean(Value))
      Case #PB_JSON_Array:   ProcedureReturn "array -> use JSONArraySize()"
      Case #PB_JSON_Object:  ProcedureReturn "object -> use ExamineJSONMembers()"
      Default :              ProcedureReturn "Unknown type?"
    EndSelect
EndProcedure
  
  
If ParseJSON(#JSON, ReturnedText$)
  Debug "Parsing Okay. Going ahead." 
  Debug "Valid and initialized (Non-Zerof if okay): " + IsJSON(#JSON) + Chr(13)
  
    ObjectValue = JSONValue(#JSON)
    If ExamineJSONMembers(ObjectValue)
      While NextJSONMember(ObjectValue) ; Iterating over the Categories
        
        If (JSONMemberKey(ObjectValue) = "Category AAA") 
          Debug "Category found. Iterating over it."   
          Debug "    Type is: " + GetAnyValue(JSONMemberValue(ObjectValue)) ; -> Array!
          nCount = JSONArraySize(JSONMemberValue(ObjectValue))
          Debug "    Number of elements in Array: " + nCount
          
          For i=0 To nCount-1 ; Start iterating over the array
            Debug "    Inside the Array."
            nElement = GetJSONElement(JSONMemberValue(ObjectValue), i)
            Debug "    " + GetAnyValue(nElement) ; nElement is the OBJECT inside the Array.
            
            If (ExamineJSONMembers(nElement))
            While NextJSONMember(nElement)
              Debug "        => Inside the Object <="
              Debug "           " + JSONMemberKey(nElement) + " : " + JSONMemberValue(nElement)
              
            Wend ; End of Object
          	EndIf
          	i = i+1
          Next i ; End iterating Array

        EndIf ; End whatever happens inside 'Category AAA'
      
      Wend ; End iterating over categories
    EndIf ; End Examine
  
Else  
  
  Debug "Could not parse JSON"
  Debug JSONErrorLine
  Debug JSONErrorMessage
  Debug JSONErrorPosition
  
EndIf

; ReturnedText$ = GetText() - assume this is comming from http://localhost:8080/script.php
Procedure.s GetText()
  ProcedureReturn  "{" + 
                   Chr(34) + "Category AAA" + Chr(34) + ": [" + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 0," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt A " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 1," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "g " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 100," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Foo Bar Braz " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 1," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt B " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 2," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "stk " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 2," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Dang Ding Dong " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 2," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt C " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 3," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "ml " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 30," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Erl Ferl Gerl " + Chr(34) + "" + 
                   "        }" + 
                   "    ]," + 
                   Chr(34) + "Category BBB" + Chr(34) + ": [" + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 3," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt D " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 4," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "g " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 10," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Hart Smart Fart " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 4," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt E " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 5," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "stk " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 10," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Irre Quirre Schmock " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 5," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt F " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 6," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "ml " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 1000," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Junk Funk Skunk " + Chr(34) + "" + 
                   "        }" + 
                   "    ]" + 
                   "}"
 EndProcedure
However, I do not get the output, I'd expect:

Image

Debug Window:

Code: Select all

Parsing Okay. Going ahead.
Valid and initialized (Non-Zerof if okay): 1

Category found. Iterating over it.
    Type is: array -> use JSONArraySize()
    Number of elements in Array: 3
    Inside the Array.
    object -> use ExamineJSONMembers()
        => Inside the Object <=
           id : [object Object]
        => Inside the Object <=
           Name : [object Object]
        => Inside the Object <=
           Points : [object Object]
        => Inside the Object <=
           Unit : [object Object]
        => Inside the Object <=
           Amount : [object Object]
        => Inside the Object <=
           Note : [object Object]
    Inside the Array.
But what I do not understand:
  • Which underlying part, why and how does know that it's the second item in the array? And: is it the 2nd item (index 1) or the item with index 2?
  • Why is it undefined, when the first one was defined? It does work for the first loop, but not for the second!?
  • The debug quite clearly prints the last key/value information “Note : [object Object]” of the first object in the array. Hence, the i=i+1 should be carried out to my understanding.
Still, any help / hint is highly appreciated. Thank you.
Kind regards,

bembulak



SpiderBasic 3.20 beta 2 on Win11, Intel Mac, MX Linux
the.weavster
Posts: 231
Joined: Sat Mar 01, 2014 3:02 pm

Re: How to work with JSON - can't wrap my head around nested struct/array of obj

Post by the.weavster »

To be honest when working with JSON it's probably easier to use inline JS

Code: Select all

Procedure DisplayElement(sValue.s)
  Debug(sValue)
EndProcedure

Procedure UseInlineJS(sJson.s)
  Protected sVal.s = ""
  !let obj = JSON.parse(v_sjson);
  !obj['Category AAA'].forEach(function(elem) {
  ! v_sval = elem['Name'];
  Debug sVal
  ! f_displayelement(elem['Amount'].toString());
  ! f_displayelement(elem['Note']);
  !});
EndProcedure

UseInlineJS(GetText())
Fred
Site Admin
Posts: 1838
Joined: Mon Feb 24, 2014 10:51 am

Re: How to work with JSON - can't wrap my head around nested struct/array of obj

Post by Fred »

If possible, you should map your JSON to structure, it's much easier this way:

https://www.spiderbasic.com/documentati ... cture.html
User avatar
bembulak
Posts: 103
Joined: Wed Feb 26, 2014 9:53 am

[SOLUTION] Re: How to work with JSON - can't wrap my head around nested struct/array of obj

Post by bembulak »

Fred wrote: Tue Dec 02, 2025 10:04 am If possible, you should map your JSON to structure, it's much easier this way:

https://www.spiderbasic.com/documentati ... cture.html
That indeed is a lot easier (and works).
Thank you very much!

Here's a complete example now:

Code: Select all

Declare.s GetText()

Structure product
  id.l
  Name.s
  Points.l
  Unit.s
  Amount.l
  Note.s
EndStructure

NewList Products.product()

Enumeration
  #JSON
EndEnumeration

Input$ = GetText()
If ParseJSON(#JSON, Input$) : Else : Debug "Parsing failed!" : EndIf

ObjectValue = JSONValue(#JSON)
If ExamineJSONMembers(ObjectValue)
  While NextJSONMember(ObjectValue) ; Iterating over the Categories
    If (JSONMemberKey(ObjectValue) = "Category AAA") 
      ; Now inside the Category. There should be a list of things.
      ; ExtractJSONStructure(JSONMemberValue(ObjectValue), 
      ; ExtractJSONArray(JSONMemberValue(ObjectValue), 
      ExtractJSONList(JSONMemberValue(ObjectValue), Products())
    EndIf ; Category
  Wend
EndIf

ForEach Products()
  Debug Products()\id
  Debug Products()\Name
  Debug Products()\Points
  Debug Products()\Unit
  Debug Products()\Amount
  Debug Products()\Note
  Debug "----------------"
Next

; ========================================================================================
; ReturnedText$ = GetText() - assume this is comming from http://localhost:8080/script.php
Procedure.s GetText()
  ProcedureReturn  "{" + 
                   Chr(34) + "Category AAA" + Chr(34) + ": [" + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 0," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt A " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 1," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "g " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 100," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Foo Bar Braz " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 1," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt B " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 2," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "stk " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 2," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Dang Ding Dong " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 2," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt C " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 3," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "ml " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 30," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Erl Ferl Gerl " + Chr(34) + "" + 
                   "        }" + 
                   "    ]," + 
                   Chr(34) + "Category BBB" + Chr(34) + ": [" + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 3," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt D " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 4," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "g " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 10," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Hart Smart Fart " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 4," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt E " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 5," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "stk " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 10," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Irre Quirre Schmock " + Chr(34) + "" + 
                   "        }," + 
                   "        {" + 
                   Chr(34) + "id" + Chr(34) + " : 5," + 
                   Chr(34) + "Name" + Chr(34) + ":  " + Chr(34) + "Produkt F " + Chr(34) + "," + 
                   Chr(34) + "Points" + Chr(34) + ": 6," + 
                   Chr(34) + "Unit" + Chr(34) + ":  " + Chr(34) + "ml " + Chr(34) + "," + 
                   Chr(34) + "Amount" + Chr(34) + ": 1000," + 
                   Chr(34) + "Note" + Chr(34) + ":  " + Chr(34) + "Junk Funk Skunk " + Chr(34) + "" + 
                   "        }" + 
                   "    ]" + 
                   "}"
 EndProcedure
 
Kind regards,

bembulak



SpiderBasic 3.20 beta 2 on Win11, Intel Mac, MX Linux
Fred
Site Admin
Posts: 1838
Joined: Mon Feb 24, 2014 10:51 am

Re: [SOLVED] How to work with JSON - can't wrap my head around nested struct/array of obj

Post by Fred »

You should even be able to use a map of Products() to extract all the JSON directly
Post Reply