Convert JSON to array with nlohmann/json - c++

I've not used C++ in over 20 years, so I am a bit rusty on this.
I am using the nlohmann/json json.h library and need to convert a JSON string that is an array of objects to an actual array.
As an example, I need to take this kind of response from a TRESTResponse object and turn it into a C++ array:
RESTRequest1->Execute();
String Content = RESTResponse1->Content;
Where Content =
"[{"fullname":"Norm A","e_mail":null,"phone":"999-555-4971"},{"fullname":"Norm C","e_mail":"ht2#yahoo.com","phone":"999-555-8887"},{"fullname":"Norma Jn","e_mail":null,"phone":"999-555-5947"},{"fullname":"Norma & Frank L","e_mail":null,"phone":"999-555-1790"},{"fullname":"Norm Sh","e_mail":null,"phone":"999-555-7545"},{"fullname":"Norm S","e_mail":null,"phone":"999-555-9955"}]"
and get it into an array of objects. I have been unsuccessful with the library. While I can get an array into json properly, I can't seem to get json back to an array.
I've looked at some similar posts on Stackoverflow, but I did not see one that concerns the nlohmann/json library.

At a guess, you were probably running into a problem because your input data contains null for a number of the strings (some of the email addresses).
To fix that, you need to explicitly check for is_null before attempting to convert the source to an std::string. At a quick guess, for a null input, you'd probably want to just leave that string empty. For that, your from_json would look something like this:
void from_json(json const &j, Person &p) {
j.at("fullname").get_to(p.name);
if (!j.at("e_mail").is_null())
j.at("e_mail").get_to(p.email);
j.at("phone").get_to(p.phone);
}
That's enough to work for the sample data, but depending on the data involved, you might want/need to protect against a null name and/or phone numbers as well (which you'd do in the same way as shown above for the email address).
A complete demo program using this would might look roughly like this:
#include <sstream>
#include <string>
#include <iostream>
#include "nlohmann/json.hpp"
using json = nlohmann::json;
std::string input { R"(
[{"fullname":"Norm A","e_mail":null,"phone":"999-555-4971"},{"fullname":"Norm C","e_mail":"ht2#yahoo.com","phone":"999-555-8887"},{"fullname":"Norma Jn","e_mail":null,"phone":"999-555-5947"},{"fullname":"Norma & Frank L","e_mail":null,"phone":"999-555-1790"},{"fullname":"Norm Sh","e_mail":null,"phone":"999-555-7545"},{"fullname":"Norm S","e_mail":null,"phone":"999-555-9955"}]
)"};
namespace P {
struct Person {
std::string name;
std::string email;
std::string phone;
friend std::ostream &operator<<(std::ostream &os, Person const &p) {
return os << "name: " << p.name << ", email: " << p.email << ", phone: " << p.phone;
}
};
void from_json(json const &j, Person &p) {
j.at("fullname").get_to(p.name);
if (!j.at("e_mail").is_null())
j.at("e_mail").get_to(p.email);
j.at("phone").get_to(p.phone);
}
}
int main() {
json j = json::parse(input);
std::vector<P::Person> people;
j.get_to(people);
for (auto const &person : people) {
std::cout << person << "\n";
}
}

[EDIT] Added an example that uses your input data. [Demo]
// Outputs:
//
// [
// (Norm A, null, 999-555-4971),
// (Norm C, ht2#yahoo.com, 999-555-8887),
// (Norma Jn, null, 999-555-5947),
// (Norma & Frank L, null, 999-555-1790),
// (Norm Sh, null, 999-555-7545),
// (Norm S, null, 999-555-9955)
// ]
The example below loads a JSON node of array type into a std::vector.
The input JSON string only contains a node writers whose content is an array of strings:
{
"writers": [
"Winston Groom",
"Eric Roth"
]
}
We load it into a JSON node with:
nlohmann::json j = nlohmann::json::parse(json_str);
We parse the "value" for the writers "key", i.e. the array, with:
j.at("writers").get_to(writers);
This will make use of the available from_json(const nlohmann::json&, YourCustomType&) in order to do the parsing.
The struct Writers parses the JSON node into a std::vector<Writer> with:
writers.data = j.get<std::vector<Writer>>();
And the struct Writer parses the JSON node into a std::string with:
j.get_to(writer.name);
[Demo]
#include <iostream> // cout
#include <nlohmann/json.hpp>
#include <ostream>
#include <string>
#include <vector>
struct Writer
{
std::string name{};
};
void from_json(const nlohmann::json& j, Writer& writer)
{
j.get_to(writer.name);
}
struct Writers
{
std::vector<Writer> data{};
};
void from_json(const nlohmann::json& j, Writers& writers)
{
writers.data = j.get<std::vector<Writer>>();
}
int main()
{
std::string json_str{R"({"writers": ["Winston Groom", "Eric Roth"]})"};
Writers writers{};
nlohmann::json j = nlohmann::json::parse(json_str.c_str());
j.at("writers").get_to(writers);
for (const auto& writer : writers.data)
{
std::cout << writer.name << ", ";
}
}
// Outputs:
//
// Winston Groom, Eric Roth,

Related

How to output enum elements using cout?

I am trying to output a element of enum I declared but for example, when I input push_ups, it outputs a number like 8621623 instead of showing push_ups. I have no idea why. I am Japanese so I am sorry if my English is broken. Thank you so much.
#include <iostream>
#include <string>
using namespace std;
enum exercise { push_ups, sit_ups, squats, walking, radio_calisthenics };
istream& operator>>(istream& is, exercise& i)
{
int tmp;
if (is >> tmp)
i = static_cast<exercise>(tmp);
return is;
}
int main()
{
exercise a;
cin >> a;
cout << a << endl;
}
I am trying to output a element of enum I declared but for example, when I input push_ups, it outputs a number like 8621623 instead of showing push_ups.
In the operator>> overload, std::cin accepts integers so push_ups isn't an integer, so std::cin will fail and and the line i = static_cast<exercise>(tmp); will be skipped making a uninitialized which when printed can cause Undefined Behavior to occur.
If you want to map strings to respective enum values, you could do that by mapping each string to the corresponding enum values manually using a hashmap (In C++, that container is called std::unordered_map):
#include <unordered_map>
// ...
const unordered_map<string, exercise> exercise_map {
{ "push_ups", push_ups },
{ "sit_ups", sit_ups },
{ "squats", squats },
{ "walking", walking },
{ "radio_calisthenics", radio_calisthenics }
};
istream& operator>>(istream& is, exercise& i) {
std::string tmp;
if (is >> tmp) {
auto const it = exercise_map.find(tmp);
if (it != exercise_map.end())
i = it->second;
}
return is;
}
Now, to print out the corresponding string value from the enum, we have to do the reverse, i.e., find the key in the hashmap using the value:
ostream& operator<<(ostream& os, exercise& i) {
auto const it = std::find_if(exercise_map.begin(), exercise_map.end(),
[i](std::pair<std::string, exercise> const& e) {
return e.second == i;
}
);
if (it != exercise_map.end())
os << it->first;
return os;
}
This is how the full code should look like:
#include <unordered_map>
#include <algorithm>
#include <utility>
#include <iostream>
#include <string>
using namespace std;
enum exercise { push_ups, sit_ups, squats, walking, radio_calisthenics };
const std::unordered_map<std::string, exercise> exercise_map {
{ "push_ups", push_ups },
{ "sit_ups", sit_ups },
{ "squats", squats },
{ "walking", walking },
{ "radio_calisthenics", radio_calisthenics }
};
istream& operator>>(istream& is, exercise& i) {
std::string tmp;
if (is >> tmp) {
auto const it = exercise_map.find(tmp);
if (it != exercise_map.end())
i = it->second;
}
return is;
}
ostream& operator<<(ostream& os, exercise& i) {
auto const it = std::find_if(exercise_map.begin(), exercise_map.end(),
[i](std::pair<std::string, exercise> const& e) {
return e.second == i;
}
);
if (it != exercise_map.end())
os << it->first;
return os;
}
int main() {
exercise a;
cin >> a;
cout << a << endl;
}
push_ups is not a valid integer value that you are trying to read at is >> tmp so a remains uninitialized. If you want to input names then you'll need to read string and then manually convert it to corresponding enum value. Same for output. Without a properly overloaded operator << a will be treated as an integer.
this line here:
i = static_cast<exercise>(tmp);
will work perfectly when tmp is holding an int value between 0 and 4,
but in your case tmp = push_ups is breaking the cast operation and your ref i is wrongly initialized
You seem to have problems with understanding enums.
I think you entered the string value "push_ups" and assumed the program would understand it to refer to a value of your enum.
An enum is just a placeholder for an integer type, mostly used to increase the readability of your program.
See an enum to be a better way to express something like
// chess_piece = 1 : pawn
// chess_piece = 2 : rook
// chess_piece = 3 : bishop
...
int chess_piece;
as
enum ChessPiece { Pawn, Rook, Bishop, ...};
ChessPiece chess_piece;
In the upper variant, it is clear that the names pawn, rook etc are comment only. The enum isn't different in that regard. It is clearly more readable to write if(chess_piece == Pawn), but the word "Pawn" is only a part of the code in the programming language, not in the compiled program. It does not exist as string value.
What you can do is to add something like
exercise exercise_from_string(const std::string& input)
{
if(input == "push_ups") return push_ups;
...
Or the same with a switch. I'd also advise that you have a value "unknown" in case a function like that finds no known term.
Edit: One of the other guys updated his answer while I wrote this, his code using a std::map is better than mine.
Hope my answer helps you understanding the core issue, though.

How to print all variables in an object, and how to print a select set of variables?

class Person
{
public:
string fname;
string lname;
string occupation;
string gender;
int age;
};
int main()
{
Person bc;
bc.fname = "Bevelry";
bc.lname = "Crusher";
bc.gender = "female";
bc.occupation = "Doctor, USS 1701-D";
bc.age = 40;
cout << bc.all << "\n"; //Something like this?
}
Is it possible for me to print every variable of an object without specifying them by myself? And is it possible for me to make a select list of variables, something like an array of variables, and then print them?
EDIT: i accidently put the cout in the class, fixed now
Is it possible for me to print every variable of an object without specifying them by myself?
No.
And is it possible for me to make a select list of variables, something like an array of variables, and then print them?
Not automatically, but you could create a collection of std::anys and add some decoding for it yourself.
Example:
#include <any>
#include <functional>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
// decode and print one std::any
void decode_one(std::ostream& os, const std::any& a) {
if(auto s = std::any_cast<std::reference_wrapper<std::string>>(&a)) os << s->get();
else if(auto i = std::any_cast<std::reference_wrapper<int>>(&a)) os << *i;
else if(auto d = std::any_cast<std::reference_wrapper<double>>(&a)) os << *d;
// add more types to decode here
else os << "<unknown type>";
}
// a custom ostream operator to decode a vector of anys:
std::ostream& operator<<(std::ostream& os, const std::vector<std::any>& va) {
auto begin = va.begin();
auto end = va.end();
if(begin != end) {
decode_one(os, *begin);
for(std::advance(begin, 1); begin != end; std::advance(begin, 1)) {
os << ',';
decode_one(os, *begin);
}
}
return os;
}
int main() {
int a = 10;
std::string b = "Hello world";
double c = 3.14159;
std::vector<std::any> va{
std::ref(a),
std::ref(b),
std::ref(c)
};
c *= 2.; // just to show that the vector holds a reference
std::cout << va << '\n'; // print the variables in the vector
}
Output:
10,Hello world,6.28318
It's not possible. In C++ there isn't anything that does what you want.
At one side one can easily say that this is not possible in C++.
However, at the other side, one can add that this situation happens quite often when people are making object oriented computer programs, and in Java there is the toString() method for this. So, you might actually write your own toString() method (based on the way it is done in Java), and work with this.
Good luck

Accessor Method to view private variable based on argument in a class in c++?

My problem is that I have many variables in my class and I want them to be accessed via an accessor method. Of course I could have several accessor functions to output my private variables but how can I make it so I can access any of them via an argument. My class:
class Character {
public:
void setAttr(string Sname,int Shealth,int SattackLevel,int SdefenseLevel) {
name = Sname;
health = Shealth;
attackLevel = SattackLevel;
defenseLevel = SdefenseLevel;
}
int outputInt(string whatToOutput) {
return whatToOutput //I want this to either be health, attackLevel or defenseLevel
}
private:
string name;
int health;
int attackLevel;
int defenseLevel;
};
Basically what I want to know is how do I return a private variable in regards to the outputInt function. Most OOP tutorials have one function to return each variable which seems like a very unhealthy thing to do in a large program.
C++ doesn't support what you try to accomplish: reflection or detailed runtime information about objects. There is something called "Run-Time Type Information" in C++, but it can't provide information about your variable name: the reason is because, in the compiled and linked binary this information (names of your variables) will not be necessarily present anymore.
However, you can accomplish something close to that, using i.e. std::unordered_map instead of plain integer variables. So it's possible to access values by their names, as strings.
Please consider the following code:
#include <string>
#include <iostream>
#include <unordered_map>
using namespace std;
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
values.insert(std::make_pair("health", Shealth));
values.insert(std::make_pair("attackLevel", SattackLevel));
values.insert(std::make_pair("defenseLevel", SdefenseLevel));
}
int outputInt(const string& whatToOutput) {
return values.at(whatToOutput);
}
private:
string name;
std::unordered_map<std::string, int> values;
};
int main(int argc, char* argv[]) {
Character yourCharacter;
yourCharacter.setAttr("yourName", 10, 100, 1000);
std::cout << "Health: " << yourCharacter.outputInt("health") <<std::endl;
std::cout << "Attack level: " << yourCharacter.outputInt("attackLevel") << std::endl;
std::cout << "Defense level: " << yourCharacter.outputInt("defenseLevel") << std::endl;
return 0;
}
It will output as expected:
Health: 10
Attack level: 100
Defense level: 1000
Another option without dependency on unordered_map would be, to use predefined static strings for your variable names and an array or vector for your values. So we could replace the class Character above with something like:
static std::string variableNames[3] = {
"health",
"attackLevel",
"defenseLevel"
};
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
variableValues[0] = Shealth;
variableValues[1] = SattackLevel;
variableValues[2] = SdefenseLevel;
}
int outputInt(const string& whatToOutput) {
int retVal = 0;
for (size_t i = 0; i < sizeof(variableNames)/sizeof(std::string); ++i) {
if (!whatToOutput.compare(variableNames[i])) {
retVal = variableValues[i];
}
}
return retVal;
}
private:
string name;
int variableValues[3];
};
And getting still same output. However, here you have to manage a list with all your variable names inside the string array manually - I don't like this solution and would prefer one of the others above personally.
Most common ways in C++ to handle such a design is to have seperate getHealth(), getAttackLevel(), getDefenseLevel() functions instead. However, this will miss one use-case, which is: if you want to let the user input a string, like i.e. "health" and display the corresponding variable then, you would need to write code by yourself to call the corresponding getXXX() function. If this is not a issue in your case, consider the following code which is much cleaner:
#include <string>
#include <iostream>
using namespace std;
class Character {
public:
void setAttr(const string& Sname, int Shealth, int SattackLevel, int SdefenseLevel) {
name = Sname;
health = Shealth;
attackLevel = SattackLevel;
defenseLevel = SdefenseLevel;
}
int getHealth() const { return health; }
int getAttackLevel() const { return attackLevel; }
int getDefenseLevel() const { return defenseLevel; }
private:
string name;
int health, attackLevel, defenseLevel;
};
int main(int argc, char* argv[]) {
Character yourCharacter;
yourCharacter.setAttr("yourName", 10, 100, 1000);
std::cout << "Health: " << yourCharacter.getHealth() <<std::endl;
std::cout << "Attack level: " << yourCharacter.getAttackLevel() << std::endl;
std::cout << "Defense level: " << yourCharacter.getDefenseLevel() << std::endl;
return 0;
}
One other unrelated advice: Instead of using string as parameter types for your functions, use const string& (const reference to string; see my example code above). This allows easier calling of your functions (they can be called directly with an string literal without the need to create additional variables in the calling code) and they will not make a additional unnecessary copy. The only copy then will take place at: name = Sname; (in your code two copies took place).
I don't know if it can be a good idea for you, but you can use a public typedef struct that you pass by reference and set your value.
class Character {
public:
//...
typedef struct allvalues{
string vname;
int vhealth;
int vattackLevel;
int vdefenseLevel;
}allvalues;
void getValues(allvalues& val){
val.vname = name;
val.vhealth = health;
val.vattackLevel = attackLevel;
val.vdefenseLevel = detenseLevel;
}
//...
};
//...
//somewhere in the code
Character myCarac;
//...
//Here how to use it
Character::allvalues values;
myCarac.getValues(values);

de-serialize ASCII to struct

I have come up with the following structure to declare various formats if messages that are to be received from the network:
#include <stdint.h>
#include <iostream>
#include <string.h>
template<int T>
struct uint
{
static uint<T> create(uint64_t value)
{
uint<T> r = {value};
return r;
}
uint(uint64_t value)
{
v = value;
}
uint()
{}
uint<T>& operator =(uint64_t value)
{
v = value;
return *this;
}
operator uint64_t() const
{
return (uint64_t)v;
}
unsigned long long v:T;
}__attribute__((packed));
example:
typedef uint<5> second_t;
suppose one of the message formats (which are auto-generated via some process) is like this:
struct seconds
{
char _type;
second_t _second;
} __attribute__((packed));
Now suppose I would like to populate an instance of the above messahe using a string:
int main()
{
seconds ii;
const char *i = "123456";
// memset, memcpy,sprintf... ??? what to use here?
std::cout << ii._type << " " << ii._second << std::endl;
}
Given a stream 123456, I expect the instance of the seconds (ii) structure to have char ii._type = '1' and integer ii._second = 23456. But I dont know how to do that. Do you have a clue how i can do that? and do you have any suggestion how to improve the basic structure?
thanks
You have a number of easier and more reliable options available that require almost no work.
check out google protocol buffers (platform independent message serialisation and deserialisation): https://developers.google.com/protocol-buffers/
or boost::serialization - (probably faster, but not platform-independant) http://www.boost.org/doc/libs/1_58_0/libs/serialization/doc/index.html

C++11 Cereal: load_and_allocate not loading correctly

I am using cereal, a C++11 serialization library. I am uncertain if this is a bug with the library or an issue with how I am using it and I would like some assistance.
Given the following minimal repro which is representative (but not reliant) on my own code I am getting an exception thrown from JSONInputArchive::search as invocated by the line next to my comment in the code sample below (//breaks here.)
I'm currently on commit 436a0a275cda007f137876f37b4fc8783e615352 in this github repro (at the time of writing, the tip of their develop branch.)
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include "cereal/cereal.hpp"
#include "cereal/types/map.hpp"
#include "cereal/types/vector.hpp"
#include "cereal/types/memory.hpp"
#include "cereal/types/string.hpp"
#include "cereal/types/base_class.hpp"
#include "cereal/archives/json.hpp"
#include <cereal/types/polymorphic.hpp>
class BaseClass : public std::enable_shared_from_this<BaseClass> {
public:
virtual ~BaseClass(){}
template <class Archive>
void serialize(Archive & archive){
archive(CEREAL_NVP(name), CEREAL_NVP(baseMember));
}
protected:
BaseClass(const std::string &a_name):
name(a_name){
}
std::string name;
int baseMember; //let this have random junk so we can see if it saves right.
};
class DerivedClass : public BaseClass {
friend cereal::access;
public:
static std::shared_ptr<DerivedClass> make(const std::string &a_name, int a_derivedMember){
return std::shared_ptr<DerivedClass>(new DerivedClass(a_name, a_derivedMember));
}
template <class Archive>
void serialize(Archive & archive){
archive(CEREAL_NVP(derivedMember), cereal::make_nvp("base", cereal::base_class<BaseClass>(this)));
}
private:
DerivedClass(const std::string &a_name, int a_derivedMember):
BaseClass(a_name),
derivedMember(a_derivedMember){
}
template <class Archive>
static DerivedClass * load_and_allocate(Archive &archive){
int derivedMember;
archive(CEREAL_NVP(derivedMember)); //breaks here.
DerivedClass* object = new DerivedClass("", derivedMember);
archive(cereal::make_nvp("base", cereal::base_class<BaseClass>(object)));
return object;
}
int derivedMember;
};
CEREAL_REGISTER_TYPE(DerivedClass);
void saveTest(){
std::stringstream stream;
{
cereal::JSONOutputArchive archive(stream);
auto testSave = DerivedClass::make("TestName", 4);
archive(cereal::make_nvp("test", testSave));
}
std::cout << stream.str() << std::endl;
std::shared_ptr<DerivedClass> loaded;
{
cereal::JSONInputArchive archive(stream);
archive(cereal::make_nvp("test", loaded));
}
std::stringstream stream2;
{
cereal::JSONOutputArchive archive(stream2);
archive(cereal::make_nvp("test", loaded));
}
std::cout << stream2.str() << std::endl;
std::cout << "TA-DA!" << std::endl;
}
int main(){
saveTest();
}
The sample output I get from the above (before the exception) is:
{
"test": {
"id": 1073741824,
"ptr_wrapper": {
"id": 2147483649,
"data": {
"derivedMember": 4,
"base": {
"name": "TestName",
"baseMember": -1163005939
}
}
}
}
}
I've modified the throwing method (in cereal/archive/json.hpp) to print what it is searching for and each of the values it is looking through in an effort to debug the problem. Here is my modified version:
//! Adjust our position such that we are at the node with the given name
/*! #throws Exception if no such named node exists */
inline void search( const char * searchName )//, GenericValue const & parent )
{
size_t index = 0;
std::cout << "_____" << std::endl;
for( auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
if( std::strcmp( searchName, it->name.GetString() ) == 0 )
{
itsIndex = index;
return;
} else{
//I added this part here
std::cout << "!" << searchName << " == " << it->name.GetString() << std::endl;
}
throw Exception("JSON Parsing failed - provided NVP not found");
}
Output for the above method before it excepts:
!derivedMember == id
!derivedMember == data
The output I get from this seems to indicate that search is looking through the members of "test.ptr_wrapper" instead of "test.ptr_wrapper.data".
My question is this: am I doing something wrong? Or is there an issue with cereal?
https://github.com/USCiLab/cereal/issues/42
It seems like this is indeed a bug with Cereal. My temporary work-around is as follows:
For now, to work around the issue I added a line 144 in memory.hpp (as
it appears on line 168 in the case of no load_and_allocate which means
that there is a default constructor.)
ar( *ptr );
I will simply avoid using the load_and_allocate archive
directly and will use my serialization functions. In my
load_and_allocate method I will construct an object with "default"
like information.
When this is fixed I should be able to correctly load in the parameters required to construct the object properly.
*edit: this has been fixed on the develop branch.