Closed PragmaTwice closed 1 year ago
jsoncons jsonpath supports a parent selector extension operator, ^
, borrowed from jsonpath-plus, that should do what you want.
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
using namespace jsoncons;
std::string input = R"(
[{"a":1, "b":2},{"c":1,"d":2}]
)";
int main()
{
json doc = json::parse(input);
auto callback = [](const std::string& path, json& value)
{
if (value.is_object())
{
auto it = value.find("a");
value.erase(it);
}
};
jsonpath::json_replace(doc, "$..a^", callback);
std::cout << doc << "\n";
}
Output:
[{"b":2},{"c":1,"d":2}]
I see. Thank you for your quick answer!
The parent selector is awesome, but we still face some problem to retrieve the key name.
For the example in https://github.com/danielaparker/jsoncons/issues/467#issuecomment-1783967621, it seems to be hard to retrieve the field name a
in the parent object, since the path can be varied (e.g. $.a
, $["a"]
, $[1]
, $..a[*]
).
May I ask if you have some idea about this? Thanks.
Oh, I see. In that case I think the strategy would be to collect the normalized paths for all nodes associated with the path, and then delete them one by one. We don't currently have a utility function for deleting the node corresponding to a normalized path, but could add one in the next release.
We don't currently have a utility function for deleting the node corresponding to a normalized path, but could add one in the next release.
Thank you. It will be highly appreciated.
Release 0.172.0 supports removing nodes that match on a JSONPath expression, e.g.
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
#include <fstream>
#include <cassert>
using jsoncons::json;
namespace jsonpath = jsoncons::jsonpath;
int main()
{
std::string input = R"(
{
"books":
[
{
"category": "fiction",
"title" : "A Wild Sheep Chase",
"author" : "Haruki Murakami",
"price" : 22.72
},
{
"category": "fiction",
"title" : "The Night Watch",
"author" : "Sergei Lukyanenko",
"price" : 23.58
},
{
"category": "fiction",
"title" : "The Comedians",
"author" : "Graham Greene",
"price" : 21.99
},
{
"category": "memoir",
"title" : "The Night Watch",
"author" : "Phillips, David Atlee"
}
]
}
)";
json doc = json::parse(input);
std::size_t n = jsonpath::remove(doc, "$.books[1,1,3,3,0,0]");
assert(n == 3); // Number of nodes removed
std::cout << jsoncons::pretty_print(doc) << "\n\n";
Output:
{
"books": [
{
"author": "Graham Greene",
"category": "fiction",
"price": 21.99,
"title": "The Comedians"
}
]
}
Before removal, duplicate nodes are removed, and locations to remove are sorted in descending path order, so e.g. node "$['books'][3]" is removed once, and node "$['books'][3]" is removed before nodes "$['books'][1]" and "$['books'][0]".
Thank you!
Describe the proposed feature Hi @danielaparker, firstly I want to thank you for such an amazing JSON library with rich features.
Our Kvrocks community is utilizing this library to implement JSON-related features like RedisJSON-compatibility. And my experience with jsoncons is really awesome.
For implementing some commands like
JSON.DEL
, we need to firstly use the jsonpath extension to locate an object in a JSON document, and then we need to delete the object if it is inside an array or object. (For example, given a JSON{"a":1, "b":2}
,JSON.DEL <key> $.a
results in{"b":2}
.)But it seems to be hard to delete since we cannot retrieve the parent object (or array) and then use some methods like
basic_json::erase
. (For example, given a JSON{"a":1, "b":2}
and jsonpath$.a
, we can only get the object1
, but instead we need to retrieve its parent object and then delete the keya
.)So I am wondering if there is any chance that such an ability can be provided in jsoncons, or if there is an cheap workaround which can solve this problem.
Related issue in Kvrocks: https://github.com/apache/kvrocks/issues/1813
What other libraries (C++ or other) have this feature? Maybe RedisJSON? Since it implements
JSON.DEL
.