aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons_ext/jsonpath/jsonpath_selector.hpp')
-rw-r--r--include/jsoncons_ext/jsonpath/jsonpath_selector.hpp1322
1 files changed, 1322 insertions, 0 deletions
diff --git a/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp b/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp
new file mode 100644
index 0000000..e06d37c
--- /dev/null
+++ b/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp
@@ -0,0 +1,1322 @@
+// Copyright 2021 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_JSONPATH_JSONPATH_SELECTOR_HPP
+#define JSONCONS_JSONPATH_JSONPATH_SELECTOR_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <type_traits> // std::is_const
+#include <limits> // std::numeric_limits
+#include <utility> // std::move
+#include <regex>
+#include <jsoncons/json.hpp>
+#include <jsoncons_ext/jsonpath/jsonpath_error.hpp>
+#include <jsoncons_ext/jsonpath/expression.hpp>
+
+namespace jsoncons {
+namespace jsonpath {
+namespace detail {
+
+ struct slice
+ {
+ jsoncons::optional<int64_t> start_;
+ jsoncons::optional<int64_t> stop_;
+ int64_t step_;
+
+ slice()
+ : start_(), stop_(), step_(1)
+ {
+ }
+
+ slice(const jsoncons::optional<int64_t>& start, const jsoncons::optional<int64_t>& end, int64_t step)
+ : start_(start), stop_(end), step_(step)
+ {
+ }
+
+ slice(const slice& other)
+ : start_(other.start_), stop_(other.stop_), step_(other.step_)
+ {
+ }
+
+ slice& operator=(const slice& rhs)
+ {
+ if (this != &rhs)
+ {
+ if (rhs.start_)
+ {
+ start_ = rhs.start_;
+ }
+ else
+ {
+ start_.reset();
+ }
+ if (rhs.stop_)
+ {
+ stop_ = rhs.stop_;
+ }
+ else
+ {
+ stop_.reset();
+ }
+ step_ = rhs.step_;
+ }
+ return *this;
+ }
+
+ int64_t get_start(std::size_t size) const
+ {
+ if (start_)
+ {
+ auto len = *start_ >= 0 ? *start_ : (static_cast<int64_t>(size) + *start_);
+ return len <= static_cast<int64_t>(size) ? len : static_cast<int64_t>(size);
+ }
+ else
+ {
+ if (step_ >= 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return static_cast<int64_t>(size);
+ }
+ }
+ }
+
+ int64_t get_stop(std::size_t size) const
+ {
+ if (stop_)
+ {
+ auto len = *stop_ >= 0 ? *stop_ : (static_cast<int64_t>(size) + *stop_);
+ return len <= static_cast<int64_t>(size) ? len : static_cast<int64_t>(size);
+ }
+ else
+ {
+ return step_ >= 0 ? static_cast<int64_t>(size) : -1;
+ }
+ }
+
+ int64_t step() const
+ {
+ return step_; // Allow negative
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class json_array_receiver : public node_receiver<Json,JsonReference>
+ {
+ public:
+ using reference = JsonReference;
+ using char_type = typename Json::char_type;
+ using json_location_node_type = json_location_node<char_type>;
+
+ Json* val;
+
+ json_array_receiver(Json* ptr)
+ : val(ptr)
+ {
+ }
+
+ void add(const json_location_node_type&, reference value) override
+ {
+ val->emplace_back(value);
+ }
+ };
+
+ template <class Json,class JsonReference>
+ struct path_generator
+ {
+ using char_type = typename Json::char_type;
+ using json_location_node_type = json_location_node<char_type>;
+ using string_type = std::basic_string<char_type>;
+
+ static const json_location_node_type& generate(dynamic_resources<Json,JsonReference>& resources,
+ const json_location_node_type& last,
+ std::size_t index,
+ result_options options)
+ {
+ const result_options require_path = result_options::path | result_options::nodups | result_options::sort;
+ if ((options & require_path) != result_options())
+ {
+ return *resources.create_path_node(&last, index);
+ }
+ else
+ {
+ return last;
+ }
+ }
+
+ static const json_location_node_type& generate(dynamic_resources<Json,JsonReference>& resources,
+ const json_location_node_type& last,
+ const string_type& identifier,
+ result_options options)
+ {
+ const result_options require_path = result_options::path | result_options::nodups | result_options::sort;
+ if ((options & require_path) != result_options())
+ {
+ return *resources.create_path_node(&last, identifier);
+ }
+ else
+ {
+ return last;
+ }
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class base_selector : public jsonpath_selector<Json,JsonReference>
+ {
+ using supertype = jsonpath_selector<Json,JsonReference>;
+
+ supertype* tail_;
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using json_location_type = typename supertype::json_location_type;
+ using node_receiver_type = typename supertype::node_receiver_type;
+ using selector_type = typename supertype::selector_type;
+
+ base_selector()
+ : supertype(true, 11), tail_(nullptr)
+ {
+ }
+
+ base_selector(bool is_path, std::size_t precedence_level)
+ : supertype(is_path, precedence_level), tail_(nullptr)
+ {
+ }
+
+ void append_selector(selector_type* expr) override
+ {
+ if (!tail_)
+ {
+ tail_ = expr;
+ }
+ else
+ {
+ tail_->append_selector(expr);
+ }
+ }
+
+ void tail_select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const
+ {
+ if (!tail_)
+ {
+ receiver.add(last, current);
+ }
+ else
+ {
+ tail_->select(resources, root, last, current, receiver, options);
+ }
+ }
+
+ reference evaluate_tail(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code& ec) const
+ {
+ if (!tail_)
+ {
+ return current;
+ }
+ else
+ {
+ return tail_->evaluate(resources, root, last, current, options, ec);
+ }
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ if (tail_)
+ {
+ s.append(tail_->to_string(level));
+ }
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class identifier_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using char_type = typename Json::char_type;
+ using string_type = std::basic_string<char_type>;
+ using string_view_type = basic_string_view<char_type>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+ private:
+ string_type identifier_;
+ public:
+
+ identifier_selector(const string_view_type& identifier)
+ : base_selector<Json,JsonReference>(), identifier_(identifier)
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ //std::string buf;
+ //buf.append("identifier selector: ");
+ //unicode_traits::convert(identifier_.data(),identifier_.size(),buf);
+
+ static const char_type length_name[] = {'l', 'e', 'n', 'g', 't', 'h', 0};
+
+ if (current.is_object())
+ {
+ auto it = current.find(identifier_);
+ if (it != current.object_range().end())
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, identifier_, options),
+ it->value(), receiver, options);
+ }
+ }
+ else if (current.is_array())
+ {
+ int64_t n{0};
+ auto r = jsoncons::detail::to_integer_decimal(identifier_.data(), identifier_.size(), n);
+ if (r)
+ {
+ std::size_t index = (n >= 0) ? static_cast<std::size_t>(n) : static_cast<std::size_t>(static_cast<int64_t>(current.size()) + n);
+ if (index < current.size())
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, index, options),
+ current[index], receiver, options);
+ }
+ }
+ else if (identifier_ == length_name && current.size() > 0)
+ {
+ pointer ptr = resources.create_json(current.size());
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, identifier_, options),
+ *ptr,
+ receiver, options);
+ }
+ }
+ else if (current.is_string() && identifier_ == length_name)
+ {
+ string_view_type sv = current.as_string_view();
+ std::size_t count = unicode_traits::count_codepoints(sv.data(), sv.size());
+ pointer ptr = resources.create_json(count);
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, identifier_, options),
+ *ptr, receiver, options);
+ }
+ //std::cout << "end identifier_selector\n";
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code& ec) const override
+ {
+ static const char_type length_name[] = {'l', 'e', 'n', 'g', 't', 'h', 0};
+
+ if (current.is_object())
+ {
+ auto it = current.find(identifier_);
+ if (it != current.object_range().end())
+ {
+ return this->evaluate_tail(resources, root,
+ path_generator_type::generate(resources, last, identifier_, options),
+ it->value(), options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+ else if (current.is_array())
+ {
+ int64_t n{0};
+ auto r = jsoncons::detail::to_integer_decimal(identifier_.data(), identifier_.size(), n);
+ if (r)
+ {
+ std::size_t index = (n >= 0) ? static_cast<std::size_t>(n) : static_cast<std::size_t>(static_cast<int64_t>(current.size()) + n);
+ if (index < current.size())
+ {
+ return this->evaluate_tail(resources, root,
+ path_generator_type::generate(resources, last, index, options),
+ current[index], options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+ else if (identifier_ == length_name && current.size() > 0)
+ {
+ pointer ptr = resources.create_json(current.size());
+ return this->evaluate_tail(resources, root,
+ path_generator_type::generate(resources, last, identifier_, options),
+ *ptr,
+ options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+ else if (current.is_string() && identifier_ == length_name)
+ {
+ string_view_type sv = current.as_string_view();
+ std::size_t count = unicode_traits::count_codepoints(sv.data(), sv.size());
+ pointer ptr = resources.create_json(count);
+ return this->evaluate_tail(resources, root,
+ path_generator_type::generate(resources, last, identifier_, options),
+ *ptr, options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("identifier selector ");
+ unicode_traits::convert(identifier_.data(),identifier_.size(),s);
+ s.append(base_selector<Json,JsonReference>::to_string(level+1));
+ //s.append("\n");
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class root_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+ using path_generator_type = path_generator<Json,JsonReference>;
+
+ std::size_t id_;
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ root_selector(std::size_t id)
+ : base_selector<Json,JsonReference>(), id_(id)
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ this->tail_select(resources, root, last, root, receiver, options);
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference,
+ result_options options,
+ std::error_code& ec) const override
+ {
+ if (resources.is_cached(id_))
+ {
+ return resources.retrieve_from_cache(id_);
+ }
+ else
+ {
+ auto& ref = this->evaluate_tail(resources, root, last, root, options, ec);
+ if (!ec)
+ {
+ resources.add_to_cache(id_, ref);
+ }
+
+ return ref;
+ }
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("root_selector ");
+ s.append(base_selector<Json,JsonReference>::to_string(level+1));
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class current_node_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ current_node_selector()
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ this->tail_select(resources,
+ root, last, current, receiver, options);
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code& ec) const override
+ {
+ //std::cout << "current_node_selector: " << current << "\n";
+ return this->evaluate_tail(resources,
+ root, last, current, options, ec);
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("current_node_selector");
+ s.append(base_selector<Json,JsonReference>::to_string(level+1));
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class parent_node_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ int ancestor_depth_;
+
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using json_location_type = typename supertype::json_location_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ parent_node_selector(int ancestor_depth)
+ {
+ ancestor_depth_ = ancestor_depth;
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ const json_location_node_type* ancestor = std::addressof(last);
+ int index = 0;
+ while (ancestor != nullptr && index < ancestor_depth_)
+ {
+ ancestor = ancestor->parent();
+ ++index;
+ }
+
+ if (ancestor != nullptr)
+ {
+ json_location_type path(*ancestor);
+ pointer ptr = jsoncons::jsonpath::select(root,path);
+ if (ptr != nullptr)
+ {
+ this->tail_select(resources, root, path.last(), *ptr, receiver, options);
+ }
+ }
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference,
+ result_options options,
+ std::error_code& ec) const override
+ {
+ const json_location_node_type* ancestor = std::addressof(last);
+ int index = 0;
+ while (ancestor != nullptr && index < ancestor_depth_)
+ {
+ ancestor = ancestor->parent();
+ ++index;
+ }
+
+ if (ancestor != nullptr)
+ {
+ json_location_type path(*ancestor);
+ pointer ptr = jsoncons::jsonpath::select(root,path);
+ if (ptr != nullptr)
+ {
+ return this->evaluate_tail(resources, root, path.last(), *ptr, options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("parent_node_selector");
+ s.append(base_selector<Json,JsonReference>::to_string(level+1));
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class index_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ int64_t index_;
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ index_selector(int64_t index)
+ : base_selector<Json,JsonReference>(), index_(index)
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ if (current.is_array())
+ {
+ int64_t slen = static_cast<int64_t>(current.size());
+ if (index_ >= 0 && index_ < slen)
+ {
+ std::size_t i = static_cast<std::size_t>(index_);
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, i, options),
+ current.at(i), receiver, options);
+ }
+ else
+ {
+ int64_t index = slen + index_;
+ if (index >= 0 && index < slen)
+ {
+ std::size_t i = static_cast<std::size_t>(index);
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, i, options),
+ current.at(i), receiver, options);
+ }
+ }
+ }
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code& ec) const override
+ {
+ if (current.is_array())
+ {
+ int64_t slen = static_cast<int64_t>(current.size());
+ if (index_ >= 0 && index_ < slen)
+ {
+ std::size_t i = static_cast<std::size_t>(index_);
+ return this->evaluate_tail(resources, root,
+ path_generator_type::generate(resources, last, i, options),
+ current.at(i), options, ec);
+ }
+ else
+ {
+ int64_t index = slen + index_;
+ if (index >= 0 && index < slen)
+ {
+ std::size_t i = static_cast<std::size_t>(index);
+ return this->evaluate_tail(resources, root,
+ path_generator_type::generate(resources, last, i, options),
+ current.at(i), options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class wildcard_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ wildcard_selector()
+ : base_selector<Json,JsonReference>()
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ if (current.is_array())
+ {
+ for (std::size_t i = 0; i < current.size(); ++i)
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, i, options), current[i],
+ receiver, options);
+ }
+ }
+ else if (current.is_object())
+ {
+ for (auto& member : current.object_range())
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, member.key(), options),
+ member.value(), receiver, options);
+ }
+ }
+ //std::cout << "end wildcard_selector\n";
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code&) const override
+ {
+ auto jptr = resources.create_json(json_array_arg);
+ json_array_receiver<Json,JsonReference> receiver(jptr);
+ select(resources, root, last, current, receiver, options);
+ return *jptr;
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("wildcard selector");
+ s.append(base_selector<Json,JsonReference>::to_string(level));
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class recursive_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ recursive_selector()
+ : base_selector<Json,JsonReference>()
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ if (current.is_array())
+ {
+ this->tail_select(resources, root, last, current, receiver, options);
+ for (std::size_t i = 0; i < current.size(); ++i)
+ {
+ select(resources, root,
+ path_generator_type::generate(resources, last, i, options), current[i], receiver, options);
+ }
+ }
+ else if (current.is_object())
+ {
+ this->tail_select(resources, root, last, current, receiver, options);
+ for (auto& item : current.object_range())
+ {
+ select(resources, root,
+ path_generator_type::generate(resources, last, item.key(), options), item.value(), receiver, options);
+ }
+ }
+ //std::cout << "end wildcard_selector\n";
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code&) const override
+ {
+ auto jptr = resources.create_json(json_array_arg);
+ json_array_receiver<Json,JsonReference> receiver(jptr);
+ select(resources, root, last, current, receiver, options);
+ return *jptr;
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("wildcard selector");
+ s.append(base_selector<Json,JsonReference>::to_string(level));
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class union_selector final : public jsonpath_selector<Json,JsonReference>
+ {
+ using supertype = jsonpath_selector<Json,JsonReference>;
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using json_location_type = typename supertype::json_location_type;
+ using path_expression_type = path_expression<Json, JsonReference>;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+ using selector_type = typename supertype::selector_type;
+ private:
+ std::vector<selector_type*> selectors_;
+ selector_type* tail_;
+ public:
+ union_selector(std::vector<selector_type*>&& selectors)
+ : supertype(true, 11), selectors_(std::move(selectors)), tail_(nullptr)
+ {
+ }
+
+ void append_selector(selector_type* tail) override
+ {
+ if (tail_ == nullptr)
+ {
+ tail_ = tail;
+ for (auto& selector : selectors_)
+ {
+ selector->append_selector(tail);
+ }
+ }
+ else
+ {
+ tail_->append_selector(tail);
+ }
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ for (auto& selector : selectors_)
+ {
+ selector->select(resources, root, last, current, receiver, options);
+ }
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code&) const override
+ {
+ auto jptr = resources.create_json(json_array_arg);
+ json_array_receiver<Json,JsonReference> receiver(jptr);
+ select(resources,root,last,current,receiver,options);
+ return *jptr;
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("union selector ");
+ for (auto& selector : selectors_)
+ {
+ s.append(selector->to_string(level+1));
+ //s.push_back('\n');
+ }
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class filter_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ expression<Json,JsonReference> expr_;
+
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ filter_selector(expression<Json,JsonReference>&& expr)
+ : base_selector<Json,JsonReference>(), expr_(std::move(expr))
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ if (current.is_array())
+ {
+ for (std::size_t i = 0; i < current.size(); ++i)
+ {
+ std::error_code ec;
+ value_type r = expr_.evaluate(resources, root, current[i], options, ec);
+ bool t = ec ? false : detail::is_true(r);
+ if (t)
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, i, options),
+ current[i], receiver, options);
+ }
+ }
+ }
+ else if (current.is_object())
+ {
+ for (auto& member : current.object_range())
+ {
+ std::error_code ec;
+ value_type r = expr_.evaluate(resources, root, member.value(), options, ec);
+ bool t = ec ? false : detail::is_true(r);
+ if (t)
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, member.key(), options),
+ member.value(), receiver, options);
+ }
+ }
+ }
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code&) const override
+ {
+ auto jptr = resources.create_json(json_array_arg);
+ json_array_receiver<Json,JsonReference> receiver(jptr);
+ select(resources, root, last, current, receiver, options);
+ return *jptr;
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("filter selector ");
+ s.append(expr_.to_string(level+1));
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class index_expression_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ expression<Json,JsonReference> expr_;
+
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ index_expression_selector(expression<Json,JsonReference>&& expr)
+ : base_selector<Json,JsonReference>(), expr_(std::move(expr))
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ std::error_code ec;
+ value_type j = expr_.evaluate(resources, root, current, options, ec);
+
+ if (!ec)
+ {
+ if (j.template is<std::size_t>() && current.is_array())
+ {
+ std::size_t start = j.template as<std::size_t>();
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, start, options),
+ current.at(start), receiver, options);
+ }
+ else if (j.is_string() && current.is_object())
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, j.as_string(), options),
+ current.at(j.as_string_view()), receiver, options);
+ }
+ }
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code& ec) const override
+ {
+ //std::cout << "index_expression_selector current: " << current << "\n";
+
+ value_type j = expr_.evaluate(resources, root, current, options, ec);
+
+ if (!ec)
+ {
+ if (j.template is<std::size_t>() && current.is_array())
+ {
+ std::size_t start = j.template as<std::size_t>();
+ return this->evaluate_tail(resources, root, last, current.at(start), options, ec);
+ }
+ else if (j.is_string() && current.is_object())
+ {
+ return this->evaluate_tail(resources, root, last, current.at(j.as_string_view()), options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("bracket expression selector ");
+ s.append(expr_.to_string(level+1));
+ s.append(base_selector<Json,JsonReference>::to_string(level+1));
+
+ return s;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class slice_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+ using path_generator_type = path_generator<Json, JsonReference>;
+
+ slice slice_;
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ slice_selector(const slice& slic)
+ : base_selector<Json,JsonReference>(), slice_(slic)
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ if (current.is_array())
+ {
+ auto start = slice_.get_start(current.size());
+ auto end = slice_.get_stop(current.size());
+ auto step = slice_.step();
+
+ if (step > 0)
+ {
+ if (start < 0)
+ {
+ start = 0;
+ }
+ if (end > static_cast<int64_t>(current.size()))
+ {
+ end = current.size();
+ }
+ for (int64_t i = start; i < end; i += step)
+ {
+ std::size_t j = static_cast<std::size_t>(i);
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last, j, options),
+ current[j], receiver, options);
+ }
+ }
+ else if (step < 0)
+ {
+ if (start >= static_cast<int64_t>(current.size()))
+ {
+ start = static_cast<int64_t>(current.size()) - 1;
+ }
+ if (end < -1)
+ {
+ end = -1;
+ }
+ for (int64_t i = start; i > end; i += step)
+ {
+ std::size_t j = static_cast<std::size_t>(i);
+ if (j < current.size())
+ {
+ this->tail_select(resources, root,
+ path_generator_type::generate(resources, last,j,options), current[j], receiver, options);
+ }
+ }
+ }
+ }
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code&) const override
+ {
+ auto jptr = resources.create_json(json_array_arg);
+ json_array_receiver<Json,JsonReference> accum(jptr);
+ select(resources, root, last, current, accum, options);
+ return *jptr;
+ }
+ };
+
+ template <class Json,class JsonReference>
+ class function_selector final : public base_selector<Json,JsonReference>
+ {
+ using supertype = base_selector<Json,JsonReference>;
+
+ expression<Json,JsonReference> expr_;
+
+ public:
+ using value_type = typename supertype::value_type;
+ using reference = typename supertype::reference;
+ using pointer = typename supertype::pointer;
+ using path_value_pair_type = typename supertype::path_value_pair_type;
+ using json_location_node_type = typename supertype::json_location_node_type;
+ using path_generator_type = path_generator<Json,JsonReference>;
+ using node_receiver_type = typename supertype::node_receiver_type;
+
+ function_selector(expression<Json,JsonReference>&& expr)
+ : base_selector<Json,JsonReference>(), expr_(std::move(expr))
+ {
+ }
+
+ void select(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ node_receiver_type& receiver,
+ result_options options) const override
+ {
+ std::error_code ec;
+ value_type ref = expr_.evaluate(resources, root, current, options, ec);
+ if (!ec)
+ {
+ this->tail_select(resources, root, last, *resources.create_json(std::move(ref)), receiver, options);
+ }
+ }
+
+ reference evaluate(dynamic_resources<Json,JsonReference>& resources,
+ reference root,
+ const json_location_node_type& last,
+ reference current,
+ result_options options,
+ std::error_code& ec) const override
+ {
+ value_type ref = expr_.evaluate(resources, root, current, options, ec);
+ if (!ec)
+ {
+ return this->evaluate_tail(resources, root, last, *resources.create_json(std::move(ref)),
+ options, ec);
+ }
+ else
+ {
+ return resources.null_value();
+ }
+ }
+
+ std::string to_string(int level = 0) const override
+ {
+ std::string s;
+ if (level > 0)
+ {
+ s.append("\n");
+ s.append(level*2, ' ');
+ }
+ s.append("function_selector ");
+ s.append(expr_.to_string(level+1));
+
+ return s;
+ }
+ };
+
+} // namespace detail
+} // namespace jsonpath
+} // namespace jsoncons
+
+#endif