JSON merge

Just starting out? Need help? Post your questions and find answers here.
User avatar
mariosk8s
Enthusiast
Enthusiast
Posts: 103
Joined: Wed Apr 06, 2011 11:37 am
Location: Hüfingen, Germany
Contact:

JSON merge

Post by mariosk8s »

How do i merge 2 JSON objects, so that one is a sub object of the other?
Example:

Code: Select all

top = ParseJSON(#PB_Any, ReplaceString("{'foo':'bar','test':1}", 
                                       "'", Chr(34)))
sub = ParseJSON(#PB_Any, ReplaceString("{'prop1':'val1','test1':1, 'more':{ 'a':1, 'b': 'hi'}}", 
                                       "'", Chr(34)))

; here's me dreaming up API
SetJSONObject(AddJSONMember(top, "sub"), JSONValue(sub))
Is there a way to do this? So i'd end up with something like

Code: Select all

ComposeJSON(top)
{
  "foo": "bar",
  "test": 1,
  "sub" : {
    "prop1": "val1",
    "test1": 1, 
    "more": { 
      "a": 1, 
      "b": "hi"
    }
  }
}
User avatar
NicTheQuick
Addict
Addict
Posts: 1226
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: JSON merge

Post by NicTheQuick »

I am working the first time with JSON and I don't understand why I can not set an object and why neither top nor sub have a type. Then I figured out that I have to use JSONValue() before JSONType() and then sub and top are recognized as objects. But I can not use SetJSONObject() to add one of these objects to an other. I think one has to develop a small recursive procedure which runs recursively through the object to be copied and add all elements one by one to the top element.

Code: Select all

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"
		Case #PB_JSON_Object:  ProcedureReturn "object"
		Default: ProcedureReturn "Unknown: " + Str(JSONType(Value))
	EndSelect
EndProcedure

top = ParseJSON(#PB_Any, ~"{\"foo\":\"bar\",\"test\":1}")
sub = ParseJSON(#PB_Any, ~"{\"prop1\":\"val1\",\"test1\":1, \"more\":{ \"a\":1, \"b\": \"hi\"}}")

Debug GetAnyValue(JSONValue(top))
Debug GetAnyValue(JSONValue(sub))

newSub = AddJSONMember(JSONValue(top), "sub")
;SetJSONObject(newSub, sub)

Debug ComposeJSON(top, #PB_JSON_PrettyPrint)
So it would be nice if there were a second parameter for SetJSONObject(). I don't understand why someone wants to create an object with no objects.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
mariosk8s
Enthusiast
Enthusiast
Posts: 103
Joined: Wed Apr 06, 2011 11:37 am
Location: Hüfingen, Germany
Contact:

Re: JSON merge

Post by mariosk8s »

So in the absence of merge functionality i created a clone function.
This is obviously not performant, but ok for small stuff.

Code: Select all

Procedure jsonClone(jSrc, jDest)
  Select JSONType(jSrc)
    Case #PB_JSON_Null:    
      SetJSONNull(jDest)
    Case #PB_JSON_String:  
      SetJSONString(jDest, GetJSONString(jSrc))
    Case #PB_JSON_Number:
      SetJSONDouble(jDest, GetJSONDouble(jSrc))
    Case #PB_JSON_Boolean: 
      SetJSONBoolean(jDest, GetJSONBoolean(jSrc))
    Case #PB_JSON_Array:
      Protected i, len = JSONArraySize(jSrc)
      SetJSONArray(jDest)
      For i = 0 To (len - 1)
        Protected ja = GetJSONElement(jSrc, i)
        Protected ca = AddJSONElement(jDest)
        jsonClone(ja, ca)
      Next
    Case #PB_JSON_Object: 
      SetJSONObject(jDest)
      If ExamineJSONMembers(jSrc)
        While NextJSONMember(jSrc)
          Protected key.s = JSONMemberKey(jSrc)
          Protected jo = JSONMemberValue(jSrc)
          Protected co = AddJSONMember(jDest, key)
          jsonClone(jo, co)
        Wend
      EndIf
    Default: 
 EndSelect
EndProcedure
Usage would like this

Code: Select all

top = ParseJSON(#PB_Any, ~"{\"foo\":\"bar\",\"test\":1}")
sub = ParseJSON(#PB_Any, ~"{\"prop1\":\"val1\",\"test1\":1, \"more\":{ \"a\":1, \"b\": \"hi\"}}")

Debug ComposeJSON(top, #PB_JSON_PrettyPrint)
Debug ComposeJSON(sub, #PB_JSON_PrettyPrint)
no = AddJSONMember(JSONValue(top), "sub")
jsonClone(JSONValue(sub), no)
Debug ComposeJSON(top, #PB_JSON_PrettyPrint)

sub2 = ParseJSON(#PB_Any, ~"[\"#1\", 2, {\"three\": true}]")
Debug ComposeJSON(sub2, #PB_JSON_PrettyPrint)
no2 = AddJSONMember(JSONValue(top), "sub2")
jsonClone(JSONValue(sub2), no2)
Debug ComposeJSON(top, #PB_JSON_PrettyPrint)

User avatar
NicTheQuick
Addict
Addict
Posts: 1226
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: JSON merge

Post by NicTheQuick »

Nice! Image
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5353
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: JSON merge

Post by Kwai chang caine »

Cool function
Thanks Mariosk8s for sharing 8)
ImageThe happiness is a road...
Not a destination
Little John
Addict
Addict
Posts: 4527
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: JSON merge

Post by Little John »

Personally, I never have stumbled across this problem.
Anyway, there is obviously some functionality missing in PB in this regard.

@mariosk8s:
Thank you for pointing this problem out, and for the code that solves it.
Post Reply