Reading variant based on tag in parent #2091
-
|
Greetings, i'm trying to use glaze to interface to some rest calls. One returns a list of nodes, where each node has a type string and an attributes struct that is different between types. I've seen glaze supports using tags to distinguish variants contents based on a tag but the tag field must be inside the structs contained in the variant, whereas i have the tags as a field outside of that variant. I tried understanding how to use glz::object and glz::custom to use the type field to choose which variant type must be read, but i'm honestly a bit lost in this mess. The glz::custom examples in the documentation all have simple fields rather than structs, so there's no example to see how "stuff" is passed down to the variant elements. Relevant documentation pages: https://github.com/stephenberry/glaze/blob/main/docs/variant-handling.md https://github.com/stephenberry/glaze/blob/main/docs/wrappers.md#custom Godbolt with a simple example: https://gcc.godbolt.org/z/soacch614 Right now it compiles and works because glaze is automatically detecting which variant type to use based on its members, but since I can't rely on that in my real application i really need a way to filter it by "node_type". Worst case I'll end up navigating the json by hand with glz::generic and only using the auto parse features on the specific attributes. My issue is almost the opposite of this #1246. In that case they had the tag on a child, in my case i have the tag on a parent. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
|
Here's an example using https://gcc.godbolt.org/z/s4G5q56fd #include <iostream>
#include <variant>
#include "glaze/glaze.hpp"
namespace attributes {
struct none {};
struct a {
std::string aa;
float ab;
};
struct b {
std::string ba;
std::string bb;
};
using variant = std::variant<none, a, b>;
} // namespace attributes
struct node {
std::string id;
std::string node_type;
attributes::variant attributes;
};
// Robust parsing that doesn't depend on JSON field order
template <>
struct glz::meta<node> {
using T = node;
// Read the entire node from generic JSON
static constexpr auto custom_read = [](T& self, const glz::generic& input) {
if (!input.is_object()) return;
const auto& obj = input.get_object();
self.id = obj.at("id").get_string();
self.node_type = obj.at("node_type").get_string();
auto& attributes = obj.at("attributes");
if (self.node_type == "a") {
attributes::a attr;
if (!glz::read_json(attr, attributes)) {
self.attributes = std::move(attr);
}
} else if (self.node_type == "b") {
attributes::b attr;
if (!glz::read_json(attr, attributes)) {
self.attributes = std::move(attr);
}
} else {
self.attributes = attributes::none{};
}
};
static constexpr auto value = glz::custom<custom_read, [](auto& self) -> T& { return self; }>;
};
std::string json_string{R"(
[
{
"id": "qwe",
"node_type": "a",
"attributes":
{
"aa": "hello",
"ab": 5
}
},
{
"id": "rty",
"node_type": "b",
"attributes":
{
"ba": "hello",
"bb": "world"
}
},
{
"id": "uiop",
"node_type": "random_stuff",
"attributes":
{
"whatever": "should get ignored"
}
}
]
)"};
int main() {
std::vector<node> nodes;
if (const auto error = glz::read<glz::opts{.error_on_unknown_keys = false}>(
nodes, json_string)) {
std::cout << glz::format_error(error, json_string) << '\n';
return 1;
}
std::cout << "Node 0 variant index: " << nodes[0].attributes.index()
<< '\n'; // expect 1 (a)
std::cout << "Node 1 variant index: " << nodes[1].attributes.index()
<< '\n'; // expect 2 (b)
std::cout << "Node 2 variant index: " << nodes[2].attributes.index()
<< '\n'; // expect 0 (none)
// Verify actual values
if (auto* attr_a = std::get_if<attributes::a>(&nodes[0].attributes)) {
std::cout << "Node 0: aa=" << attr_a->aa << ", ab=" << attr_a->ab
<< '\n';
}
if (auto* attr_b = std::get_if<attributes::b>(&nodes[1].attributes)) {
std::cout << "Node 1: ba=" << attr_b->ba << ", bb=" << attr_b->bb
<< '\n';
}
return 0;
} |
Beta Was this translation helpful? Give feedback.
Here's an example using
glz::genericwithin a similar approach toglz::customthat you were aiming for:https://gcc.godbolt.org/z/s4G5q56fd