JSON Data using Boost - c++

Is it possible to read the following data below using boost?
{
"ok": true,
"result": [
{
"update_id": 1235285,
"message": {
"message_id": 2,
"from": {
"id": 3325446,
"is_bot": false,
"first_name": "Test",
"language_code": "en-PH"
},
"chat": {
"id": 12532541,
"first_name": "Test Account",
"type": "private"
},
"date": 152014521,
"text": "Test Message"
}
}
]
}

You could see the linked post in comment,
To summarize you can have like following to read from a file say mfile.json :
boost::property_tree::ptree pt;
boost::property_tree::read_json("myfile.json", pt);
print_contents( pt );
where print_contents is:
void print_contents( const boost::property_tree::ptree& pt)
{
using boost::property_tree::ptree;
for (const auto& x: pt )
{
std::cout << x.first << ": " << x.second.get_value<std::string>() << std::endl;
print_contents(x.second);
}
}
See Here
I could have closed it as duplicate, but looks like there was no "better" post for reading a json file

Related

How to apply custom score to a search filed in Elastic Search

I am making a search query in Elastic Search and I want to treat the fields the same when they match. For example if I search for field field1 and it matches, then the _score is increase by 10(for example), same for the field2.
I was tried function_score but it's not working. It throws an error.
"caused_by": {
"type": "class_cast_exception",
"reason": "class
org.elasticsearch.index.fielddata.plain.SortedSetDVOrdinalsIndexFieldData
cannot be cast to class
org.elasticsearch.index.fielddata.IndexNumericFieldData
(org.elasticsearch.index.fielddata.plain.SortedSetDVOrdinalsIndexFieldData
and org.elasticsearch.index.fielddata.IndexNumericFieldData are in unnamed
module of loader 'app')"
}
The query:
{
"track_total_hits": true,
"size": 50,
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"term": {
"field1": {
"value": "Value 1"
}
}
},
{
"term": {
"field2": {
"value": "value 2"
}
}
}
]
}
},
"functions": [
{
"field_value_factor": {
"field": "field1",
"factor": 10,
"missing": 0
}
},
{
"field_value_factor": {
"field": "field2",
"factor": 10,
"missing": 0
}
}
],
"boost_mode": "multiply"
}
}
}
You can use function score with filter function to boost.
assuming that your mapping looks like the one below
{
"mappings": {
"properties": {
"field_1": {
"type": "keyword"
},
"field_2": {
"type": "keyword"
}
}
}
}
with documents
{"index":{}}
{"field_1": "foo", "field_2": "bar"}
{"index":{}}
{"field_1": "foo", "field_2": "foo"}
{"index":{}}
{"field_1": "bar", "field_2": "bar"}
you can use weight parameter to boost the documents matched for each query.
{
"query": {
"function_score": {
"query": {
"match_all": {}
},
"functions": [
{
"filter": {
"term": {
"field_1": "foo"
}
},
"weight": 10
},
{
"filter": {
"term": {
"field_2": "foo"
}
},
"weight": 20
}
],
"score_mode": "multiply"
}
}
}
You can refer below solution if you want to provide manual weight for different field in query. This will always replace highest weight field on top of your query response -
Elasticsearch query different fields with different weight

How to edit a json file using jsoncons?

I am using jsoncons, which is a requirement for this question.
I am trying to edit some fields in a deeply nested json file, for example the following one:
{
"Error": null,
"HubNotificationId": "8a321f40-3692-11ec-b2a8-02420a0000fc",
"HubNotificationTimestamp": "2021-10-26T19:25:55.330812",
"MessageTimestampUtc": "2021-10-26T19:25:55",
"Result": "SUCCESS",
"ScanId": "0789e64f-87a7-42b0-a912-362acad7536c",
"ScanTimestampUtc": "2021-10-26T19:25:44",
"Source": {
"InstanceId": "",
"ModuleId": "atlas",
"ServiceId": "uv-acquisition-manager",
"ServiceVersion": "2.1.0-0001",
"SiteId": "rnd-oem-holon"
},
"Type": "ScanNotification",
"Version": "2.8.0",
"abortReason": null,
"context": "scan/end",
"data": [
{
"frameGrabberId": "at-uv-dm-fg1",
"scanLocation": {
"Original_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Original_ScaledDown",
"uri": "INJECTED"
},
"Undistorted_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Undistorted_ScaledDown",
"uri": "INJECTED"
},
"Unprocessed": {
"keyPrefix": "a0366334-b44b-459e-8484-8a0c835c6889/c5424457-9066-4d82-9ab9-df5cc2a17c21/20201006/2020-10-06T11-16-04.000Z_98021622-12ff-455b-972d-79af24c169a1",
"mimeType": "",
"role": "Unprocessed",
"uri": "INJECTED"
}
}
},
{
"frameGrabberId": "at-uv-dm-fg2",
"scanLocation": {
"Original_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Original_ScaledDown",
"uri": "INJECTED"
},
"Undistorted_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Undistorted_ScaledDown",
"uri": "INJECTED"
},
"Unprocessed": {
"keyPrefix": "INJECTED",
"mimeType": "",
"role": "Unprocessed",
"uri": "INJECTED"
}
}
},
{
"frameGrabberId": "at-uv-dm-fg3",
"scanLocation": {
"Original_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Original_ScaledDown",
"uri": "INJECTED"
},
"Undistorted_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Undistorted_ScaledDown",
"uri": "INJECTED"
},
"Unprocessed": {
"keyPrefix": "a0366334-b44b-459e-8484-8a0c835c6889/c5424457-9066-4d82-9ab9-df5cc2a17c21/20201006/2020-10-06T11-16-04.000Z_98021622-12ff-455b-972d-79af24c169a1",
"mimeType": "",
"role": "Unprocessed",
"uri": "INJECTED"
}
}
},
{
"frameGrabberId": "at-uv-dm-mgr",
"scanLocation": {
"Original_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Original_ScaledDown",
"uri": "INJECTED"
},
"Undistorted_ScaledDown": {
"keyPrefix": null,
"mimeType": "",
"role": "Undistorted_ScaledDown",
"uri": "INJECTED"
},
"Unprocessed": {
"keyPrefix": "a0366334-b44b-459e-8484-8a0c835c6889/c5424457-9066-4d82-9ab9-df5cc2a17c21/20201006/2020-10-06T11-16-04.000Z_98021622-12ff-455b-972d-79af24c169a1",
"mimeType": "",
"role": "Unprocessed",
"uri": "INJECTED"
}
}
}
],
"dynamicMetaData": {
"vehicleParams": {
"color": "122",
"model": "225",
"vendor": "a"
}
},
"scanDuration_sec": 10.98,
"shotsCount": 96,
"sourceInfo": [],
"staticMetaData": null
}
I want to edit some of the keys - for example, the uri keys.
How to use the library to be able to edit the json and save an edited copy?
What I have so far is
const jsoncons::json& TestMessage::injectPathToFMTemplate(const std::string &scanPath) {
auto& raw = this->_raw_input;
auto& parsed = this->_templateMessage;
auto parsedTree = parsed.as<std::map<std::string, jsoncons::json>>();
auto dataPos = parsedTree.find("data");
auto& data = dataPos->second;
auto grabbers = data.as<std::vector<std::map<std::string, jsoncons::json>>>();
int grabberIndex = 0;
for (auto& grabberTree : grabbers){
auto scanLocationPos = grabberTree.find("scanLocation");
auto scanLocationTree = scanLocationPos->second.as<std::map<std::string, jsoncons::json>>();
auto Original_ScaledDownPos = scanLocationTree.find("Original_ScaledDown");
auto Undistorted_ScaledDownPos = scanLocationTree.find("Undistorted_ScaledDown");
auto UnprocessedPos = scanLocationTree.find("Unprocessed");
auto Original_ScaledDownPosTree = Original_ScaledDownPos->second.as<std::map<std::string, jsoncons::json>>();
auto Undistorted_ScaledDownPosTree = Original_ScaledDownPos->second.as<std::map<std::string, jsoncons::json>>();
auto UnprocessedPosTree = Original_ScaledDownPos->second.as<std::map<std::string, jsoncons::json>>();
auto uriPos1 = Original_ScaledDownPosTree.find("uri");
auto uriPos2 = Undistorted_ScaledDownPosTree.find("uri");
auto uriPos3 = UnprocessedPosTree.find("uri");
uriPos1->second = scanPath;
uriPos2->second = scanPath;
uriPos3->second = scanPath;
++grabberIndex;
}
parsed = jsoncons::json(parsedTree);
auto s = parsed.as<std::string>();
return parsed;
Which goes all the way down to the uri fields, but then can't edit them because nothing is (or can be) by reference, and I find that I have to re-build all of the json object again, which makes no sense.
I am sure the library allows this somehow, just can't find out how.
The jsoncons library provides a number of options for editing a JSON value, but a simple way is
std::string scanPath = "FOO";
try
{
json root = json::parse(input);
json& data = root.at("data");
for (auto& grabberTree : data.array_range())
{
json& scanLocationTree = grabberTree.at("scanLocation");
json& Original_ScaledDown = scanLocationTree.at("Original_ScaledDown");
json& Undistorted_ScaledDown = scanLocationTree.at("Undistorted_ScaledDown");
json& Unprocessed = scanLocationTree.at("Unprocessed");
Original_ScaledDown.at("uri") = scanPath;
Undistorted_ScaledDown.at("uri") = scanPath;
Unprocessed.at("uri") = scanPath;
}
std::cout << pretty_print(root) << "\n";
}
catch (const std::exception& e)
{
std::cout << e.what() << "\n";
}

Read a sub json using boost property tree

I need to read a field in a JSON file which itself is a JSON. I need to read the JSON field in one go. Is there any way available? Sample JSON I am trying to read is provided below.
enter code here
{
"responses": [
{
"id": "1",
"status": 200,
"headers": {
"OData-Version": "4.0",
"Content-Type":"application/json;odata.metadata=minimal;odata.streaming=true"
},
"body": {
"createdDateTime": "2021-04-22T09:24:59.394Z",
"displayName": "Test1",
"visibility": "public",
"isMembershipLimitedToOwners": false,
"discoverySettings": { "showInTeamsSearchAndSuggestions": true },
"memberSettings": {
"allowCreateUpdateChannels": true,
"allowCreateUpdateRemoveConnectors": true
},
"guestSettings": {
"allowCreateUpdateChannels": true,
"allowDeleteChannels": false
},
"messagingSettings": {
"allowUserEditMessages": true,
"allowChannelMentions": true
},
"funSettings": {
"allowGiphy": true,
"allowCustomMemes": true
}
} } ]
}
I am trying to read the "body" field using the code below (json is read in boost::property_tree::ptree jsonBatchResponse jsonBatchResponse). But strBody is empty and it doesn't read the "Body" field correctly. :
enter code here
for (auto& v : jsonBatchResponse.get_child("responses"))
{
std::string strID = v.second.get<std::string>("id", "");
std::string strStatus = v.second.get<std::string>("status", "");
std::string strBody = v.second.get<std::string>("body", "");
}
It looks like v.second.getstd::string("body", "") is not the right way to read the JSON field. Is there any other way available (other than reading individual fields in the JSON value)? Please let me know.
The body is not a string.
So, getting the child object would be in order:
for (auto const& v : jsonBatchResponse.get_child("responses")) {
std::string strID = v.second.get<std::string>("id", "");
std::string strStatus = v.second.get<std::string>("status", "");
ptree const& body = v.second.get_child("body");
}
If you add some output to that loop with e.g.
std::cout << std::quoted(strID) << "\n";
std::cout << std::quoted(strStatus) << "\n";
write_json(std::cout, body);
It will print Live On Coliru
"1"
"200"
{
"createdDateTime": "2021-04-22T09:24:59.394Z",
"displayName": "Test1",
"visibility": "public",
"isMembershipLimitedToOwners": "false",
"discoverySettings": {
"showInTeamsSearchAndSuggestions": "true"
},
"memberSettings": {
"allowCreateUpdateChannels": "true",
"allowCreateUpdateRemoveConnectors": "true"
},
"guestSettings": {
"allowCreateUpdateChannels": "true",
"allowDeleteChannels": "false"
},
"messagingSettings": {
"allowUserEditMessages": "true",
"allowChannelMentions": "true"
},
"funSettings": {
"allowGiphy": "true",
"allowCustomMemes": "true"
}
}
BONUS: Using a proper JSON library instead
Boost Property Tree is NOT a JSON library, and therefore has a lot of limitations.
Instead I suggest using Boost JSON:
Live On Coliru
#include <boost/json.hpp>
#include <boost/json/src.hpp>
#include <iostream>
namespace json = boost::json;
extern std::string sample;
int main() {
json::object jsonBatchResponse = json::parse(sample).as_object();
for (auto& v : jsonBatchResponse["responses"].as_array()) {
auto& res = v.as_object();
json::value id = res["id"], // string
status = res["status"], // integer
body = res["body"]; // object
std::cout << id << "\n";
std::cout << status << "\n";
std::cout << body << "\n";
}
}
std::string sample = R"(
{
"responses": [{
"id": "1",
"status": 200,
"headers": {
"OData-Version": "4.0",
"Content-Type": "application/json;odata.metadata=minimal;odata.streaming=true"
},
"body": {
"createdDateTime": "2021-04-22T09:24:59.394Z",
"displayName": "Test1",
"visibility": "public",
"isMembershipLimitedToOwners": false,
"discoverySettings": {
"showInTeamsSearchAndSuggestions": true
},
"memberSettings": {
"allowCreateUpdateChannels": true,
"allowCreateUpdateRemoveConnectors": true
},
"guestSettings": {
"allowCreateUpdateChannels": true,
"allowDeleteChannels": false
},
"messagingSettings": {
"allowUserEditMessages": true,
"allowChannelMentions": true
},
"funSettings": {
"allowGiphy": true,
"allowCustomMemes": true
}
}
}]
}
)";
Prints
"1"
200
{"createdDateTime":"2021-04-22T09:24:59.394Z","displayName":"Test1","visibility":"public","isMembershipLimitedToOwners":false,"discoverySettings":{"showInTeamsSearchAndSuggestions":true},"memberSettings":{"allowCreateUpdateChannels":true,"allowCreateUpdateRemoveConnectors":true},"guestSettings":{"allowCreateUpdateChannels":true,"allowDeleteChannels":false},"messagingSettings":{"allowUserEditMessages":true,"allowChannelMentions":true},"funSettings":{"allowGiphy":true,"allowCustomMemes":true}}

Keyname not found in json

I'm trying to create my own Telegram bot as a project and don't want to use any of the libraries already out there that already do all the hard work for me as I want to do this for myself as on going self learning.
I'm using CPPRESTSDK and trying to get values from the JSON back from telegram.
Here is an example of the JSON
{
"ok": true,
"result": [
{
"update_id": 534699960,
"message": {
"message_id": 159183,
"from": {
"id": HIDDEN,
"is_bot": false,
"first_name": "Hawke",
"username": "XXXXXXXX"
},
"chat": {
"id": HIDDEN,
"title": "CHANNEL_NAME_HIDDEN",
"username": "HIDDEN",
"type": "supergroup"
},
"date": 1548427328,
"text": "Nope, at work"
}
}
]
}
I'm trying to read the text value but I'm getting Keyname not found when trying to access result. The above JSON is stored into a file once retrieving the JSON from telegram.
try {
string_t importFile = U("json.txt");
ifstream_t f(importFile);
stringstream_t s;
json::value v;
if (f) {
s << f.rdbuf();
f.close();
v = json::value::parse(s);
auto results_array = v.at(U("result")).as_array();
}
}
catch (web::json::json_exception& excep) {
std::cout << excep.what();
}

c++ json-nlohmann accessing the list elements

I'm trying to use json-nlohmann library to read JSON files in C++
So far I got along with it preatty well, but now I'm trying to access elements of the list in given json. JSON:
{
"GameMap": "path_to_game_map",
"Objects": [
{ "object_1": { "Transform": { "Position": { "X": 1, "Y": 2 }, "Rotation": { "X": 3.5, "Y": 8.2 }, "Scale": { "X": 1, "Y":1 } },
"Components": [
{ "0": { "data": { "some_data": "false" } } },
{ "1": { "data": { "some_data": "false" } } },
{ "2": { "data": { "some_data": "false" } } }
] } },
{ "object_2": { "Transform": { "Position": { "X": 1, "Y": 2 }, "Rotation": { "X": 3.5, "Y": 8.2}, "Scale": { "X": 1, "Y":1 } },
"Components": [
{ "0": { "data": { "some_data": "false" } } },
{ "1": { "data": { "some_data": "false" } } },
{ "2": { "data": { "some_data": "false" } } }
] } }
]
}
Where I'm trying to access each Component and read it's key value.
I've got an object out for every Component. But I just cannot figure out how to read its key and value.
Help! Please.
When you iterate a JSON object, say j, you can access the key and value like this:
for (json::iterator it = j.begin(); it != j.end(); ++it) {
std::cout << it.key() << " : " << it.value() << "\n";
}
you can also now use for (auto& element : j.items()) and then element.key() and element.value() inside the loop.