I'm new to c++ and trying to use nlohmann library and I'm quite stuck. I want to modify array of objects from json.
json =
{
"a": "xxxx",
"b": [{
"c": "aaa",
"d": [{
"e": "yyy"
},
{
"e": "sss",
"f": "fff"
}
]
}]
}
now I want to replace e value with "example" in the above structure. Could some one help me.
I tried to loop through the json structure and was able to read the "e" value but can't replace it. I tried: `
std::vector<std::string> arr_value;
std::ifstream in("test.json");
json file = json::parse(in);
for (auto& td : file["b"])
for (auto& prop : td["d"])
arr_value.push_back(prop["e"]);
//std::cout<<"prop" <<prop["e"]<< std::endl;
for (const auto& x : arr_value)
std::cout <<"value in vector string= " <<x<< "\n";
for (decltype(arr_value.size()) i = 0; i <= arr_value.size() - 1; i++)
{
std::string s = arr_value[i]+ "emp";
std::cout <<"changed value= " <<s << std::endl;
json js ;
js = file;
std::ofstream out("test.json");
js["e"]= s;
out << std::setw(4) << js << std::endl;
}
The following appends MODIFIED to every "e"-value and writes the result to test_out.json:
#include <vector>
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main() {
std::ifstream in("test.json");
json file = json::parse(in);
for (auto& td : file["b"])
for (auto& prop : td["d"]) {
prop["e"] = prop["e"].get<std::string>() + std::string(" MODIFIED");
}
std::ofstream out("test_out.json");
out << std::setw(4) << file << std::endl;
}
The prop["e"] = ... line does three things:
It gets the property with key "e",
Coerces it into a string using .get<std::string>() and appends "modified", and
writes back the result to prop["e"], which is a reference to the object nested in the JSON structure.
Related
I wrote a code that prompts the user for the access path to an element in a JSON file and then retrieves the value of that element. But I can only get access to a root element. What should user write to e.g. get object.array[2].field? I use single include nlohmann/json library.
My code:
using json = nlohmann::json;
int main() {
std::ifstream file("test3.json");
json data;
file >> data;
std::string access_path;
std::cout << "Enter the access path to the nested element (e.g. 'object.array[2].field'): ";
std::getline(std::cin, access_path);
try {
json nested_element = data.at(access_path);
std::cout << "Value of element: " << nested_element.dump() << std::endl;
} catch (json::out_of_range& e) {
std::cout << "Error: Invalid access path." << std::endl;
}
return 0;
}
First of all, you need a json_pointer.
json nested_element = data.at(json::json_pointer(access_path));
Then accessing field in array[2] in object would be entered by the user as
/object/array/2/field
Example version of the test3.json file:
{
"object": {
"array": [{
"field": "foo"
},
{
"field": "bar"
},
{
"field": "hello world"
}
]
}
}
Output:
Value of element: "hello world"
I have nlohmann json object:
json uuid = R"(
{
"uuid": ["aaa","bbb","ccc"]
}
)"_json;
I can get the values in array without problems: str = uuid["uuid"][0];
But how can i get array name himself ?
You can get the underlying map from the json object which gives you the array names and the arrays. If you just want to iterate through the items that's easy as well.
#include <iostream>
#include <json.hpp>
using json = nlohmann::json;
int main()
{
json uuid = R"(
{
"uuid": ["aaa","bbb","ccc"],
"uuie": ["aaa","bbb","ccc"],
"uuif": ["aaa","bbb","ccc"]
}
)"_json;
if (uuid.is_object())
{
auto obj = uuid.get<json::object_t>();
for (auto& kvp : obj)
{
std::cout << kvp.first << ":" << kvp.second << "\n";
}
}
for (auto& item : uuid)
{
std::cout << item << "\n";
}
return 0;
}
I tried to write a simple JSON reader for my program then I use JsonCpp. I have this JSON from my web server:
{
"return":
{
"status":200,
"message":"Accepted"
},
"entries":
[
{
"messageid":185002992,
"message":"CplusItsGood",
"status":1,
"statustext":"test",
"sender":"1234567",
"receptor":"123456789",
"date":1234,
"cost":140
}
]
}
And this is my C++ code:
Json::Reader reader;
Json::Value root;
reader.parse(jsonContext, root, false);
const Json::Value entriesArray = root["return"]["entries"];
int A = entriesArray["sender"].asInt();
cout << A;
It's print only 0, I can't read the sender or any other element of the entries array.
I want get the value of the cost or sender for example.
How can I do that?
your root contains 2 elements "return" and "entries" so or
root["return"] or root["entries"]
Then - array contains a list of members - so even if it only one entry - you still have to get it.
if value is quoted - it is string - you cannot use getInt on it. For example getInt is applicable to "status" not "sender"
Here is the whole sample
#include <iostream>
#include <string>
#include <json/json.h>
int main()
{
std::string s = R"({
"return":
{
"status":200,
"message":"Accepted"
},
"entries":
[
{
"messageid":185002992,
"message":"CplusItsGood",
"status":1,
"statustext":"test",
"sender":"1234567",
"receptor":"123456789",
"date":1234,
"cost":140
}
]
})";
Json::Reader reader;
Json::Value root;
reader.parse(s, root, false);
auto entriesArray = root["entries"];
auto firstelem = entriesArray[0];
std::string sender = firstelem["sender"].asString();
int i = std::stoi(sender);
std::cout << "array:" << entriesArray << "\n";
std::cout << "element:" << firstelem << "\n";
std::cout << "value:" << sender << "\n";
std::cout << "parsed value:" << i << "\n";
}
Output
array:[
{
"cost" : 140,
"date" : 1234,
"message" : "CplusItsGood",
"messageid" : 185002992,
"receptor" : "123456789",
"sender" : "1234567",
"status" : 1,
"statustext" : "test"
}
]
element:{
"cost" : 140,
"date" : 1234,
"message" : "CplusItsGood",
"messageid" : 185002992,
"receptor" : "123456789",
"sender" : "1234567",
"status" : 1,
"statustext" : "test"
}
value:1234567
parsed value:1234567
For arrays with only 1 object, use 0.
const Json::Value entriesArray = root["entries"][0];
I have this code that I need to parse/or get the JSON array as std::string to be used in the app.
std::string ss = "{ \"id\" : \"123\", \"number\" : \"456\", \"stuff\" : [{ \"name\" : \"test\" }] }";
ptree pt2;
std::istringstream is(ss);
read_json(is, pt2);
std::string id = pt2.get<std::string>("id");
std::string num= pt2.get<std::string>("number");
std::string stuff = pt2.get<std::string>("stuff");
What is needed is the "stuff" to be retrieved like this as std::string [{ "name" : "test" }]
However the code above stuff is just returning empty string. What could be wrong
Arrays are represented as child nodes with many "" keys:
docs
JSON arrays are mapped to nodes. Each element is a child node with an empty name. If a node has both named and unnamed child nodes, it cannot be mapped to a JSON representation.
Live On Coliru
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using boost::property_tree::ptree;
int main() {
std::string ss = "{ \"id\" : \"123\", \"number\" : \"456\", \"stuff\" : [{ \"name\" : \"test\" }, { \"name\" : \"some\" }, { \"name\" : \"stuffs\" }] }";
ptree pt;
std::istringstream is(ss);
read_json(is, pt);
std::cout << "id: " << pt.get<std::string>("id") << "\n";
std::cout << "number: " << pt.get<std::string>("number") << "\n";
for (auto& e : pt.get_child("stuff")) {
std::cout << "stuff name: " << e.second.get<std::string>("name") << "\n";
}
}
Prints
id: 123
number: 456
stuff name: test
stuff name: some
stuff name: stuffs
Since "stuff" is an array, you can iterate over the elements of it, which are dictionaries. And then you can iterate over the elements of the dictionary, which are key-value pairs:
for (const auto& dict : pt2.get_child("stuff")) {
for (const auto& kv : dict.second) {
std::cout << "key = " << kv.first << std::endl;
std::cout << "val = " << kv.second.get_value<std::string>() << std::endl;
}
}
continue with #sehe 's answer, related to the question asked by #xkm
Is it possible to get it like '[{ "name" : "some" }, { "name" : "stuffs" }]'
Yes, you can. Just treat it with an "unnamed" key which means the key with empty string.
f.g.
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
using boost::property_tree::ptree;
int main()
{
std::stringstream ss;
ss << R"([{"a": 5}, {"a": 9}])";
ptree pt;
read_json(ss, pt);
for (auto& item : pt.get_child(""))
std::cout << "value is " << item.second.get<int>("a") << std::endl;
}
How can I get data from JSON with array as root node by using Boost.PropertyTree?
[
{
"ID": "cc7c3e83-9b94-4fb2-aaa3-9da458c976f7",
"Type": "VM"
}
]
The array elements are just values with a key named "" for property tree:
for (auto& array_element : pt) {
for (auto& property : array_element.second) {
std::cout << property.first << " = " << property.second.get_value<std::string>() << "\n";
}
}
Prints
ID = cc7c3e83-9b94-4fb2-aaa3-9da458c976f7
Type = VM
Live On Coliru
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
using namespace boost::property_tree;
int main()
{
std::istringstream iss(R"([
{
"ID": "cc7c3e83-9b94-4fb2-aaa3-9da458c976f7",
"Type": "VM"
}
]
)");
ptree pt;
json_parser::read_json(iss, pt);
for (auto& array_element : pt) {
for (auto& property : array_element.second) {
std::cout << property.first << " = " << property.second.get_value<std::string>() << "\n";
}
}
}