The jsonpath extension implements Stefan Goessner's JSONPath. It provides functions for search and "search and replace" using JSONPath expressions.
jsonpath_expression | Represents the compiled form of a JSONPath string. (since 0.161.0) |
basic_json_location | Represents the location of a specific value in a JSON document. (since 0.172.0) |
basic_path_node | Represents a normalized path as a singly linked list where each node has a pointer to its (shared) parent node. (since 0.172.0) |
make_expression | Returns a compiled JSONPath expression for later evaluation. (since 0.161.0) |
json_query | Searches for all values that match a JSONPath expression |
json_replace | Search and replace using JSONPath expressions. |
flatten unflatten |
Flattens a json object or array. |
JSONPath is a loosely standardized syntax for querying JSON. There are many implementations and they differ in significant ways, see Christoph Burgmer's JSONPath comparison. For details about the jsoncons implementation, see the document JsonCons JSONPath.
In addition, the C++ implementation supports the following features:
-
A length property on arrays and strings that returns the number of elements in an array, or the number of codepoints in a string, e.g.
$[?(@.length == 2)]
. -
Custom functions, allowing the user to augment the list of built in JSONPath functions with user-provided functions (since 0.164.0).
The examples use the sample data file books.json
,
{
"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"
}
]
}
Using json_query
Using json_replace
Using make_expression
Custom functions
#include <fstream>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
using json = jsoncons::json;
namespace jsonpath = jsoncons::jsonpath;
int main()
{
std::ifstream is(/*path_to_books_file*/);
json data = json::parse(is);
auto result1 = jsonpath::json_query(data, "$.books[1,1,3].title");
std::cout << "(1)\n" << pretty_print(result1) << "\n\n";
auto result2 = jsonpath::json_query(data, "$.books[1,1,3].title",
jsonpath::result_options::path);
std::cout << "(2)\n" << pretty_print(result2) << "\n\n";
//auto result3 = jsonpath::json_query(data, "$.books[1,1,3].title",
// jsonpath::result_options::value |
// jsonpath::result_options::nodups); (until 0.164.0)
auto result3 = jsonpath::json_query(data, "$.books[1,1,3].title",
jsonpath::result_options::nodups); (since 0.164.0)
std::cout << "(3)\n" << pretty_print(result3) << "\n\n";
//auto result4 = jsonpath::json_query(data, "$.books[1,1,3].title",
// jsonpath::result_options::nodups); (until 0.164.0)
auto result4 = jsonpath::json_query(data, "$.books[1,1,3].title",
jsonpath::result_options::nodups |
jsonpath::result_options::path); (since 0.164.0)
std::cout << "(4)\n" << pretty_print(result4) << "\n\n";
}
Output:
(1)
[
"The Night Watch",
"The Night Watch",
"The Night Watch"
]
(2)
[
"$['books'][1]['title']",
"$['books'][1]['title']",
"$['books'][3]['title']"
]
(3)
[
"The Night Watch",
"The Night Watch"
]
(4)
[
"$['books'][1]['title']",
"$['books'][3]['title']"
]
#include <fstream>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
using json = jsoncons::json;
namespace jsonpath = jsoncons::jsonpath;
int main()
{
std::ifstream is(/*path_to_books_file*/);
json data = json::parse(is);
auto f = [](const std::string& /*location*/, json& price)
{
price = std::round(price.as<double>() - 1.0);
};
jsonpath::json_replace(data, "$.books[*].price", f);
std::cout << pretty_print(data) << "\n";
}
Output:
{
"books": [
{
"author": "Haruki Murakami",
"category": "fiction",
"price": 22.0,
"title": "A Wild Sheep Chase"
},
{
"author": "Sergei Lukyanenko",
"category": "fiction",
"price": 23.0,
"title": "The Night Watch"
},
{
"author": "Graham Greene",
"category": "fiction",
"price": 21.0,
"title": "The Comedians"
},
{
"author": "Phillips, David Atlee",
"category": "memoir",
"title": "The Night Watch"
}
]
}
A [jsoncons::jsonpath::Using make_expression](Using make_expression.md)
represents the compiled form of a JSONPath expression. It allows you to
evaluate a single compiled expression on multiple JSON documents.
A Using make_expression
is immutable and thread-safe.
#include <fstream>
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
using json = jsoncons::json;
namespace jsonpath = jsoncons::jsonpath;
int main()
{
auto expr = jsonpath::make_expression<json>("$.books[1,1,3].title");
std::ifstream is(/*path_to_books_file*/);
json data = json::parse(is);
json result1 = expr.evaluate(data);
std::cout << "(1)\n" << pretty_print(result1) << "\n\n";
json result2 = expr.evaluate(data, jsonpath::result_options::path);
std::cout << "(2)\n" << pretty_print(result2) << "\n\n";
//json result3 = expr.evaluate(data, jsonpath::result_options::value |
// jsonpath::result_options::nodups); (until 0.164.0)
json result3 = expr.evaluate(data, jsonpath::result_options::nodups); (since 0.164.0)
std::cout << "(3)\n" << pretty_print(result3) << "\n\n";
//json result4 = expr.evaluate(data, jsonpath::result_options::nodups); (until 0.164.0)
json result4 = expr.evaluate(data, jsonpath::result_options::nodups |
jsonpath::result_options::path); (since 0.164.0)
std::cout << "(4)\n" << pretty_print(result4) << "\n\n";
}
Output:
(1)
[
"The Night Watch",
"The Night Watch",
"The Night Watch"
]
(2)
[
"$['books'][1]['title']",
"$['books'][1]['title']",
"$['books'][3]['title']"
]
(3)
[
"The Night Watch",
"The Night Watch"
]
(4)
[
"$['books'][1]['title']",
"$['books'][3]['title']"
]
#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
using json = jsoncons::json;
namespace jsonpath = jsoncons::jsonpath;
template <class Json>
class my_custom_functions : public jsonpath::custom_functions<Json>
{
public:
my_custom_functions()
{
this->register_function("divide", // function name
2, // number of arguments
[](jsoncons::span<const jsonpath::parameter<Json>> params,
std::error_code& ec) -> Json
{
const Json& arg0 = params[0].value();
const Json& arg1 = params[1].value();
if (!(arg0.is_number() && arg1.is_number()))
{
ec = jsonpath::jsonpath_errc::invalid_type;
return Json::null();
}
return Json(arg0.as<double>() / arg1.as<double>());
}
);
}
};
int main()
{
json root = json::parse(R"([{"foo": 60, "bar": 10},{"foo": 60, "bar": 5}])");
json result = jsonpath::json_query(root,
"$[?(divide(@.foo, @.bar) == 6)]",
jsonpath::result_options(),
my_custom_functions<json>()); // (since 0.164.0)
std::cout << pretty_print(result) << "\n\n";
}
Output:
[{"bar": 10,"foo": 60}]