Disclaimer: The sample below is not a full blown JSON parser. Consider using a library that supports your needs. You can see a more evolved JSON parser here https://github.com/sehe/spirit-v2-json
A quick-and-dirty Spirit grammar (assuming you don't need too much conformance) would be:
text_ = '"' >> raw [*('\\' >> char_ | ~char_('"'))] >> '"'; // ¹
value_ = null | bool | text_ | double_ | object_ | array_; // ²
member_ = text_ >> ':' >> value_;
object_ = '{' >> -(member_ % ',') >> '}';
array_ = '[' >> -(value_ % ',') >> ']';
// ¹ as a bonus I added utf8 escape decoding in the full sample
// ² as another bonus I threw in the missing `null` and `bool` types
Which translates into C++ types without further effort using an AST like:
using text = std::string;
using value = boost::make_recursive_variant<
null,
bool,
text, // "string" (roughly!)
double, // number
std::map, // object
std::vector // array
>::type;
using member = std::pair;
using object = std::map;
using array = std::vector;
If you have two qd_json::value objects, you can just compare them:
qd_json::value local_tree, remote_tree;
if (local_tree == remote_tree)
{
std::cout << "the tree is unchanged\n";
}
Here's a demo program:
Updated Demo
The demonstration was updated to show you how to get to the "user-friendly" data structure you suggested in the edit of the question:
int main() {
auto json = qd_json::parse(sample);
// extract into user friendly datastructure from the question:
auto extracted = Data::extract_from(json);
for (auto& e : extracted.folders) std::cout << "folder:\t" << e.id << "\t" << e.path << "\n";
for (auto& e : extracted.files) std::cout << "file:\t" << e.id << "\t" << e.path << "\t" << e.name << "\n";
}
Live On Coliru
#include
#include
#include
#include
Output:
folder: 109 /1/105/110/
folder: 110 /1/105/
file: 26 /1/105/ picture.png
file: 25 /1/105/110/ another_picture.jpg