merging json objects

Posted by jmls on 12-Apr-2014 10:34

11.3 (although will probably work on 11.x)

I'm trying to merge two json objects together. The code below seems to work, but I was wondering if there is any other  (faster, more efficient) way. 

  /** merge source object into target object
   *  @param   : source json object
   *  @param   : target json object
   *  @returns : void
   */
    
  method void mergeJson(oSource as JsonObject,oTarget as JsonObject):
    def var lv_i as int no-undo.
    
    def var lv_name as char extent no-undo.
    
    /** get all the defined properties of the source object */
    assign lv_name = oSource:getnames().
    
    /** loop through all properties of the source object
     *  and try to add the property to the target object
     *  using no-error to supress any error if the target
     *  object already has the property defined
     */
      
    do lv_i = 1 to extent(lv_name):
      
      /** add to the target object using the appropriate getter on the source object */

      case oSource:GetType(lv_name[lv_i]):
      
        when JsonDataType:ARRAY   then oTarget:add(lv_name[lv_i],oSource:GetJsonArray(lv_name[lv_i]))  no-error.
        when JsonDataType:BOOLEAN then oTarget:add(lv_name[lv_i],oSource:GetLogical(lv_name[lv_i]))    no-error.
        when JsonDataType:NUMBER  then oTarget:add(lv_name[lv_i],oSource:GetDecimal(lv_name[lv_i]))    no-error.
        when JsonDataType:OBJECT  then oTarget:add(lv_name[lv_i],oSource:GetJsonObject(lv_name[lv_i])) no-error.
        when JsonDataType:string  then oTarget:add(lv_name[lv_i],oSource:GetCharacter(lv_name[lv_i]))  no-error.

        /** yikes. throw a wobbly */
        otherwise undo, throw new AppError(substitute("Unknown json datatype &1",oSource:GetType(lv_name[lv_i])),0).
      end case.
    end.
    
  end method.


All Replies

Posted by jmls on 12-Apr-2014 11:13

actually, there's a nasty little bug hiding in here

getType() returns jsonDataType:NUMBER for both integer and decimal

so, you don't know to use getInteger() or getDecimal() .. which is a problem  ..

let's say that the property in source is an integer. this means that

oTarget:add(lv_name[lv_i],oSource:Decimal(lv_name[lv_i]))


would add a decimal property to the target

but if I used 

oTarget:add(lv_name[lv_i],oSource:GetInteger(lv_name[lv_i]))


on a decimal property on the source , the add fails because I tried to get a integer ..

so, the question now is

not knowing the structure of the json file, and having to rely on GetType() to determine the type of the property. how can I add a decimal field if the source property is decimal, and a n integer property if the source property is integer ??

Posted by Håvard Danielsen on 14-Apr-2014 08:06

You can use AddNumber as follows:

when JsonDataType:NUMBER then
    pcTarget:AddNumber(cNames[i],string(pcSource:GetDecimal(cNames[i]))).
                 

Note that this will remove any unnecessary decimals (2.0 will be output as 2). .If you want to keep the decimal delimiter also when it is 0 you would need to read as integer or int64 first and use decimal if it fails:

when JsonDataType:NUMBER then
do:
   intval = ?.
   intval =  pcSource:GetInt64(cNames[i]) no-error.
   if intval <> ? then
       pcTarget:Add(cNames[i],intval).
   else
       pcTarget:Add(cNames[i],pcSource:GetDecimal(cNames[i])).
end.

--

 

 

   

Posted by Håvard Danielsen on 14-Apr-2014 08:27

I'm trying to merge two json objects together. The code below seems to work, but I was wondering if there is any other  (faster, more efficient) way.


I believe this is the only way to merge Json nodes in ABL. You should probably wrap your merge with a Has check instead of using Add with no-error and also check for NULLs.

do lv_i = 1 to extent(lv_name):
     
    /** add to the target object using the appropriate getter on the source object */
    if not oTarget:Has(lv_name[lv_i]) then
    do: 
        case oSource:GetType(lv_name[lv_i]):     
            when JsonDataType:ARRAY   then oTarget:Add(lv_name[lv_i],oSource:GetJsonArray(lv_name[lv_i])).
            when JsonDataType:BOOLEAN then oTarget:Add(lv_name[lv_i],oSource:GetLogical(lv_name[lv_i])).
            when JsonDataType:NUMBER  then oTarget:Add(lv_name[lv_i],oSource:GetDecimal(lv_name[lv_i])).
            when JsonDataType:OBJECT  then oTarget:Add(lv_name[lv_i],oSource:GetJsonObject(lv_name[lv_i])).
            when JsonDataType:STRING  then oTarget:Add(lv_name[lv_i],oSource:GetCharacter(lv_name[lv_i])).
            when JsonDataType:NULL    then oTarget:AddNull(lv_name[lv_i]).
        end case.
    end.
end.



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

yp.

This thread is closed