[probably trivial] Access JSON objects members

Just starting out? Need help? Post your questions and find answers here.
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 543
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

[probably trivial] Access JSON objects members

Post by bbanelli »

Greetings,

I apologize for asking stupid questions, but I'm really confused with this one - here's the JSON I parse:

Code: Select all

{
  "product": {
      "x"        : "text",
      "y"      : false,
      "z"   : true,
    }
}
I get it as a string, and after the following code:

Code: Select all

  If ParseJSON(0, JSONData)
    ObjectValue = JSONValue(0)
    If ExamineJSONMembers(ObjectValue)
      While NextJSONMember(ObjectValue)
        Debug JSONMemberKey(ObjectValue)
      Wend
    EndIf
  EndIf
the only thing I get out is "product".

But how do I access elements x, y and z? And so on, if for example, element x has another {} pattern below it...

Sorry for missing nomenclature, I'm just getting a feel of JSON stuff...
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [probably trivial] Access JSON objects members

Post by Little John »

Are you looking for something like this?
The procedure TraverseJSON() should work for all kinds of dynamic JSON data.
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: [probably trivial] Access JSON objects members

Post by Lunasole »

Hah, I understand how you feel trying to do something with this.
The stupid is JSON format itself, not a question. I definitely just hate this web-trash, also last time had to work with it a lot too. Even XML is much better.

For your example you should do something like this, also check the link @Little John posted, that proc is really very useful when working with such a stupid data format

Code: Select all

Structure product_struct
	x$
	y.i ; or a or b should work too
	z.i
EndStructure

Define Temp.product_struct

Define Jshit = LoadJSON(#PB_Any, your_json)
Define tmp = JSONValue(Jshit)
	tmp = GetJSONMember(Tmp, "product") ; this gets element next to root level, also assuming you already received key or just know it
	ExtractJSONStructure(tmp, Temp, product_struct)
Generally you need first to GetJSONMember (moving to element you need and referencing it by key), then you using returned value to receive specific data by one of functions for this
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
User avatar
bbanelli
Enthusiast
Enthusiast
Posts: 543
Joined: Tue May 28, 2013 10:51 pm
Location: Europe
Contact:

Re: [probably trivial] Access JSON objects members

Post by bbanelli »

Little John wrote:Are you looking for something like this?
The procedure TraverseJSON() should work for all kinds of dynamic JSON data.
Hi Little John,

yes, thank you! I've managed to adapt your code for some testing purpose. But on a path of Lunasole's statement...
Lunasole wrote:Hah, I understand how you feel trying to do something with this.
I really felt intellectually undercapacitated for not being able to quickly fully grasp logic and motives behind JSON formating...
The stupid is JSON format itself, not a question. I definitely just hate this web-trash, also last time had to work with it a lot too. Even XML is much better.
:) Well, frankly, so far I've had much more luck with JSON than XML, owing to XML validation, normalization and some other processes that I have to study harder. I am actually adding some REST API code to my current software for communication with web shops, so that's the reason for exploring XML/JSON in the first place...
For your example you should do something like this
/snip
Generally you need first to GetJSONMember (moving to element you need and referencing it by key), then you using returned value to receive specific data by one of functions for this
I've been using freek's code from here: http://forum.purebasic.com/english/view ... 12&t=62502 and that ExtractJSONStructure().

Is there any reason to believe that approach is suboptimal for any reason whatsoever? I'm basically adding elements to list of structures.
"If you lie to the compiler, it will get its revenge."
Henry Spencer
https://www.pci-z.com/
User avatar
the.weavster
Addict
Addict
Posts: 1537
Joined: Thu Jul 03, 2003 6:53 pm
Location: England

Re: [probably trivial] Access JSON objects members

Post by the.weavster »

JSON is a great format 8)
bbanelli wrote:

Code: Select all

{
  "product": {
      "x" : "text",
      "y" : false,
      "z" : true
    }
}
How could you possibly define this object any clearer or easier? XML... bah humbug :evil:

If you know the format of the JSON object you're going to receive getting at an element is not difficult in PB. Take your test object above for example, if this was in a string variable named js and you wanted to get the value of x you could do this:

Code: Select all

nJS = JSONValue(ParseJSON(#PB_Any, js))
nProduct = GetJSONMember(nJS,"product")
nX = GetJSONMember(nProduct,"x")
x.s = GetJSONString(nX)
User avatar
Lunasole
Addict
Addict
Posts: 1091
Joined: Mon Oct 26, 2015 2:55 am
Location: UA
Contact:

Re: [probably trivial] Access JSON objects members

Post by Lunasole »

bbanelli wrote:I've been using freek's code from here: http://forum.purebasic.com/english/view ... 12&t=62502 and that ExtractJSONStructure().
Is there any reason to believe that approach is suboptimal for any reason whatsoever? I'm basically adding elements to list of structures.
Well that generator just does what else has to be done manually.
Thanks, nice tool, I didn't seen it before but came to structures too. I don't think there can be any props when using them to extract any values - that definitely makes code much cleaner, shorter and easy to update.
Just in cases when need to extract only several variables from a large JSHT file it might be more rational to extract single variables instead of getting all with structures
"W̷i̷s̷h̷i̷n̷g o̷n a s̷t̷a̷r"
vwidmer
Enthusiast
Enthusiast
Posts: 282
Joined: Mon Jan 20, 2014 6:32 pm

Re: [probably trivial] Access JSON objects members

Post by vwidmer »

How do u get something deeper?

like wind > VWINDBAT - SPEED2

or even deeper?

Code: Select all

{"wind":{"SPEED":"14","TEMP":"27","ANGLE":"66","VWINDBAT":{"ANGLE2":"66","SPEED2":"14","TEMP2":"27"}}}
Thanks
the.weavster wrote:JSON is a great format 8)
bbanelli wrote:

Code: Select all

{
  "product": {
      "x" : "text",
      "y" : false,
      "z" : true
    }
}
How could you possibly define this object any clearer or easier? XML... bah humbug :evil:

If you know the format of the JSON object you're going to receive getting at an element is not difficult in PB. Take your test object above for example, if this was in a string variable named js and you wanted to get the value of x you could do this:

Code: Select all

nJS = JSONValue(ParseJSON(#PB_Any, js))
nProduct = GetJSONMember(nJS,"product")
nX = GetJSONMember(nProduct,"x")
x.s = GetJSONString(nX)
WARNING: I dont know what I am doing! I just put stuff here and there and sometimes like magic it works. So please improve on my code and post your changes so I can learn more. TIA
infratec
Always Here
Always Here
Posts: 6869
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: [probably trivial] Access JSON objects members

Post by infratec »

Hi,

try this:

Code: Select all

Structure VWindBatStructure
  ANGLE2$
  SPEED2$
  TEMP2$
EndStructure

Structure WindStructure
  SPEED$
  TEMP$
  ANGLE$
  VWINDBAT.VWindBatStructure
EndStructure


Structure AirStructure
  wind.WindStructure
EndStructure


Define Air.AirStructure


JSON$ = ~"{\"wind\":{\"SPEED\":\"14\",\"TEMP\":\"27\",\"ANGLE\":\"66\",\"VWINDBAT\":{\"ANGLE2\":\"66\",\"SPEED2\":\"14\",\"TEMP2\":\"27\"}}}"

Debug JSON$

Debug ""

If ParseJSON(0, JSON$)
  ExtractJSONStructure(JSONValue(0), @Air, AirStructure)
  
  Debug "Speed2: " + Air\wind\VWINDBAT\SPEED2$
EndIf
Bernd
infratec
Always Here
Always Here
Posts: 6869
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: [probably trivial] Access JSON objects members

Post by infratec »

For the original question:

Code: Select all

Structure ProductStructure
  x$
  y.i
  z.i
EndStructure


Structure StoreStructure
  product.ProductStructure
EndStructure


Define Store.StoreStructure


JSON$ = ~"{\"product\": {\"x\":\"text\",\"y\":false,\"z\":true}}"
Debug JSON$

Debug ""

If ParseJSON(0, JSON$)
  ExtractJSONStructure(JSONValue(0), @Store, StoreStructure)
  
  Debug Store\product\x$
  Debug Store\product\y
  Debug Store\product\z
  
EndIf
But the JSON is a bit malformed.
PBs ParseJSON() does not like it.
I had to remove the comma after the true.

I don't know if this comma is allowed or not.
If yes, then Fred should improve ParseJSON().

Bernd
vwidmer
Enthusiast
Enthusiast
Posts: 282
Joined: Mon Jan 20, 2014 6:32 pm

Re: [probably trivial] Access JSON objects members

Post by vwidmer »

Thanks for the code however I was looking for something a little simpler along these lines

Code: Select all

nJS = JSONValue(ParseJSON(#PB_Any, js))
nProduct = GetJSONMember(nJS,"product")
nX = GetJSONMember(nProduct,"x")
x.s = GetJSONString(nX)
So I dont have to structure the whole json. some of the jsons I have have too much structure to go through all that just to pull one thing unless have to? would be nicer if could just call it blindly but maybe its not possible :)

Thanks again
WARNING: I dont know what I am doing! I just put stuff here and there and sometimes like magic it works. So please improve on my code and post your changes so I can learn more. TIA
infratec
Always Here
Always Here
Posts: 6869
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: [probably trivial] Access JSON objects members

Post by infratec »

Hi, hi,

use FindString()
Then you save also a lot of code, because the json lib is not included.
vwidmer
Enthusiast
Enthusiast
Posts: 282
Joined: Mon Jan 20, 2014 6:32 pm

Re: [probably trivial] Access JSON objects members

Post by vwidmer »

Well this is what I came up with it does mostly what I was trying to accomplish. It will fail as I dont really know how to put in any kind of error protection yet.

Please improve on it and make changes if you would like and post back.

Thanks

Code: Select all

Global NewMap Result.s()

Procedure gJSValue(jsData.s,jsReq.s)
  cnt.i ; counter
  
  jsLVL.i = CountString(jsReq,".")
  If Mid(jsReq,Len(jsReq),1) = "."
    jsTree.i = 1
  Else
    jsLVL = jsLVL+1
  EndIf
  
  nJS = JSONValue(ParseJSON(#PB_Any, jsData))
  
  If jsLVL > 0
    ;Debug CountString(jsReq,".")
    
    For cnt = 2 To jsLVL
      JSTag.s = StringField(jsReq,cnt,".")
      ;Debug JSTag
      If cnt = 2
        ;Debug "C1"
        nProduct = GetJSONMember(nJS,JSTag)
      Else
        ;Debug "C2"
        nProduct = GetJSONMember(nProduct,JSTag)
      EndIf
      
    Next
    
    If Mid(jsReq,Len(jsReq),1) = "."
      Debug "Get listing for: " + jsReq
      ;Debug Mid(jsReq,Len(jsReq),1)
      
      If Len(jsReq) = 1
        ExtractJSONMap(nJS, Result())
      Else
        ExtractJSONMap(nProduct, Result())
      EndIf
      
      ; display the result
      ForEach Result()
        Debug MapKey(Result()) + " = " + Result()
      Next
      
    Else
      
      x.s = GetJSONString(nProduct)
      Debug x
      
    EndIf  
  EndIf
  
EndProcedure

;js.s = "{"+#DQUOTE$+"product"+#DQUOTE$+":{"+#DQUOTE$+"x"+#DQUOTE$+":"+#DQUOTE$+"text"+#DQUOTE$+","+#DQUOTE$+"y"+#DQUOTE$+":false,"+#DQUOTE$+"z"+#DQUOTE$+":true}}"
js.s = "{"+#DQUOTE$+"status"+#DQUOTE$+":"+#DQUOTE$+"success"+#DQUOTE$+", "+#DQUOTE$+"data"+#DQUOTE$+":{"+#DQUOTE$+"username"+#DQUOTE$+":"+#DQUOTE$+"mycoolusername"+#DQUOTE$+","+#DQUOTE$+"fname"+#DQUOTE$+":"+#DQUOTE$+"V"+#DQUOTE$+","+#DQUOTE$+"lname"+#DQUOTE$+":"+#DQUOTE$+""+#DQUOTE$+","+#DQUOTE$+"sub_id"+#DQUOTE$+":"+#DQUOTE$+"7"+#DQUOTE$+","+#DQUOTE$+"points"+#DQUOTE$+":1,"+#DQUOTE$+"language"+#DQUOTE$+":"+#DQUOTE$+"en"+#DQUOTE$+","+#DQUOTE$+"plan_id"+#DQUOTE$+":1,"+#DQUOTE$+"plan_name"+#DQUOTE$+":"+#DQUOTE$+"Free Plan"+#DQUOTE$+","+#DQUOTE$+"plan_free"+#DQUOTE$+":1,"+#DQUOTE$+"need_account_activation"+#DQUOTE$+":false,"+#DQUOTE$+"need_account_renew"+#DQUOTE$+":false}}"

Debug "Root level:" 
gJSValue(js,".")
Debug "1st level:"
gJSValue(js,".data.")
Debug "1st level item:"
gJSValue(js,".data.username")
I was trying to emulate the way ./jq (https://stedolan.github.io/jq/) program works on the terminal in its simplest form.
WARNING: I dont know what I am doing! I just put stuff here and there and sometimes like magic it works. So please improve on my code and post your changes so I can learn more. TIA
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: [probably trivial] Access JSON objects members

Post by Little John »

infratec wrote:But the JSON is a bit malformed.
PBs ParseJSON() does not like it.
I had to remove the comma after the true.

I don't know if this comma is allowed or not.
If yes, then Fred should improve ParseJSON().
This JSON validator says "invalid comma", so ParseJSON() seems to work correct here.
vwidmer
Enthusiast
Enthusiast
Posts: 282
Joined: Mon Jan 20, 2014 6:32 pm

Re: [probably trivial] Access JSON objects members

Post by vwidmer »

how to implement code to handle something like this:

Code: Select all

{"positions":[[123,456,"TEST1"],[234,212,"TEST2"],[982,273,"TEST3",]],"time_on_server":null}
WARNING: I dont know what I am doing! I just put stuff here and there and sometimes like magic it works. So please improve on my code and post your changes so I can learn more. TIA
User avatar
kenmo
Addict
Addict
Posts: 1967
Joined: Tue Dec 23, 2003 3:54 am

Re: [probably trivial] Access JSON objects members

Post by kenmo »

The JSON format is fine (better than XML in some ways), but yes you can request more features in PB's JSON library.

You can try my include file to simplify JSON in PB: JSON_Helper.pbi

Code: Select all

IncludeFile "JSON_Helper.pbi"

JSON$ = ReplaceString( "{'product': {'x':'text','y':false,'z':true}}" , "'", #DQUOTE$)
ParseJSON(0, JSON$)
Debug JSONStringFromPath( MainJSONObject(0), "product.x") ; shows "text"
Post Reply