Reputation: 749
I am using the nlohmann JSON C++ library to read a JSON file with this structure:
{
"Main": [
{
"obj1": "bar"
},
{
"obj2": "foo"
}
]
}
The main object with key known to the user "Main"
contains an array of objects with unknown key names.
I want to transfer the JSON object in the following program to a C++ structure. How could this be done?
#include <nlohmann/json.hpp>
#include <iostream>
#include <fstream>
using json = nlohmann::json;
int main()
{
std::ifstream ifs("../test/test_2.json");
json js = json::parse(ifs);
for (json::iterator it = js.begin(); it != js.end(); ++it)
{
std::cout << it.key() << " :\n";
std::cout << it.value() << "\n";
}
if (js.contains("Main"))
{
json a = js["Main"];
for (size_t idx = 0; idx < a.size(); ++idx)
{
json o = a.at(idx);
std::cout << o << "\n";
}
}
return 0;
}
Output:
Main :
[{"obj1":"bar"},{"obj2":"foo"}]
{"obj1":"bar"}
{"obj2":"foo"}
Upvotes: 1
Views: 7878
Reputation: 749
This is one way to read and write the JSON in the original format, versions of the functions from_json() and to_json() are needed:
#include <iostream>
#include <fstream>
#include <map>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
using json = nlohmann::json;
struct key_value_t
{
std::string key;
std::string value;
};
void from_json(const json& j, key_value_t& kv)
{
assert(j.is_object());
assert(j.size() == 1);
kv.key = j.begin().key();
kv.value = j.begin().value();
}
void to_json(json& j, const key_value_t& kv)
{
j = nlohmann::json{
{kv.key, kv.value}
};
}
int main()
{
try
{
std::string str{ R"({ "Main": [ { "obj1": "bar" }, { "obj2": "foo" } ] })" };
json js_in = json::parse(str);
std::vector<key_value_t> kv_in;
//get input object
js_in.at("Main").get_to(kv_in);
if (js_in.contains("Main"))
{
nlohmann::json js_out = nlohmann::json::object_t();
std::vector<key_value_t> kv_;
key_value_t kv1{ "obj1", "1" };
key_value_t kv2{ "obj2", "2" };
kv_.push_back(kv1);
kv_.push_back(kv2);
nlohmann::json js_arr = kv_;
//add to main JSON object
js_out += {"Main", js_arr};
//save output
std::ofstream ofs("output.json");
ofs << std::setw(2) << js_out << std::endl;
ofs.close();
}
}
catch (std::exception& e)
{
std::cout << e.what() << '\n';
}
return 0;
}
Output is:
{
"Main": [
{
"obj1": "1"
},
{
"obj2": "2"
}
]
}
Upvotes: 0
Reputation: 749
Yes, but the API gives an automatic way to do this by means of NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE; it seems it would be like just defining a vector like this, but this program gives the error
[json.exception.out_of_range.403] key 'key' not found
program
#include <nlohmann/json.hpp>
#include <iostream>
#include <fstream>
using json = nlohmann::json;
struct key_value_t
{
std::string key;
std::string value;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(key_value_t, key, value);
int main()
{
try
{
std::string str{ R"({ "Main": [ { "obj1": "bar" }, { "obj2": "foo" } ] })" };
json js = json::parse(str);
std::vector<key_value_t> kv;
if (js.contains("Main"))
{
js.at("Main").get_to(kv);
}
}
catch (std::exception& e)
{
std::cout << e.what() << '\n';
}
return 0;
}
Upvotes: 0
Reputation: 8054
You could parse the vector of maps under Main
with:
auto objects{ j.at("Main").get<objects_t>() };
Where:
using object_t = std::map<std::string, std::string>;
using objects_t = std::vector<object_t>;
#include <fmt/ranges.h>
#include <iostream> // cout
#include <map>
#include <nlohmann/json.hpp>
#include <string>
#include <vector>
using json = nlohmann::json;
using object_t = std::map<std::string, std::string>;
using objects_t = std::vector<object_t>;
int main() {
std::string str{R"({ "Main": [ { "obj1": "bar" }, { "obj2": "foo" } ] })"};
json j = json::parse(str);
auto objects{ j.at("Main").get<objects_t>() };
fmt::print("{}", objects);
}
// Outputs:
//
// [{"obj1": "bar"}, {"obj2": "foo"}]
Upvotes: 3