Page 1 of 2

[probably trivial] Access JSON objects members

Posted: Mon Mar 14, 2016 4:09 pm
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...

Re: [probably trivial] Access JSON objects members

Posted: Mon Mar 14, 2016 4:31 pm
by Little John
Are you looking for something like this?
The procedure TraverseJSON() should work for all kinds of dynamic JSON data.

Re: [probably trivial] Access JSON objects members

Posted: Tue Mar 15, 2016 12:05 am
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

Re: [probably trivial] Access JSON objects members

Posted: Tue Mar 15, 2016 8:10 am
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.

Re: [probably trivial] Access JSON objects members

Posted: Tue Mar 15, 2016 11:10 am
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)

Re: [probably trivial] Access JSON objects members

Posted: Wed Mar 16, 2016 7:54 pm
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

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 5:43 am
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)

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 7:14 am
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

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 7:39 am
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

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 1:56 pm
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

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 4:02 pm
by infratec
Hi, hi,

use FindString()
Then you save also a lot of code, because the json lib is not included.

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 4:53 pm
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.

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 5:47 pm
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.

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 6:40 pm
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}

Re: [probably trivial] Access JSON objects members

Posted: Wed Jun 28, 2017 7:01 pm
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"