diff options
Diffstat (limited to 'src/xpath.h')
-rw-r--r-- | src/xpath.h | 170 |
1 files changed, 108 insertions, 62 deletions
diff --git a/src/xpath.h b/src/xpath.h index 725be1e6..ec627fe5 100644 --- a/src/xpath.h +++ b/src/xpath.h @@ -68,7 +68,9 @@ public: CHILD_SCOPE, SYMBOL_SCOPE, CALL_SCOPE, - CONTEXT_SCOPE + CONTEXT_SCOPE, + SELECTION_SCOPE, + PREDICATE_SCOPE } type_; explicit scope_t(type_t _type) : type_(_type) { @@ -91,11 +93,18 @@ public: virtual optional<scope_t&> find_scope(const type_t _type, bool skip_this = false) = 0; + virtual optional<scope_t&> find_first_scope(const type_t _type1, + const type_t _type2, + bool skip_this = false) = 0; template <typename T> T& find_scope(bool skip_this = false) { assert(false); } + template <typename T> + optional<T&> maybe_find_scope(bool skip_this = false) { + assert(false); + } }; class child_scope_t : public scope_t @@ -135,6 +144,18 @@ public: } return none; } + + virtual optional<scope_t&> find_first_scope(const type_t _type1, + const type_t _type2, + bool skip_this = false) { + for (scope_t * ptr = (skip_this ? parent : this); ptr; ) { + if (ptr->type() == _type1 || ptr->type() == _type2) + return *ptr; + + ptr = polymorphic_downcast<child_scope_t *>(ptr)->parent; + } + return none; + } }; class symbol_scope_t : public child_scope_t @@ -205,74 +226,74 @@ public: class context_scope_t : public child_scope_t { public: - value_t element; - optional<value_t> sequence; - - explicit context_scope_t(scope_t& _parent, - const value_t& _element, - const optional<value_t>& _sequence = none) - : child_scope_t(_parent, CONTEXT_SCOPE) - { - TRACE_CTOR(xpath_t::context_scope_t, - "scope_t&, const value_t&, const optional<value_t>&"); - set_context(_element, _sequence); - } - explicit context_scope_t(scope_t& _parent, - node_t& _element, - const optional<value_t>& _sequence = none) - : child_scope_t(_parent, CONTEXT_SCOPE) + value_t current_element; + std::size_t element_index; + std::size_t sequence_size; + + explicit context_scope_t(scope_t& _parent, + const value_t& _element = NULL_VALUE, + const std::size_t _element_index = 0, + const std::size_t _sequence_size = 0) + : child_scope_t(_parent, CONTEXT_SCOPE), current_element(_element), + element_index(_element_index), sequence_size(_sequence_size) { - TRACE_CTOR(xpath_t::context_scope_t, - "scope_t&, const value_t&, const optional<value_t>&"); - set_context(value_t(&_element), _sequence); + TRACE_CTOR(xpath_t::context_scope_t, "scope_t&, const value_t&, ..."); } virtual ~context_scope_t() { TRACE_DTOR(xpath_t::context_scope_t); } - void set_context(const value_t& _element, - const optional<value_t>& _sequence) { - element = _element; - sequence = _sequence; - - assert(! element.is_sequence()); - - if (DO_VERIFY() && sequence) { - if (sequence->is_sequence()) { - value_t::sequence_t seq(sequence->as_sequence()); - value_t::iterator i = std::find(seq.begin(), seq.end(), element); - assert(i != seq.end()); - } else { - assert(element == *sequence); - } - } - } - const std::size_t index() const { - if (! sequence) { - return 0; - } else { - value_t::sequence_t seq(sequence->as_sequence()); - value_t::iterator i = std::find(seq.begin(), seq.end(), element); - assert(i != seq.end()); - int_least16_t offset = i - seq.begin(); - assert(offset >= 0); - return std::size_t(offset); - } + return element_index; } - const std::size_t size() const { - return sequence ? sequence->size() : (element.is_null() ? 0 : 1); + return sequence_size; } value_t& value() { - return element; + return current_element; } - node_t& xml_node() { - if (! element.is_xml_node()) - throw_(calc_error, "The current context value is not an XML node"); - return *element.as_xml_node(); + assert(current_element.is_xml_node()); + return *current_element.as_xml_node(); + } + }; + + class selection_scope_t : public child_scope_t + { + public: + ptr_op_t selection_path; + bool recurse; + + explicit selection_scope_t(scope_t& _parent, + const ptr_op_t& _selection_path = NULL, + const bool _recurse = false) + : child_scope_t(_parent, SELECTION_SCOPE), + selection_path(_selection_path), recurse(_recurse) + { + TRACE_CTOR(xpath_t::selection_scope_t, + "scope_t&, const ptr_op_t&, const bool"); + } + virtual ~selection_scope_t() { + TRACE_DTOR(xpath_t::selection_scope_t); + } + }; + + typedef function<bool (scope_t&)> predicate_t; + + class predicate_scope_t : public child_scope_t + { + public: + predicate_t predicate; + + explicit predicate_scope_t(scope_t& _parent, + const predicate_t& _predicate = predicate_t()) + : child_scope_t(_parent, PREDICATE_SCOPE), predicate(_predicate) + { + TRACE_CTOR(xpath_t::predicate_scope_t, "scope_t&, const predicate_t&"); + } + virtual ~predicate_scope_t() { + TRACE_DTOR(xpath_t::predicate_scope_t); } }; @@ -604,12 +625,10 @@ public: static ptr_op_t wrap_value(const value_t& val); static ptr_op_t wrap_functor(const function_t& fobj); - typedef function<value_t (scope_t&)> predicate_t; - ptr_op_t compile(scope_t& scope); value_t current_value(scope_t& scope); node_t& current_xml_node(scope_t& scope); - value_t calc(scope_t& scope, const predicate_t& = predicate_t()); + value_t calc(scope_t& scope); struct print_context_t { @@ -639,12 +658,13 @@ public: } }; - class op_functor { + class op_predicate { ptr_op_t op; public: - explicit op_functor(ptr_op_t _op) : op(_op) {} - value_t operator()(scope_t& scope) const { - return op->calc(scope); + explicit op_predicate(ptr_op_t _op) : op(_op) {} + bool operator()(scope_t& scope) { + predicate_scope_t null_predicate(scope); + return op->calc(null_predicate).to_boolean(); } }; @@ -875,8 +895,30 @@ xpath_t::scope_t::find_scope<xpath_t::context_scope_t>(bool skip_this) { return downcast<context_scope_t>(*scope); } +template<> +inline optional<xpath_t::selection_scope_t&> +xpath_t::scope_t::maybe_find_scope<xpath_t::selection_scope_t>(bool skip_this) { + optional<scope_t&> scope = find_scope(SELECTION_SCOPE, skip_this); + if (scope) + return downcast<selection_scope_t>(*scope); + else + return none; +} + +template<> +inline optional<xpath_t::predicate_scope_t&> +xpath_t::scope_t::maybe_find_scope<xpath_t::predicate_scope_t>(bool skip_this) { + optional<scope_t&> scope = find_scope(PREDICATE_SCOPE, skip_this); + if (scope) + return downcast<predicate_scope_t>(*scope); + else + return none; +} + #define FIND_SCOPE(scope_type, scope_ref) \ downcast<xml::xpath_t::scope_t>(scope_ref).find_scope<scope_type>() +#define MAYBE_FIND_SCOPE(scope_type, scope_ref) \ + downcast<xml::xpath_t::scope_t>(scope_ref).maybe_find_scope<scope_type>() #define CALL_SCOPE(scope_ref) \ FIND_SCOPE(xml::xpath_t::call_scope_t, scope_ref) @@ -884,6 +926,10 @@ xpath_t::scope_t::find_scope<xpath_t::context_scope_t>(bool skip_this) { FIND_SCOPE(xml::xpath_t::symbol_scope_t, scope_ref) #define CONTEXT_SCOPE(scope_ref) \ FIND_SCOPE(xml::xpath_t::context_scope_t, scope_ref) +#define SELECTION_SCOPE(scope_ref) \ + MAYBE_FIND_SCOPE(xml::xpath_t::selection_scope_t, scope_ref) +#define PREDICATE_SCOPE(scope_ref) \ + MAYBE_FIND_SCOPE(xml::xpath_t::predicate_scope_t, scope_ref) } // namespace xml |