summaryrefslogtreecommitdiff
path: root/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp')
-rw-r--r--vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp921
1 files changed, 921 insertions, 0 deletions
diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp
new file mode 100644
index 00000000..7e530abd
--- /dev/null
+++ b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp
@@ -0,0 +1,921 @@
+// Copyright 2013 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_JSONQUERY_HPP
+#define JSONCONS_JSONPATH_JSONQUERY_HPP
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <istream>
+#include <cstdlib>
+#include <memory>
+#include "jsoncons/json.hpp"
+#include "jsonpath_filter.hpp"
+#include "jsonpath_error_category.hpp"
+
+namespace jsoncons { namespace jsonpath {
+
+ template<typename CharT>
+ bool try_string_to_index(const CharT *s, size_t length, size_t* value)
+ {
+ static const size_t max_value = std::numeric_limits<size_t>::max JSONCONS_NO_MACRO_EXP();
+ static const size_t max_value_div_10 = max_value / 10;
+
+ size_t n = 0;
+ for (size_t i = 0; i < length; ++i)
+ {
+ CharT c = s[i];
+ switch (c)
+ {
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ {
+ size_t x = c - '0';
+ if (n > max_value_div_10)
+ {
+ return false;
+ }
+ n = n * 10;
+ if (n > max_value - x)
+ {
+ return false;
+ }
+
+ n += x;
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
+ }
+ *value = n;
+ return true;
+ }
+
+ template <typename CharT>
+ struct json_jsonpath_traits
+ {
+ };
+
+ template <>
+ struct json_jsonpath_traits<char>
+ {
+ static const std::string length_literal() {return "length";};
+ };
+
+ template <>
+ struct json_jsonpath_traits<wchar_t> // assume utf16
+ {
+ static const std::wstring length_literal() {return L"length";};
+ };
+
+// here
+
+template<class JsonT>
+JsonT json_query(const JsonT& root, const typename JsonT::char_type* path, size_t length)
+{
+ jsonpath_evaluator<JsonT> evaluator;
+ evaluator.evaluate(root,path,length);
+ return evaluator.get_values();
+}
+
+template<class JsonT>
+JsonT json_query(const JsonT& root, const typename JsonT::string_type& path)
+{
+ return json_query(root,path.data(),path.length());
+}
+
+template<class JsonT>
+JsonT json_query(const JsonT& root, const typename JsonT::char_type* path)
+{
+ return json_query(root,path,std::char_traits<typename JsonT::char_type>::length(path));
+}
+
+enum class states
+{
+ start,
+ cr,
+ lf,
+ expect_separator,
+ expect_unquoted_name,
+ unquoted_name,
+ single_quoted_name,
+ double_quoted_name,
+ left_bracket,
+ left_bracket_start,
+ left_bracket_end,
+ left_bracket_end2,
+ left_bracket_step,
+ left_bracket_step2,
+ expect_right_bracket,
+ dot
+};
+
+template<class JsonT>
+class jsonpath_evaluator : private basic_parsing_context<typename JsonT::char_type>
+{
+private:
+ typedef typename JsonT::char_type char_type;
+ typedef typename JsonT::string_type string_type;
+ typedef const JsonT* cjson_ptr;
+ typedef std::vector<cjson_ptr> node_set;
+
+ basic_parse_error_handler<char_type> *err_handler_;
+ states state_;
+ string_type buffer_;
+ size_t start_;
+ size_t end_;
+ size_t step_;
+ bool positive_start_;
+ bool positive_end_;
+ bool positive_step_;
+ bool end_undefined_;
+ std::vector<node_set> stack_;
+ bool recursive_descent_;
+ std::vector<cjson_ptr> nodes_;
+ std::vector<std::shared_ptr<JsonT>> temp_;
+ size_t line_;
+ size_t column_;
+ const char_type* begin_input_;
+ const char_type* end_input_;
+ const char_type* p_;
+ states pre_line_break_state_;
+
+ void transfer_nodes()
+ {
+ stack_.push_back(nodes_);
+ nodes_.clear();
+ }
+
+public:
+ jsonpath_evaluator()
+ : err_handler_(std::addressof(basic_default_parse_error_handler<char_type>::instance()))
+ {
+ }
+
+ JsonT get_values() const
+ {
+ JsonT result = JsonT::make_array();
+
+ if (stack_.size() > 0)
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ cjson_ptr p = stack_.back()[i];
+ result.add(*p);
+ }
+ }
+ return result;
+ }
+
+ void evaluate(const JsonT& root, const string_type& path)
+ {
+ evaluate(root,path.data(),path.length());
+ }
+ void evaluate(const JsonT& root, const char_type* path)
+ {
+ evaluate(root,path,std::char_traits<char_type>::length(path));
+ }
+
+ void evaluate(const JsonT& root, const char_type* path, size_t length)
+ {
+ begin_input_ = path;
+ end_input_ = path + length;
+ p_ = begin_input_;
+
+ line_ = 1;
+ column_ = 1;
+ state_ = states::start;
+ buffer_.clear();
+ start_ = 0;
+ end_ = 0;
+ step_ = 1;
+ recursive_descent_ = false;
+ positive_start_ = true;
+ positive_end_ = true;
+ positive_step_ = true;
+ end_undefined_ = false;
+
+ while (p_ < end_input_)
+ {
+ switch (state_)
+ {
+ case states::cr:
+ ++line_;
+ column_ = 1;
+ switch (*p_)
+ {
+ case '\n':
+ state_ = pre_line_break_state_;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ state_ = pre_line_break_state_;
+ break;
+ }
+ break;
+ case states::lf:
+ ++line_;
+ column_ = 1;
+ state_ = pre_line_break_state_;
+ break;
+ case states::start:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case ' ':case '\t':
+ ++p_;
+ ++column_;
+ break;
+ case '$':
+ case '@':
+ {
+ node_set v;
+ v.push_back(std::addressof(root));
+ stack_.push_back(v);
+ state_ = states::expect_separator;
+ }
+ break;
+ default:
+ err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_root, jsonpath_error_category()), *this);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case states::dot:
+ switch (*p_)
+ {
+ case '.':
+ recursive_descent_ = true;
+ ++p_;
+ ++column_;
+ state_ = states::expect_unquoted_name;
+ break;
+ default:
+ state_ = states::expect_unquoted_name;
+ break;
+ }
+ break;
+ case states::expect_unquoted_name:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case '.':
+ err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_name, jsonpath_error_category()), *this);
+ ++p_;
+ ++column_;
+ break;
+ case '*':
+ end_all();
+ transfer_nodes();
+ state_ = states::expect_separator;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ state_ = states::unquoted_name;
+ break;
+ }
+ break;
+ case states::expect_separator:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case ' ':case '\t':
+ ++p_;
+ ++column_;
+ break;
+ case '.':
+ state_ = states::dot;
+ break;
+ case '[':
+ state_ = states::left_bracket;
+ break;
+ default:
+ err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_separator, jsonpath_error_category()), *this);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case states::expect_right_bracket:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case ',':
+ state_ = states::left_bracket;
+ break;
+ case ']':
+ transfer_nodes();
+ state_ = states::expect_separator;
+ break;
+ case ' ':case '\t':
+ break;
+ default:
+ err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_right_bracket, jsonpath_error_category()), *this);
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case states::left_bracket_step:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case '-':
+ positive_step_ = false;
+ state_ = states::left_bracket_step2;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ step_ = static_cast<size_t>(*p_-'0');
+ state_ = states::left_bracket_step2;
+ break;
+ case ']':
+ end_array_slice();
+ transfer_nodes();
+ state_ = states::expect_separator;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case states::left_bracket_step2:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ step_ = step_*10 + static_cast<size_t>(*p_-'0');
+ break;
+ case ']':
+ end_array_slice();
+ transfer_nodes();
+ state_ = states::expect_separator;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case states::left_bracket_end:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case '-':
+ positive_end_ = false;
+ state_ = states::left_bracket_end2;
+ break;
+ case ':':
+ step_ = 0;
+ state_ = states::left_bracket_step;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ end_undefined_ = false;
+ end_ = static_cast<size_t>(*p_-'0');
+ state_ = states::left_bracket_end2;
+ break;
+ case ']':
+ end_array_slice();
+ transfer_nodes();
+ state_ = states::expect_separator;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case states::left_bracket_end2:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case ':':
+ step_ = 0;
+ state_ = states::left_bracket_step;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ end_undefined_ = false;
+ end_ = end_*10 + static_cast<size_t>(*p_-'0');
+ break;
+ case ']':
+ end_array_slice();
+ transfer_nodes();
+ state_ = states::expect_separator;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case states::left_bracket_start:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case ':':
+ step_ = 1;
+ end_undefined_ = true;
+ state_ = states::left_bracket_end;
+ break;
+ case ',':
+ find_elements();
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ start_ = start_*10 + static_cast<size_t>(*p_-'0');
+ break;
+ case ']':
+ find_elements();
+ transfer_nodes();
+ state_ = states::expect_separator;
+ break;
+ }
+ ++p_;
+ ++column_;
+ break;
+ case states::left_bracket:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case ' ':case '\t':
+ ++p_;
+ ++column_;
+ break;
+ case '(':
+ {
+ if (stack_.back().size() == 1)
+ {
+ jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_);
+ parser.parse(p_,end_input_);
+ auto index = parser.eval(*(stack_.back()[0]));
+ if (index.template is<size_t>())
+ {
+ start_ = index. template as<size_t>();
+ find_elements();
+ }
+ else if (index.is_string())
+ {
+ find(index.as_string());
+ }
+ }
+ else
+ {
+ ++p_;
+ ++column_;
+ }
+ }
+ break;
+ case '?':
+ {
+ jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_);
+ parser.parse(p_,end_input_);
+ nodes_.clear();
+ for (size_t j = 0; j < stack_.back().size(); ++j)
+ {
+ accept(*(stack_.back()[j]),parser);
+ }
+ }
+ break;
+
+ case ':':
+ step_ = 1;
+ end_undefined_ = true;
+ state_ = states::left_bracket_end;
+ ++p_;
+ ++column_;
+ break;
+ case ',':
+ find_elements();
+ ++p_;
+ ++column_;
+ break;
+ case '-':
+ positive_start_ = false;
+ state_ = states::left_bracket_start;
+ ++p_;
+ ++column_;
+ break;
+ case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
+ start_ = static_cast<size_t>(*p_-'0');
+ state_ = states::left_bracket_start;
+ ++p_;
+ ++column_;
+ break;
+ case ']':
+ //find_elements();
+ transfer_nodes();
+ state_ = states::expect_separator;
+ ++p_;
+ ++column_;
+ break;
+ case '*':
+ end_all();
+ //transfer_nodes();
+ state_ = states::expect_right_bracket;
+ ++p_;
+ ++column_;
+ break;
+ case '\'':
+ state_ = states::single_quoted_name;
+ ++p_;
+ ++column_;
+ break;
+ case '\"':
+ state_ = states::double_quoted_name;
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ++p_;
+ ++column_;
+ break;
+ }
+ break;
+ case states::unquoted_name:
+ switch (*p_)
+ {
+ case '\r':
+ pre_line_break_state_ = state_;
+ state_ = states::cr;
+ break;
+ case '\n':
+ pre_line_break_state_ = state_;
+ state_ = states::lf;
+ break;
+ case '[':
+ find(buffer_);
+ buffer_.clear();
+ transfer_nodes();
+ start_ = 0;
+ state_ = states::left_bracket;
+ break;
+ case '.':
+ find(buffer_);
+ buffer_.clear();
+ transfer_nodes();
+ state_ = states::dot;
+ break;
+ case ' ':case '\t':
+ break;
+ default:
+ buffer_.push_back(*p_);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case states::single_quoted_name:
+ switch (*p_)
+ {
+ case '\'':
+ find(buffer_);
+ buffer_.clear();
+ state_ = states::expect_right_bracket;
+ break;
+ case '\\':
+ buffer_.push_back(*p_);
+ if (p_+1 < end_input_)
+ {
+ ++p_;
+ ++column_;
+ buffer_.push_back(*p_);
+ }
+ break;
+ default:
+ buffer_.push_back(*p_);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ case states::double_quoted_name:
+ switch (*p_)
+ {
+ case '\"':
+ find(buffer_);
+ buffer_.clear();
+ state_ = states::expect_right_bracket;
+ break;
+ case '\\':
+ buffer_.push_back(*p_);
+ if (p_+1 < end_input_)
+ {
+ ++p_;
+ ++column_;
+ buffer_.push_back(*p_);
+ }
+ break;
+ default:
+ buffer_.push_back(*p_);
+ break;
+ };
+ ++p_;
+ ++column_;
+ break;
+ default:
+ ++p_;
+ ++column_;
+ break;
+ }
+ }
+ switch (state_)
+ {
+ case states::unquoted_name:
+ {
+ find(buffer_);
+ buffer_.clear();
+ transfer_nodes();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void accept(const JsonT& val,
+ jsonpath_filter_parser<JsonT>& filter)
+ {
+ if (val.is_object())
+ {
+ if (recursive_descent_ && val.is_object())
+ {
+ for (auto it = val.members().begin(); it != val.members().end(); ++it)
+ {
+ accept(it->value(),filter);
+ }
+ }
+ if (filter.exists(val))
+ {
+ nodes_.push_back(std::addressof(val));
+ }
+ }
+ else if (val.is_array())
+ {
+ for (auto it = val.elements().begin(); it != val.elements().end(); ++it)
+ {
+ accept(*it,filter);
+ }
+ }
+ }
+
+
+
+ void end_all()
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ cjson_ptr p = stack_.back()[i];
+ if (p->is_array())
+ {
+ for (auto it = p->elements().begin(); it != p->elements().end(); ++it)
+ {
+ nodes_.push_back(std::addressof(*it));
+ }
+ }
+ else if (p->is_object())
+ {
+ for (auto it = p->members().begin(); it != p->members().end(); ++it)
+ {
+ nodes_.push_back(std::addressof(it->value()));
+ }
+ }
+
+ }
+ start_ = 0;
+ }
+
+ void find_elements()
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ cjson_ptr p = stack_.back()[i];
+ if (p->is_array() && start_ < p->size())
+ {
+ nodes_.push_back(std::addressof((*p)[start_]));
+ }
+ }
+ start_ = 0;
+ }
+
+ void end_array_slice()
+ {
+ if (positive_step_)
+ {
+ end_array_slice1();
+ }
+ else
+ {
+ end_array_slice2();
+ }
+ start_ = 0;
+ end_ = 0;
+ step_ = 1;
+ positive_start_ = positive_end_ = positive_step_ = true;
+ end_undefined_ = true;
+ }
+
+ void end_array_slice1()
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ cjson_ptr p = stack_.back()[i];
+ if (p->is_array())
+ {
+ size_t start = positive_start_ ? start_ : p->size() - start_;
+ size_t end;
+ if (!end_undefined_)
+ {
+ end = positive_end_ ? end_ : p->size() - end_;
+ }
+ else
+ {
+ end = p->size();
+ }
+ for (size_t j = start; j < end; j += step_)
+ {
+ if (p->is_array() && j < p->size())
+ {
+ nodes_.push_back(std::addressof((*p)[j]));
+ }
+ }
+ }
+ }
+ }
+
+ void end_array_slice2()
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ cjson_ptr p = stack_.back()[i];
+ size_t start = positive_start_ ? start_ : p->size() - start_;
+ size_t end;
+ if (!end_undefined_)
+ {
+ end = positive_end_ ? end_ : p->size() - end_;
+ }
+ else
+ {
+ end = p->size();
+ }
+
+ size_t j = end + step_ - 1;
+ while (j > (start+step_-1))
+ {
+ j -= step_;
+ if (p->is_array() && j < p->size())
+ {
+ nodes_.push_back(std::addressof((*p)[j]));
+ }
+ }
+ }
+ }
+
+ void find(const string_type& name)
+ {
+ if (name.length() > 0)
+ {
+ for (size_t i = 0; i < stack_.back().size(); ++i)
+ {
+ find1(*(stack_.back()[i]), name);
+ }
+ recursive_descent_ = false;
+ }
+ }
+
+ void find1(const JsonT& context_val, const string_type& name)
+ {
+ if (context_val.is_object())
+ {
+ if (context_val.count(name) > 0)
+ {
+ nodes_.push_back(std::addressof(context_val.at(name)));
+ }
+ if (recursive_descent_)
+ {
+ for (auto it = context_val.members().begin(); it != context_val.members().end(); ++it)
+ {
+ if (it->value().is_object() || it->value().is_array())
+ {
+ find1(it->value(), name);
+ }
+ }
+ }
+ }
+ else if (context_val.is_array())
+ {
+ size_t index = 0;
+ if (try_string_to_index(name.data(),name.size(),&index))
+ {
+ if (index < context_val.size())
+ {
+ nodes_.push_back(std::addressof(context_val[index]));
+ }
+ }
+ else if (name == json_jsonpath_traits<char_type>::length_literal() && context_val.size() > 0)
+ {
+ auto q = std::make_shared<JsonT>(context_val.size());
+ temp_.push_back(q);
+ nodes_.push_back(q.get());
+ }
+ if (recursive_descent_)
+ {
+ for (auto it = context_val.elements().begin(); it != context_val.elements().end(); ++it)
+ {
+ if (it->is_object() || it->is_array())
+ {
+ find1(*it, name);
+ }
+ }
+ }
+ }
+ }
+
+ size_t do_line_number() const override
+ {
+ return line_;
+ }
+
+ size_t do_column_number() const override
+ {
+ return column_;
+ }
+
+ char_type do_current_char() const override
+ {
+ return 0; //p_ < end_input_? *p_ : 0;
+ }
+
+};
+
+}}
+
+#endif