| #include <iostream> | |
| #include <nlohmann/json.hpp> | |
| #include <stdexcept> | |
| #include <string> | |
| #include <unordered_set> | |
| #include <vector> | |
| using json = nlohmann::json; | |
| json parse_strict(const std::string& input) | |
| { | |
| // one key set per nesting depth, reused across sibling objects | |
| std::vector<std::unordered_set<std::string>> keys; | |
| auto reject_duplicate_keys = [&](int depth, json::parse_event_t event, json & parsed) | |
| { | |
| if (event == json::parse_event_t::object_start) | |
| { | |
| // keys of this object are reported at depth+1 (see the event table above) | |
| const auto child_depth = static_cast<std::size_t>(depth) + 1; | |
| if (keys.size() <= child_depth) | |
| { | |
| keys.resize(child_depth + 1); | |
| } | |
| keys[child_depth].clear(); | |
| return true; | |
| } | |
| if (event == json::parse_event_t::key) | |
| { | |
| auto& seen = keys[static_cast<std::size_t>(depth)]; | |
| const auto& key = parsed.get_ref<const std::string&>(); | |
| if (!seen.insert(key).second) | |
| { | |
| throw std::runtime_error("duplicate JSON object key: " + key); | |
| } | |
| return true; | |
| } | |
| return true; | |
| }; | |
| return json::parse(input, reject_duplicate_keys); | |
| } | |
| int main() | |
| { | |
| // parsing succeeds when all keys are unique | |
| json j = parse_strict(R"({"one": 1, "two": 2})"); | |
| std::cout << j << '\n'; | |
| // parsing throws when a key is repeated | |
| try | |
| { | |
| parse_strict(R"({"one": 1, "one": 2})"); | |
| } | |
| catch (const std::exception& e) | |
| { | |
| std::cout << e.what() << '\n'; | |
| } | |
| } |