user writes access path to a nested element in a JSON file - c++

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"

Related

Parse json array string using jsoncpp

I have this JSON:
[{"header": "test" , "test2" : "test2"}]
I'm trying to parse this using jsoncpp.
Here's my code snippet:
Json::CharReaderBuilder builder;
Json::CharReader *reader = builder.newCharReader();
Json::Value root;
bool parseRet = reader->parse(serverResponse.c_str(),serverResponse.c_str() +serverResponse.size(), &root, &errors);
parseRet returns true. But root does not include json data.
How do I parse this?
parseRet returns true. But root does not include JSON data.
This sounds like an issue with the way you're accessing the parsed JSON elements.
Below is a complete working example with a raw string literal as JSON input.
A few points:
Use std::unique_ptr for reader to de-allocate memory appropriately at the end. In your code snippet, it's a memory leak.
Read the documentation carefully! Accessing an element using a method or operator might return a default value or an exception so handle accordingly. For example, the JSON in root is an array so it should be accessed by index and then each index contains an object i.e. root[0]["header"].
Example (C++11):
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
int main()
{
const std::string raw_json = R"json([{"header": "test" , "test2" : "test2"}])json";
Json::CharReaderBuilder builder {};
// Don't leak memory! Use std::unique_ptr!
auto reader = std::unique_ptr<Json::CharReader>( builder.newCharReader() );
Json::Value root {};
std::string errors {};
const auto is_parsed = reader->parse( raw_json.c_str(),
raw_json.c_str() + raw_json.length(),
&root,
&errors );
if ( !is_parsed )
{
std::cerr << "ERROR: Could not parse! " << errors << '\n';
return -1;
}
std::cout << "Parsed JSON:\n" << root << "\n\n";
try
{
std::cout << "header: " << root[0]["header"] << '\n';
std::cout << "test2 : " << root[0]["test2"] << '\n';
}
catch ( const Json::Exception& e )
{
std::cerr << e.what() << '\n';
}
return 0;
}
Output:
Parsed JSON:
[
{
"header" : "test",
"test2" : "test2"
}
]
header: "test"
test2 : "test2"

access json array values in c++

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.

Assigning numbers to .json data for editing C++

I need to assign users input number to the displayed part of .json data so that I can edit the data in a latter function.
I have this code:
int choice;
int numeration = 1;
for (auto& check : airports.items()) //outputs airport city and airport code numbered from 1
{
std::cout << numeration << ". " << airports[check.key()]["city"] << " " << airports[check.key()]["shortVersion"] << std::endl;
numeration++;
}
std::cout << "Your choice"; //user inputs the number of the displayed airport
std::cin >> choice;
And this is the .json file.
{
"(LGW)": {
"address": "Horley, Gatwick RH6 0NP, UK",
"city": "London",
"shortVersion": "(LGW)"
},
"(RIX)": {
"address: "Marupe, LV-1053",
"city": "Riga",
"shortVersion": "(RIX)"
}
}
How do I assign the number that the user input to the displayed airport so that the program later edits the variables only from the selected data or deletes the whole group like (LGW) or (RIX) seperately? For instance, user inputs 1 (That's for (LGW)) and later he can edit the city, address or shortVersion variables under (LGW).
I would store the airports in an array as follows:
{
"airports": [{
"address": "Horley, Gatwick RH6 0NP, UK",
"city": "London",
"shortVersion": "(LGW)"
},
{
"address": "Marupe, LV-1053",
"city": "Riga",
"shortVersion": "(RIX)"
}
]
}
Arrays in json are ordered, see: json.org. You would then use the index entered by the user to access the desired airport.
Edit: The index is implied based on the order of the airport within the json array. "London" will be index 0, "Riga" 1 etc...
Code to access the airport would depend on the json library that you are using. The pseudo-code for this would be something like:
int user_selection = 1; // Whatever number the user picked...
JsonArray airports = json["airports"];
JsonObject airport = airports[user_selection]; // Index the array based on user's input
airport["city"] = "Amsterdam"; // Change city from Riga to Amsterdam
Edit2: Using nlohmann json library:
#include "json.hpp"
#include <iostream>
#include <string>
std::string GenerateJson(const std::string& city, const std::string& address, const std::string& iata_code)
{
json j;
json j_array = json::array();
json j_object = json::object();
j_object["city"] = city;
j_object["address"] = address;
j_object["shortVersion"] = iata_code;
j_array.emplace_back(j_object);
j["airports"] = j_array;
return j.dump(4);
}
int main()
{
auto json = R"(
{
"airports": [{
"address": "Horley, Gatwick RH6 0NP, UK",
"city": "London",
"shortVersion": "LGW"
},
{
"address": "Marupe, LV-1053",
"city": "Riga",
"shortVersion": "RIX"
}
]
}
)"_json;
int index = 1;
auto& airports = json["airports"];
for (const auto& airport : airports)
{
std::cout << index << ") " << airport["city"].get<std::string>() << " " << airport["shortVersion"].get<std::string>() << std::endl;
++index;
}
int choice = 0;
std::cout << "Your choice:" << std::endl;
std::cin >> choice;
choice -= 1;
std::string iata_code;
std::cout << "Change IATA airport code:" << std::endl;
std::cin >> iata_code;
auto& airport = airports[choice];
airport["shortVersion"] = iata_code;
std::cout << json.dump(4) << std::endl;
int any;
std::cout << "Press any key to exit..." << std::endl;
std::cin >> any;
}

C++ nlohmann JSON get name of array

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;
}

Reading Array of the json in JsonCpp

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];