While trying parsing a json string in my c++ code, using the library minijson, I got a code like that so far:
<<"version">> [&]() { result.setVersion(v.as_long()); }
<<"capabilities">> [&]()
{
parse_array(ctx, [&](value capability)
{
result.getCapabilities().push_back(capability.as_string());
});
}
the data should be stored on this struct:
struct block_template {
int version;
vector<string> capabilities;
...
}
the version value is stored correctly, but the vector is staying with size 0. I try visualize the data being read from the json string ( with cout << capability.as_string() << endl ) and it's display correctly, just not being stored in the data structure.
Anyone who already worked with this library can give a hint of what's wrong here?
Since the OP asks for examples using other libraries in the comments, I'll reply more generally.
In jsoncons, if the JSON member names and the C++ variable names were the same, you could use the macro JSONCONS_ALL_MEMBER_TRAITS to set up the mappings,
#include <iostream>
#include <jsoncons/json.hpp>
struct block_template {
int version;
std::vector<std::string> capabilities;
};
JSONCONS_ALL_MEMBER_TRAITS(block_template, version, capabilities)
int main()
{
std::string input = R"(
{
"version" : 1,
"capabilities" : ["foo","bar","baz"]
}
)";
auto result = jsoncons::decode_json<block_template>(input);
std::cout << "(1)\n" << "version: " << val.version << "\n";
for (auto& item : val.capabilities)
{
std::cout << "item: " << item << "\n";
}
std::string output;
jsoncons::encode_json(val, output, jsoncons::indenting::indent);
std::cout << "(2)\n" << output << "\n\n";
}
Output:
(1)
version: 1
item: foo
item: bar
item: baz
(2)
{
"capabilities": ["foo", "bar", "baz"],
"version": 1
}
And if the JSON and C++ names were different, you could use the macro JSONCONS_ALL_MEMBER_NAME_TRAITS instead,
JSONCONS_ALL_MEMBER_NAME_TRAITS(block_template, (version,"Version"),
(capabilities,"Capabilities"))
With this change, the output becomes:
(1)
version: 1
item: foo
item: bar
item: baz
(2)
{
"Capabilities": ["foo", "bar", "baz"],
"Version": 1
}
See this answer for more examples of libraries that decode JSON to C++ data structures and encode back again, including Martin York's interesting ThorsSerializer.
Related
I was trying out C++20 ranges while working on my Vulkan project, I decided I wanted to try to check if a layer was available before the client added it in my builder object.
I set up my layer properties vector like so:
//...
vkEnumerateInstanceLayerProperties(&amount_of_layers, nullptr);
std::vector<VkLayerProperties> layer_properties(amount_of_layers);
vkEnumerateInstanceLayerProperties(&amount_of_layers, layer_properties.data());
//...
If I print them out like so, it works just fine:
for(auto& current_properties : layer_properties)
std::cout << current_properties.layerName << "\n";
The problem comes when I tried to use ranges to filter them, this is not the original filter I tried to apply, but this has similar problems:
auto available_layers = layer_properties | std::views::filter(
[&](auto current_layer_properties) {
return std::string{current_layer_properties.layerName}.size() % 2 == 0;
}
);
I just need a count at this point, not to iterate so I just store it in available_layers.
However if I try to print out current_layer_properties.layerName I get the first few layer names, and then what looks like a bunch of data that is from the data segment of the Vulkan library binaries, it looks like JSON.
VK_LAYER_MESA_device_select
VK_LAYER_INTEL_nullhw
VK_LAYER_MESA_overlay
VK_LAYER_LUNARG_monitor
VK_LAYER_KHRONOS_synchronization2
VK_LAYER_LUNARG_api_dump
E_CREATE_NEW",
"label": "Log File Overwrite",
"description": "Specifies that log file initialization should overwrite an existing file when true, or append to an existing file when false.",
"type": "BOOL",
"default": true
}
]
}
]
}
]
}
//...
Same happens if I try to apply std::views::transform and turn layer_properties into a container/view of std::string the same thing happens.
Sometimes depending on my filter (I use a find to find a string in it, then omit the element if its not found) it goes on forever.
Am I doing something wrong with ranges? Or does this have something to do with Vulkan?
Does it have something to do with some sort of side effect these LunarG .gfxr/gfxrecon_capture log files I am seeing(the erroneous output looks related, but could be totally random)?
UPDATE[ 0 ]:
Someone in the comments requested I show how I print things, it has changed as I have debugged, but I will put it here (it also crashes without printing)
In the lambda for std::filter and/or std::transform I have put variations of the following:
std::cout << current_layer_properties.layerName << "\n";
std::cout << current_layer_properties << "\n"; //When I apply std::transform and turn it into a std::string or std::string_view
log<LogType::Debug>(std::cout, current_layer_properties);
Here is my log function
template<typename LogParameterType>
void log(
LogParameterType& log,
const std::string_view message,
const std::source_location location =
std::source_location::current()
)
{
if constexpr(DebugParameterConstant == true
&& LogParameterConstant == LogType::Debug)
return;
log << to_string(LogParameterConstant) << "::"
<< location.file_name() << "("
<< location.line() << ":"
<< location.column() << ")::"
<< location.function_name() << ": "
<< message << "\n";
}
My debug layer is not working but here is the function it is suppose to run:
//If anyone can think of a better way to do this please let me know :)
void vulkan_log(
VkDebugUtilsMessageSeverityFlagBitsEXT vulkan_log_type,
VkDebugUtilsMessageTypeFlagsEXT message_type,
const VkDebugUtilsMessengerCallbackDataEXT* callback_data
)
{
LogType log_type = LogType::Unkown;
std::string message_type_string = to_string(message_type);
switch(vulkan_log_type)
{
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
{
std::cerr << message_type_string;
log<LogType::Diagnostic>(std::cerr, callback_data->pMessage);
break;
}
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
{
std::cerr << message_type_string;
log<LogType::Error>(std::cerr, callback_data->pMessage);
break;
}
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
{
std::cerr << message_type_string;
log<LogType::Warning>(std::cerr, callback_data->pMessage);
break;
}
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
{
std::cout << message_type_string;
log<LogType::Note>(std::cout, callback_data->pMessage);
break;
}
default:
break;
}
}
Thanks!
TFB
I have a very quick question...
I'm using nlohmann's json library.
My issue is that when I go to print a element, the program stops responding.
My json file
{
"Consoleprinting": false,
"Input" : [{"Code" : [{"Name": "EC", "Keybind": "VK_NUMPAD1"}] }]
}
What I have tried.
nlohmann::json jsonData = nlohmann::json::parse(i_Read);
std::cout << jsonData << std::endl;
for (auto& array : jsonData["Input"]) {
std::cout << array["Code"] << std::endl;
}
^ This works but it prints out
[{"Name": "EC", "Keybind": "VK_NUMPAD1"}]
How can I get this it print out just the name?
array["Code"] is an array containing a single collection of key-value pairs, so you need to write:
std::cout << array["Code"][0]["Name"] << std::endl;
I want to parse a json file/string with boosts property_tree, but instead of having sub-trees parsed into an array I would like it to stay as a string for use in another existing function which only deals with json-Strings.
I hope the following example is sufficient:
example.json
{
"type": "myType",
"colors": {
"color0":"red",
"color1":"green",
"color2":"blue"
}
}
main.cpp
std::stringstream ss("example.json");
ptree pt;
read_json(ss, pt);
std::string sType = pt.get("type", "");
std::string sColors = pt.get<std::string>("colors");
std::cout << "sType: " << sType << std::endl; // sType: myType
std::cout << "sColors: " << sColors << std::endl; // sColors: {"color0":"red", "color1":"green", "color2":"blue"}
I've tried several functions, for example pt.get_child("colors") would just return another ptree and pt.get_value<std::string>("colors") does return an empty string ("").
The desired output would look like this:
sColors: {"color0":"red", "color1":"green", "color2":"blue"}
or
sColors: {\"color0\":\"red\", \"color1\":\"green\", \"color2\":\"blue\"}
Is there a way to recive the desired output for sColors?
I found a possible solution faster than anticipated, the following code will provide a satisfactory answer:
std::stringstream os;
write_json(os, pt.get_child("colors"), false);
std::string sColors = os.str();
std::cout << "sColors: " << sColors << std::endl;
If there is a more elegant solution feel free to post it as well!
My JSON file resembles this
{
"active" : false,
"list1" : ["A", "B", "C"],
"objList" : [
{
"key1" : "value1",
"key2" : [ 0, 1 ]
}
]
}
Using nlohmann json now, I've managed to store it and when I do a dump jsonRootNode.dump(), the contents are represented properly.
However I can't find a way to access the contents.
I've tried jsonRootNode["active"], jsonRootNode.get() and using the json::iterator but still can't figure out how to retrieve my contents.
I'm trying to retrieve "active", the array from "list1" and object array from "objList"
The following link explains the ways to access elements in the JSON. In case the link goes out of scope here is the code
#include <json.hpp>
using namespace nlohmann;
int main()
{
// create JSON object
json object =
{
{"the good", "il buono"},
{"the bad", "il cativo"},
{"the ugly", "il brutto"}
};
// output element with key "the ugly"
std::cout << object.at("the ugly") << '\n';
// change element with key "the bad"
object.at("the bad") = "il cattivo";
// output changed array
std::cout << object << '\n';
// try to write at a nonexisting key
try
{
object.at("the fast") = "il rapido";
}
catch (std::out_of_range& e)
{
std::cout << "out of range: " << e.what() << '\n';
}
}
In case anybody else is still looking for the answer.. You can simply access the contents using the same method as for writing to an nlohmann::json object. For example to get values from
json in the question:
{
"active" : false,
"list1" : ["A", "B", "C"],
"objList" : [
{
"key1" : "value1",
"key2" : [ 0, 1 ]
}
]
}
just do:
nlohmann::json jsonData = nlohmann::json::parse(your_json);
std::cout << jsonData["active"] << std::endl; // returns boolean
std::cout << jsonData["list1"] << std::endl; // returns array
If the "objList" was just an object, you can retrieve its values just by:
std::cout << jsonData["objList"]["key1"] << std::endl; // returns string
std::cout << jsonData["objList"]["key2"] << std::endl; // returns array
But since "objList" is a list of key/value pairs, to access its values use:
for(auto &array : jsonData["objList"]) {
std::cout << array["key1"] << std::endl; // returns string
std::cout << array["key2"] << std::endl; // returns array
}
The loop runs only once considering "objList" is array of size 1.
Hope it helps someone
I really like to use this in C++:
for (auto& el : object["list1"].items())
{
std::cout << el.value() << '\n';
}
It will loop over the the array.
I'm trying to use boost json with property trees to decode a json message. I'm only interested about checking whether "mykey" is in the message and, if that is the case, get the corresponding values.
I'm a little lost in boost documentation, and I was trying to see what the actual code would be to parse a message such as the one below.
{
// some values
"mykey": [
{
"var1": "value1_str",
"var2" : "value2"
}
]
// some other values
}
I don't know about Boost ptree for JSON. I've tried it but it seemed... very clunky.
Here's a simple JSON parser based on the RFC, made in Spirit: https://github.com/sehe/spirit-v2-json/tree/q21356666
You could use it for your use case like test.cpp
#include <vector>
#include "json.hpp"
struct X {
static X from_json(JSON::Value const& v);
std::string var1;
double var2;
};
int main()
{
auto doc = as_object(JSON::parse(
"{\n"
" // some values\n"
" \"mykey\": [\n"
" {\n"
" \"var1\": \"value1_str\",\n"
" \"var2\" : 3.14\n"
" }\n"
" ]\n"
" // some other values\n"
"}\n"
));
if (doc.has_key("mykey"))
{
X data = X::from_json(doc["mykey"]);
std::cout << "X.var1: " << data.var1 << "\n";
std::cout << "X.var2: " << data.var2 << "\n";
}
std::cout << "doc: " << doc << "\n";
std::cout << "doc[\"mykey\"]: " << doc["mykey"] << "\n";
}
X X::from_json(JSON::Value const& v)
{
X result;
auto& o = as_object(as_array(v)[0]);
result.var1 = as_string(o["var1"]);
result.var2 = as_double(o["var2"]);
return result;
}
Output:
X.var1: value1_str
X.var2: 3.14
doc: {"mykey":[{"var1":"value1_str","var2":3.14}]}
doc["mykey"]: [{"var1":"value1_str","var2":3.14}]
There are other json libraries around. I suggest you select one to suit your needs.