Json: concatenate objects

Created on 26 May 2016  路  14Comments  路  Source: nlohmann/json

Hi!
I wish to concatenate two json objects and thought of this:

#include <json.hpp>
#include <iostream>

int main() {
  nlohmann::json a,b;

  a[ "sec" ] = {
    { "title", "some title" }, 
    { "cnt", 10 }
  };

  b[ "sec" ] = {
    { "more info", "add something more" }
  };

  a += b;

  std::cout << a.dump(4);
}

which however throws an exception with v1.1.0. Any suggestions how to best do this?
Best, Mikael

enhancemenimprovement

Most helpful comment

Hi @mlund, you can achieve merging objects with the following function:

json merge(const json &a, const json &b)
{
    json result = a.flatten();
    json tmp = b.flatten();

    for (json::iterator it = tmp.begin(); it != tmp.end(); ++it)
    {
        result[it.key()] = it.value();
    }

    return result.unflatten();
}

It is based on the flatten()/unflatten() functions and has the single limitation that empty arrays and objects are replaced by null.

I hope this helps!

All 14 comments

The exception "cannot use push_back() with object" is due to the fact that a += b; is executed as a.push_back(b);, and push_back is only valid for arrays (see its documentation.)

(You originally reported a segmentation fault, and I was worried there was a bug ;-))

Unfortunately, the requested functionality is not present at this moment. Looking at Stack Overflow, it seems that std::map::insert can have similar effects. Maybe overloading nlohmann::json::insert accordingly could help. Any thoughts about this?

Thanks for quick response and sorry about the initial text; no bugs indeed! I actually do not know how to achieve what I want, regardless of syntax and I wonder if it's possible to add new objects to a["sec"] from another object? The insert() method does not allow objects if I understand it correctly. Concretely I have a json object created by a base class, and I need derived classes to add specific information to it.
I suppose STL-like merging using i.e. a.insert(b.begin(),b.end()) as for maps would be ideal, alternatively a << b?

Hi @mlund, you can achieve merging objects with the following function:

json merge(const json &a, const json &b)
{
    json result = a.flatten();
    json tmp = b.flatten();

    for (json::iterator it = tmp.begin(); it != tmp.end(); ++it)
    {
        result[it.key()] = it.value();
    }

    return result.unflatten();
}

It is based on the flatten()/unflatten() functions and has the single limitation that empty arrays and objects are replaced by null.

I hope this helps!

Thanks! Alternatively, this also worked for my purpose:

for (auto it=b["sec"].begin(); it!=b["sec"].end(); it++)
    a["sec"].push_back( json::object_t::value_type(it.key(), it.value())  );

Hi, is this usefull for include one json object into other? i've get some errors 馃槥

This basically implements the similar insert functions of std::map (http://en.cppreference.com/w/cpp/container/map/insert) and std::vector (http://en.cppreference.com/w/cpp/container/vector/insert).

Thats greate!

No, i need to concatenate one json object into a specific index of another, something like:

Entities["table"] = mergeJSON(Entities, ReadedEntity);

Where mergeJSON is the merge function what i getted from this topic.

How can i do that?

Could you provide an example for Entities and ReadedEntity?

Entities:

{"CSVMsg": {
 "name": "PacketEntities",
 "class":35,
 "id":2,
 "serial":782
 }
}

ReadedEntity:

{"table":
 {"name": "DC_Player",
  "fields": {
   "0": {"m_flSimulationTime": 47},
   "1": {"m_nTickBase": 160748},
   "2": {"m_vecOrigin": {
    "0": 299.141327,
    "1": 2343.210938
    },
   },
   "3": {"m_vecOrigin2": -250.849808}
  }
 }
}

Need something like:

{"CSVMsg": {
 "name": "PacketEntities",
 "class":35,
 "id":2,
 "serial":782,
 "table":
  {"name": "DC_Player",
   "fields": {
    "0": {"m_flSimulationTime": 47},
    "1": {"m_nTickBase": 160748},
    "2": {"m_vecOrigin": {
     "0": 299.141327,
     "1": 2343.210938
     },
    },
    "3": {"m_vecOrigin2": -250.849808}
   }
  }
 }
}

For your example, the following should do:

Entities["CSVMsg"]["table"] = ReadedEntity["table"];

I don't test it already, but you are a kind of genius for my. Thank you a lot!

Hey
Not sure of how much of this is correct as I'm new to C++ but the original nlohmann post about merge produced issues with empty arrays as it converted them to null.. I did this little tweak to his code and now I can merge json files with empty arrays...

json merge(const json &a, const json &b)
{
    json result = a;
    json tmp = b;
    for (json::iterator it = tmp.begin(); it != tmp.end(); ++it)
    {
        result[it.key()] = it.value();
    }
    return result;
}

We discuss a merge operation for objects in #661.

@Dariusz1989 FYI, the json tmp = b; there should not be necessary, you should just be able to use b directly to avoid copying b unnecessarily, which can be expensive.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zhishupp picture zhishupp  路  4Comments

Prati369 picture Prati369  路  4Comments

jmlemetayer picture jmlemetayer  路  3Comments

koemeet picture koemeet  路  4Comments

bassosimone picture bassosimone  路  3Comments