File: jsonpath_expression.hpp

package info (click to toggle)
jsoncons 1.3.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 17,584 kB
  • sloc: cpp: 136,382; sh: 33; makefile: 5
file content (260 lines) | stat: -rw-r--r-- 12,703 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
// Copyright 2013-2025 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// See https://github.com/danielaparker/jsoncons for latest version

#ifndef JSONCONS_EXT_JSONPATH_JSONPATH_EXPRESSION_HPP
#define JSONCONS_EXT_JSONPATH_JSONPATH_EXPRESSION_HPP

#include <algorithm> // std::reverse
#include <cstddef>
#include <memory>
#include <system_error>
#include <type_traits> // std::is_const
#include <utility> // std::move
#include <vector>

#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/allocator_set.hpp>
#include <jsoncons/utility/extension_traits.hpp>
#include <jsoncons/tag_type.hpp>

#include <jsoncons_ext/jsonpath/token_evaluator.hpp>
#include <jsoncons_ext/jsonpath/json_location.hpp>
#include <jsoncons_ext/jsonpath/jsonpath_parser.hpp>
#include <jsoncons_ext/jsonpath/path_node.hpp>

namespace jsoncons { 
namespace jsonpath {

    template <typename Json,typename TempAllocator =std::allocator<char>>
    class jsonpath_expression
    {
    public:
        using allocator_type = typename jsonpath_traits<Json>::allocator_type;
        using char_type = typename jsonpath_traits<Json>::char_type;
        using string_type = typename jsonpath_traits<Json>::string_type;
        using string_view_type = typename jsonpath_traits<Json>::string_view_type;
        
        using value_type = typename jsonpath_traits<Json>::value_type;
        using reference = typename jsonpath_traits<Json>::reference;
        using const_reference = typename jsonpath_traits<Json>::const_reference;
        
        using static_resources_type = jsoncons::jsonpath::detail::static_resources<value_type>;
        using path_expression_type = jsoncons::jsonpath::detail::path_expression<value_type,reference>;
        using const_path_expression_type = jsoncons::jsonpath::detail::path_expression<value_type,const_reference>;
        using path_node_type = basic_path_node<typename Json::char_type>;
    private:
        allocator_type alloc_;
        std::unique_ptr<static_resources_type> static_resources_;
        const_path_expression_type const_expr_;
        path_expression_type expr_;
    public:
        jsonpath_expression(const allocator_set<allocator_type,TempAllocator>& alloc_set,
            std::unique_ptr<static_resources_type>&& resources,
            const_path_expression_type&& const_expr, 
            path_expression_type&& expr)
            : alloc_(alloc_set.get_allocator()),
              static_resources_(std::move(resources)), 
              const_expr_(std::move(const_expr)),
              expr_(std::move(expr))
        {
        }

        jsonpath_expression(const jsonpath_expression&) = delete;
        jsonpath_expression(jsonpath_expression&&) = default;

        ~jsonpath_expression() = default;

        jsonpath_expression& operator=(const jsonpath_expression&) = delete;
        jsonpath_expression& operator=(jsonpath_expression&&) = default;

        template <typename BinaryCallback>
        typename std::enable_if<extension_traits::is_binary_function_object<BinaryCallback,const string_type&,const_reference>::value,void>::type
        evaluate(const_reference root, BinaryCallback callback, result_options options = result_options()) const
        {
            jsoncons::jsonpath::detail::eval_context<Json,const_reference> context{alloc_};
            auto f = [&callback](const path_node_type& path, const_reference val)
            {
                callback(to_basic_string(path), val);
            };
            const_expr_.evaluate(context, root, path_node_type{}, root, f, options | result_options::path);
        }

        value_type evaluate(const_reference root, result_options options = result_options()) const
        {
            if ((options & result_options::path) == result_options::path)
            {
                jsoncons::jsonpath::detail::eval_context<value_type, const_reference> context{ alloc_ };

                value_type result(json_array_arg, semantic_tag::none, alloc_);
                auto callback = [&result](const path_node_type& p, const_reference)
                {
                    result.emplace_back(to_basic_string(p));
                };
                const_expr_.evaluate(context, root, path_node_type{}, root, callback, options);
                return result;
            }
            jsoncons::jsonpath::detail::eval_context<value_type, const_reference> context{ alloc_ };
            return const_expr_.evaluate(context, root, path_node_type{}, root, options);
        }

        value_type select(const_reference root, result_options options = result_options()) const
        {
            if ((options & result_options::path) == result_options::path)
            {
                jsoncons::jsonpath::detail::eval_context<value_type, const_reference> context{ alloc_ };

                value_type result(json_array_arg, semantic_tag::none, alloc_);
                auto callback = [&result](const path_node_type& p, const_reference)
                {
                    result.emplace_back(to_basic_string(p));
                };
                const_expr_.evaluate(context, root, path_node_type{}, root, callback, options);
                return result;
            }
            jsoncons::jsonpath::detail::eval_context<value_type, const_reference> context{ alloc_ };
            return const_expr_.evaluate(context, root, path_node_type{}, root, options);
        }

        template <typename BinaryCallback>
        typename std::enable_if<extension_traits::is_binary_function_object<BinaryCallback,const path_node_type&,const_reference>::value,void>::type
        select(const_reference root, BinaryCallback callback, result_options options = result_options()) const
        {
            jsoncons::jsonpath::detail::eval_context<value_type,const_reference> context{alloc_};
            const_expr_.evaluate(context, root, path_node_type{}, root, callback, options | result_options::path);
        }

        template <typename BinaryCallback>
        typename std::enable_if<extension_traits::is_binary_function_object<BinaryCallback,const path_node_type&,value_type&>::value,void>::type
        update(reference root, BinaryCallback callback) const
        {
            jsoncons::jsonpath::detail::eval_context<value_type,reference> context{alloc_};

            result_options options = result_options::nodups | result_options::path | result_options::sort_descending;
            expr_.evaluate(context, root, path_node_type{}, root, callback, options);
        }

        std::vector<basic_json_location<char_type>> select_paths(const_reference root, 
            result_options options = result_options::nodups | result_options::sort) const
        {
            std::vector<basic_json_location<char_type>> result;

            options = options | result_options::path;

            auto callback = [&result](const path_node_type& path, const_reference)
            {
                result.emplace_back(path);
            };

            jsoncons::jsonpath::detail::eval_context<value_type,const_reference> context{alloc_};
            const_expr_.evaluate(context, root, path_node_type{}, root, callback, options);

            return result;
        }
    };

    template <typename Json>
    jsonpath_expression<Json> make_expression(const typename Json::string_view_type& path,
        const jsoncons::jsonpath::custom_functions<typename jsonpath_traits<Json>::value_type>& funcs = jsoncons::jsonpath::custom_functions<typename jsonpath_traits<Json>::value_type>())
    {
        using value_type = typename jsonpath_traits<Json>::value_type;
        using reference = typename jsonpath_traits<Json>::reference;
        using const_reference = typename jsonpath_traits<Json>::const_reference;
        using static_resources_type = jsoncons::jsonpath::detail::static_resources<value_type>;
        using evaluator_type = typename jsoncons::jsonpath::detail::jsonpath_evaluator<value_type, reference>;
        using const_evaluator_type = typename jsoncons::jsonpath::detail::jsonpath_evaluator<value_type, const_reference>;

        auto resources = jsoncons::make_unique<static_resources_type>(funcs);
        const_evaluator_type const_evaluator;
        auto const_expr = const_evaluator.compile(*resources, path);

        evaluator_type evaluator;
        auto expr = evaluator.compile(*resources, path);

        return jsonpath_expression<Json>(jsoncons::combine_allocators(), 
            std::move(resources), std::move(const_expr), std::move(expr));
    }

    template <typename Json>
    jsonpath_expression<Json> make_expression(const typename Json::string_view_type& expr, std::error_code& ec)
    {
        return make_expression<Json>(jsoncons::combine_allocators(), expr, custom_functions<Json>(), ec);
    }

    template <typename Json,typename TempAllocator >
    jsonpath_expression<Json> make_expression(const allocator_set<typename Json::allocator_type,TempAllocator>& alloc_set, 
        const typename Json::string_view_type& expr, std::error_code& ec)
    {
        return make_expression<Json>(alloc_set, expr, custom_functions<Json>(), ec);
    }

    template <typename Json,typename TempAllocator >
    jsonpath_expression<Json> make_expression(const allocator_set<typename Json::allocator_type,TempAllocator>& alloc_set, 
        const typename Json::string_view_type& path, 
        const custom_functions<Json>& funcs = custom_functions<Json>())
    {
        using value_type = typename jsonpath_traits<Json>::value_type;
        using reference = typename jsonpath_traits<Json>::reference;
        using const_reference = typename jsonpath_traits<Json>::const_reference;
        using static_resources_type = jsoncons::jsonpath::detail::static_resources<value_type>;
        using evaluator_type = typename jsoncons::jsonpath::detail::jsonpath_evaluator<value_type, reference>;
        using const_evaluator_type = typename jsoncons::jsonpath::detail::jsonpath_evaluator<value_type, const_reference>;

        auto resources = jsoncons::make_unique<static_resources_type>(funcs,
            alloc_set.get_allocator());
        const_evaluator_type const_evaluator{alloc_set.get_allocator()};
        auto const_expr = const_evaluator.compile(*resources, path);

        evaluator_type evaluator{alloc_set.get_allocator()};
        auto expr = evaluator.compile(*resources, path);

        return jsonpath_expression<Json>(alloc_set, 
            std::move(resources), std::move(const_expr), std::move(expr));
    }

    template <typename Json,typename TempAllocator >
    jsonpath_expression<Json> make_expression(const allocator_set<typename Json::allocator_type,TempAllocator>& alloc_set,
        const typename Json::string_view_type& path,
        const jsoncons::jsonpath::custom_functions<typename jsonpath_traits<Json>::value_type>& funcs, std::error_code& ec)
    {
        using value_type = typename jsonpath_traits<Json>::value_type;
        using reference = typename jsonpath_traits<Json>::reference;
        using const_reference = typename jsonpath_traits<Json>::const_reference;
        using static_resources_type = jsoncons::jsonpath::detail::static_resources<value_type>;
        using evaluator_type = typename jsoncons::jsonpath::detail::jsonpath_evaluator<value_type, reference>;
        using const_evaluator_type = typename jsoncons::jsonpath::detail::jsonpath_evaluator<value_type, const_reference>;

        auto resources = jsoncons::make_unique<static_resources_type>(funcs);
        const_evaluator_type const_evaluator{alloc_set.get_allocator()};
        auto const_expr = const_evaluator.compile(*resources, path, ec);

        evaluator_type evaluator{alloc_set.get_allocator()};
        auto expr = evaluator.compile(*resources, path, ec);

        return jsonpath_expression<Json>(alloc_set, 
            std::move(resources), std::move(const_expr), std::move(expr));
    }

    template <typename Json>
    std::size_t remove(Json& root, const jsoncons::basic_string_view<typename Json::char_type>& path_string)
    {
        std::size_t count = 0;

        auto expr = jsonpath::make_expression<Json>(path_string);
        std::vector<jsonpath::json_location> locations = expr.select_paths(root,
            jsonpath::result_options::nodups | jsonpath::result_options::sort_descending);

        for (const auto& location : locations)
        {
            std::size_t n = jsonpath::remove(root, location);
            count += n;
        }
        return count;
    }

} // namespace jsonpath
} // namespace jsoncons

#endif // JSONCONS_EXT_JSONPATH_JSONPATH_EXPRESSION_HPP