How can I parse unpredictable JSON fields in c++? - c++

So, I access an API an receive data in JSON format as shown below. I'm looking to draw a chart with the dates on the "x" axis and the Data on the "y" axis. I donĀ“t know what dates I will be getting, and they will be plenty. I want to save that data in an array/vector of objects that contain a structure containing the date and value at that date. Because this isn't a key-value relation, I do not know how to parse it, do you?
Structure
typedef struct
{
float Data;
string date;
}Data_t;
JSON received
"Information: Data": {
"2021-06-01 16:00:01": {
"Data": "139.5578"
},
"2021-05-28": {
"Data": "137.7645"
},
"2021-05-21": {
"Data": "135.8931"
},
"2021-05-14": {
"Data": "133.6110"
}
...
...
...

Related

How to read Json string starting with square brackets in it? [duplicate]

This question already has an answer here:
How to use boost::property_tree to parse JSON with array root
(1 answer)
Closed 2 years ago.
I am using c++ code to read json string to retrieve value based on specific key names. Example of my json response from web API is in array format like below.
[
{
"username": "123456",
"useraddress": "abc",
"data": [
{
"schedule": true,
"task": "abc",
"risk": "1",
}
],
"date": "0000-00-00"
}
]
Like the above format is the actual response. I have to retrieve date value using key "date".
My code snippet:
{
std::stringstream jsonString;
boost::property_tree::ptree pt;
jsonString << ws2s(Info).c_str();
boost::property_tree::read_json(jsonString, pt);
std::string date = pt.get<std::string>("date");
}
'Info' in above snippet is wsstring containing json response data.
I can able to retrieve "date" if [] square brackets are removed manually. Since it is array format, if I pass without removing brackets, read_json throws error.
Can somebody help this out?
Yeah. Boost Property Tree is a property tree library, not JSON.
You're in luck though, Boost has a JSON library now https://www.boost.org/doc/libs/1_75_0/libs/json/doc/html/index.html
Note: your input isn't valid JSON either, because JSON doesn't strictly allow trailing commas. You can enable them with an option in Boost JSON though:
Live On Compiler Explorer
#include <boost/json.hpp>
#include <iostream>
int main() {
std::string input = R"(
[
{
"username": "123456",
"useraddress": "abc",
"data": [
{
"schedule": true,
"task": "abc",
"risk": "1",
}
],
"date": "0000-00-00"
}
])";
boost::json::parse_options options;
options.allow_trailing_commas = true;
auto json = boost::json::parse(input, {}, options);
for (auto& el : json.as_array()) {
std::cout << el.at("date") << "\n";
}
}
Prints
"0000-00-00"

Create a table in AWS athena parsing dynamic keys in nested json

I have JSON files each line of the format below and I would like to parse this data and index it to a table using AWS Athena.
{
"123": {
"abc": {
"id": "test",
"data": "ipsum lorum"
},
"abd": {
"id": "test_new",
"data": "lorum ipsum"
}
}
}
Can a table with this format be created for the above data? In the documentation, it is mentioned that struct can be used for parsing nested JSON, however, there are no sample examples for dynamic keys.
You could cast JSON to map or array and transform it in any way you want. In this case you could use map_values and CROSS JOIN UNNEST to produce rows from JSON objects:
with test AS
(SELECT '{ "123": { "abc": { "id": "test", "data": "ipsum lorum" }, "abd": { "id": "test_new", "data": "lorum ipsum" } } }' AS str),
struct_like AS
(SELECT cast(json_parse(str) AS map<varchar,
map<varchar,
map<varchar,
varchar>>>) AS m
FROM test),
flat AS
(SELECT item
FROM struct_like
CROSS JOIN UNNEST(map_values(m)) AS t(item))
SELECT
key,
value['id'] AS id,
value['data'] AS data
FROM flat
CROSS JOIN unnest(item) AS t(key, value)
The result:
key id data
abc test ipsum lorum
abd test_new lorum ipsum

Parsing JSON Responses Of Unknown Format For Single Value

I am creating a stock screener that sources data from ultiple apis. I would like to parse api responses from various apis for a single value.
I am using stock data apis that return JSON in different nested formats. Since the format of the JSON can be different, e.g. root could be an object or an array.. I am having trouble understanding how to go about this. I have successfully parsed JSON responses when the format is known. I am using qt, with no 3rd party libs, which seems to require that you parse these responses explcitly as I have done previously. How do I create a generic JSON parser that? Is this even possible?
Example: For this JSON response.. I would like to parse for "value"
{
"historical_data": [
{
"date": "2019-06-28",
"value": 197.92
}
],
"security": {
"id": "sec_agjrgj",
"company_id": "com_NX6GzO",
"stock_exchange_id": "sxg_ozMr9y",
"name": "Apple Inc",
"code": "EQS",
"currency": "USD",
"ticker": "AAPL",
"composite_ticker": "AAPL:US",
"figi": "BBG000B9Y5X2",
"composite_figi": "BBG000B9XRY4",
"share_class_figi": "BBG001S5N8V8"
},
"next_page": null
}
I also want to parse this JSON repsone for "value"
{
"date": "2019-06-28",
"value": 197.92
}
I am trying to not write a parser function for each api I use. I would like to be able to find if the JSON has a "value" and if so.. return its value.
You can use JsonPath for this. For example, using the jsoncons implementation of JsonPath, you can write
#include <iostream>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/json_query.hpp>
using namespace jsoncons;
int main()
{
std::string data = /* your JSON response */;
json root = json::parse(data);
// json_query returns an array of items that match the JsonPath expression
json result = jsonpath::json_query(root, "$..value");
for (const auto& item : result.array_range())
{
std::cout << item << "\n";
}
}
Output:
197.92

How to change json object name without changing its values in C++?

I'm using json for modern c++.
And I have a json file which contains some data like:
{
"London": {
"Adress": "londonas iela 123",
"Name": "London",
"Shortname": "LL"
},
"Riga": {
"Adrese": "lidostas iela 1",
"Name": "Riga",
"Shortname": "RIX"
}
And I found out a way to modify the values of "Adrese", "Name", "Shortname".
As you can see I have "name" and key element name set to the same thing.
But I need to change both the key element and value "name".
So at the end when somehow in the code I modify it, it would look like:
{
"Something_New": {
"Adress": "londonas iela 123",
"Name": "Something_New",
"Shortname": "LL"
},
"Riga": {
"Adrese": "lidostas iela 1",
"Name": "Riga",
"Shortname": "RIX"
}
I've tried:
/other_code/
json j
/functions_for_opening_json file/
j["London"]["Name"] = "Something_New"; //this changes the value "name"
j["London"] = "Something_New"; //But this replaces "London" with
"Something_new" and deletes all of its inside values.
Then I tried something like:
for(auto& el : j.items()){
if(el.key() == "London"){
el.key() = "Something_New";}
}
But that didn't work either.
I would like something like j["London"] = "Something_new", and for it to keep all the values that originally was for "London".
The value associated with key "London" is the entire subtree json object containing the other 3 keys with their values. This line j["London"] = "Something_New"; does not change the key, "London" but its value. So you end up with the pair "London" : "Something new", overwriting the json subtree object. The keys are stored internally as std::map . Therefore you can't simply rename a key like that. Try:
void change_key(json &j, const std::string& oldKey, const std::string& newKey)
{
auto itr = j.find(oldKey); // try catch this, handle case when key is not found
std::swap(j[newKey], itr.value());
object.erase(itr);
}
And then
change_key(j, "London", "Something_New");

Rails, Highchart maps - adding custom data

I need some basic assistance with a Highmap (via Highcharts) I am trying to put in my Rails 4 app. I suspect I have some fundamental misunderstanding of it but can't find any clear guidance.
See a simple fiddle taken from the documentation, here
http://jsfiddle.net/SimonWalsh/zpdc1btu/
What I ultimately need to do is provide membership numbers for each country so that it will be displayed much the same as the population density is in this map.
I know I need to provide my data and the means to join it to the map data in
series : [{
data : data,
mapData: Highcharts.maps['custom/world'],
joinBy: ['iso-a2', 'code'],
name: 'Population density',
states: {
hover: {
color: '#BADA55'
}
}
}]
In this example, I am guessing that the data is being pulled from an external source and that the map data is the 'iso-a2' part of the array.
If this is the case, then why can't I supply this with my data....as an example see the added array with my data.....(just one example given for Denmark)
var mydata = [
{
"iso-a2": "dk",
"value": 30
},
]
and then do
series : [{
data : mydata,
mapData: Highcharts.maps['custom/world'],
joinBy: ['iso-a2', 'value'],
name: 'Population density',
states: {
hover: {
color: '#BADA55'
}
}
}]
This does not work.....any guidance at all (other than simply pointing me to docs would be greatly appreciated)
The joinBy specifies on which value you map a country with your data. With
joinBy: ['iso-a2', 'code']
you say that the 'iso-a2' value of the mapData should be equal to the 'code' value of your data. Therefore, your data must have this format:
var mydata = [
{
"code": "dk",
"value": 30
},
/* ... */
]