From 9710ee3293fbf33f3f8fc96c1c6344f412b835b8 Mon Sep 17 00:00:00 2001 From: Daniel Parker Date: Thu, 16 Nov 2023 17:23:23 -0500 Subject: [PATCH] json_location select --- .../jsoncons_ext/jsonpath/json_location.hpp | 53 +++++- test/jsonpath/src/json_location_tests.cpp | 155 ++++++++++++++++-- 2 files changed, 194 insertions(+), 14 deletions(-) diff --git a/include/jsoncons_ext/jsonpath/json_location.hpp b/include/jsoncons_ext/jsonpath/json_location.hpp index 3797f76de9..193926dc9e 100644 --- a/include/jsoncons_ext/jsonpath/json_location.hpp +++ b/include/jsoncons_ext/jsonpath/json_location.hpp @@ -223,7 +223,7 @@ namespace jsonpath { }; template - std::size_t erase(Json& instance, const basic_json_location& location) + std::size_t remove(Json& instance, const basic_json_location& location) { std::size_t count = 0; @@ -283,6 +283,57 @@ namespace jsonpath { return count; } + template + Json* select(Json& instance, const basic_json_location& location) + { + Json* p_current = std::addressof(instance); + bool found = false; + + std::size_t last = location.size() == 0 ? 0 : location.size() - 1; + for (std::size_t i = 0; i < location.size(); ++i) + { + const auto& element = location[i]; + if (element.has_name()) + { + if (p_current->is_object()) + { + auto it = p_current->find(element.name()); + if (it != p_current->object_range().end()) + { + p_current = std::addressof(it->value()); + if (i == last) + { + found = true; + } + } + else + { + break; + } + } + else + { + break; + } + } + else // if (element.has_index()) + { + if (p_current->is_array() && element.index() < p_current->size()) + { + p_current = std::addressof(p_current->at(element.index())); + if (i == last) + { + found = true; + } + } + else + { + break; + } + } + } + return found ? p_current : nullptr; + } using json_location = basic_json_location; using wjson_location = basic_json_location; diff --git a/test/jsonpath/src/json_location_tests.cpp b/test/jsonpath/src/json_location_tests.cpp index c9498dfd1c..2916269085 100644 --- a/test/jsonpath/src/json_location_tests.cpp +++ b/test/jsonpath/src/json_location_tests.cpp @@ -23,8 +23,7 @@ TEST_CASE("json_location tests") } } - -TEST_CASE("json_location erase tests") +TEST_CASE("json_location remove tests") { std::string json_string = R"( @@ -62,7 +61,7 @@ TEST_CASE("json_location erase tests") CHECK(doc["store"]["book"].size() == 3); CHECK(doc["store"]["book"][1]["author"].as() == "Evelyn Waugh"); - std::size_t count = jsonpath::erase(doc, loc); + std::size_t count = jsonpath::remove(doc, loc); CHECK(count == 1); CHECK(doc["store"]["book"].size() == 2); @@ -78,7 +77,7 @@ TEST_CASE("json_location erase tests") CHECK(doc["store"]["book"].size() == 3); CHECK(doc["store"]["book"][2]["author"].as() == "Herman Melville"); - std::size_t count = jsonpath::erase(doc, loc); + std::size_t count = jsonpath::remove(doc, loc); CHECK(count == 1); CHECK(doc["store"]["book"].size() == 2); @@ -87,17 +86,18 @@ TEST_CASE("json_location erase tests") SECTION("store book 3") { + json orig = doc; + jsonpath::json_location loc; loc.append("store").append("book").append(3); CHECK(doc["store"]["book"].size() == 3); CHECK(doc["store"]["book"][2]["author"].as() == "Herman Melville"); - std::size_t count = jsonpath::erase(doc, loc); + std::size_t count = jsonpath::remove(doc, loc); CHECK(count == 0); - CHECK(doc["store"]["book"].size() == 3); - CHECK(doc["store"]["book"][2]["author"].as() == "Herman Melville"); + CHECK(doc == orig); } SECTION("store") @@ -105,7 +105,7 @@ TEST_CASE("json_location erase tests") jsonpath::json_location loc; loc.append("store"); - std::size_t count = jsonpath::erase(doc, loc); + std::size_t count = jsonpath::remove(doc, loc); CHECK(count == 1); CHECK(doc.size() == 0); } @@ -116,20 +116,22 @@ TEST_CASE("json_location erase tests") loc.append("store").append("book"); CHECK(doc["store"]["book"].size() == 3); - std::size_t count = jsonpath::erase(doc, loc); + std::size_t count = jsonpath::remove(doc, loc); CHECK(count == 1); CHECK(doc["store"]["book"].size() == 0); } SECTION("store lost&found") { + json orig = doc; + jsonpath::json_location loc; loc.append("store").append("lost&found"); CHECK(doc["store"].size() == 1); - std::size_t count = jsonpath::erase(doc, loc); + std::size_t count = jsonpath::remove(doc, loc); CHECK(count == 0); - CHECK(doc["store"].size() == 1); + CHECK(doc == orig); } SECTION("store book 2 price") @@ -137,17 +139,144 @@ TEST_CASE("json_location erase tests") jsonpath::json_location loc; loc.append("store").append("book").append(2).append("price"); - CHECK(doc["store"]["book"].size() == 3); CHECK(doc["store"]["book"][2]["author"].as() == "Herman Melville"); CHECK(doc["store"]["book"][2].contains("price")); - std::size_t count = jsonpath::erase(doc, loc); + std::size_t count = jsonpath::remove(doc, loc); CHECK(count == 1); CHECK(doc["store"]["book"].size() == 3); CHECK(doc["store"]["book"][2]["author"].as() == "Herman Melville"); CHECK_FALSE(doc["store"]["book"][2].contains("price")); } + + SECTION("store 0") + { + json orig = doc; + + jsonpath::json_location loc; + loc.append("store").append(0); + + CHECK(doc["store"]["book"].size() == 3); + CHECK(doc["store"]["book"][2].contains("price")); + + std::size_t count = jsonpath::remove(doc, loc); + + CHECK(count == 0); + CHECK(doc == orig); + } +} + +TEST_CASE("json_location select tests") +{ + + std::string json_string = R"( +{ "store": { + "book": [ + { "category": "reference", + "author": "Nigel Rees", + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + } + ] + } +} + )"; + + json doc = json::parse(json_string); + + SECTION("store book 1") + { + jsonpath::json_location loc; + loc.append("store").append("book").append(1); + + json* p_json = jsonpath::select(doc, loc); + + CHECK_FALSE(p_json == nullptr); + CHECK(*p_json == doc.at("store").at("book").at(1)); + } + + SECTION("store book 2") + { + jsonpath::json_location loc; + loc.append("store").append("book").append(2); + + json* p_json = jsonpath::select(doc, loc); + + CHECK_FALSE(p_json == nullptr); + CHECK(*p_json == doc.at("store").at("book").at(2)); + } + + SECTION("store book 3") + { + jsonpath::json_location loc; + loc.append("store").append("book").append(3); + + json* p_json = jsonpath::select(doc, loc); + + CHECK(p_json == nullptr); + } + + SECTION("store") + { + jsonpath::json_location loc; + loc.append("store"); + + json* p_json = jsonpath::select(doc, loc); + CHECK_FALSE(p_json == nullptr); + CHECK(*p_json == doc.at("store")); + } + + SECTION("store book") + { + jsonpath::json_location loc; + loc.append("store").append("book"); + + json* p_json = jsonpath::select(doc, loc); + CHECK_FALSE(p_json == nullptr); + CHECK(*p_json == doc.at("store").at("book")); + } + + SECTION("store lost&found") + { + jsonpath::json_location loc; + loc.append("store").append("lost&found"); + + json* p_json = jsonpath::select(doc, loc); + CHECK(p_json == nullptr); + } + + SECTION("store book 2 price") + { + jsonpath::json_location loc; + loc.append("store").append("book").append(2).append("price"); + + json* p_json = jsonpath::select(doc, loc); + + CHECK_FALSE(p_json == nullptr); + CHECK(*p_json == doc.at("store").at("book").at(2).at("price")); + } + + SECTION("store 0") + { + jsonpath::json_location loc; + loc.append("store").append(0); + + json* p_json = jsonpath::select(doc, loc); + + CHECK(p_json == nullptr); + } }