diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cc | 4 | ||||
-rw-r--r-- | src/value.h | 26 | ||||
-rw-r--r-- | src/xpath.cc | 388 | ||||
-rw-r--r-- | src/xpath.h | 170 |
4 files changed, 364 insertions, 224 deletions
diff --git a/src/main.cc b/src/main.cc index 0b29e253..d01ebd50 100644 --- a/src/main.cc +++ b/src/main.cc @@ -145,7 +145,7 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[], xml::xpath_t expr(*arg); xml::document_t temp(xml::LEDGER_NODE); - xml::xpath_t::context_scope_t doc_scope(report, temp); + xml::xpath_t::context_scope_t doc_scope(report, &temp); IF_INFO() { std::cout << "Value expression tree:" << std::endl; @@ -260,7 +260,7 @@ static int read_and_report(ledger::report_t& report, int argc, char * argv[], // Are we handling the expr commands? Do so now. - xml::xpath_t::context_scope_t doc_scope(report, xml_document); + xml::xpath_t::context_scope_t doc_scope(report, &xml_document); if (verb == "expr") { xml::xpath_t expr(*arg); diff --git a/src/value.h b/src/value.h index 47db1a31..62bbca63 100644 --- a/src/value.h +++ b/src/value.h @@ -539,19 +539,21 @@ public: } void push_back(const value_t& val) { - if (is_null()) { - *this = val; - } else { - if (! is_sequence()) - in_place_cast(SEQUENCE); - - value_t::sequence_t& seq(as_sequence_lval()); - if (! val.is_sequence()) { - if (! val.is_null()) - seq.push_back(val); + if (! val.is_null()) { + if (is_null()) { + *this = val; } else { - const value_t::sequence_t& val_seq(val.as_sequence()); - std::copy(val_seq.begin(), val_seq.end(), back_inserter(seq)); + if (! is_sequence()) + in_place_cast(SEQUENCE); + + value_t::sequence_t& seq(as_sequence_lval()); + if (! val.is_sequence()) { + if (! val.is_null()) + seq.push_back(val); + } else { + const value_t::sequence_t& val_seq(val.as_sequence()); + std::copy(val_seq.begin(), val_seq.end(), back_inserter(seq)); + } } } } diff --git a/src/xpath.cc b/src/xpath.cc index 43b16403..e35cf675 100644 --- a/src/xpath.cc +++ b/src/xpath.cc @@ -405,6 +405,11 @@ void xpath_t::token_t::unexpected(char c, char wanted) } } + +void xpath_t::scope_t::define(const string& name, const value_t& val) { + define(name, op_t::wrap_value(val)); +} + void xpath_t::symbol_scope_t::define(const string& name, ptr_op_t def) { DEBUG("ledger.xpath.syms", "Defining '" << name << "' = " << def); @@ -424,29 +429,27 @@ void xpath_t::symbol_scope_t::define(const string& name, ptr_op_t def) } } -void xpath_t::scope_t::define(const string& name, const value_t& val) { - define(name, op_t::wrap_value(val)); -} - -value_t xpath_fn_last(xpath_t::call_scope_t& scope) -{ - xpath_t::context_scope_t& context(CONTEXT_SCOPE(scope)); +namespace { + value_t xpath_fn_last(xpath_t::call_scope_t& scope) + { + xpath_t::context_scope_t& context(CONTEXT_SCOPE(scope)); - return context.size(); -} + return context.size(); + } -value_t xpath_fn_position(xpath_t::call_scope_t& scope) -{ - xpath_t::context_scope_t& context(CONTEXT_SCOPE(scope)); + value_t xpath_fn_position(xpath_t::call_scope_t& scope) + { + xpath_t::context_scope_t& context(CONTEXT_SCOPE(scope)); - return context.index() + 1; -} + return context.index() + 1; + } -value_t xpath_fn_text(xpath_t::call_scope_t& scope) -{ - xpath_t::context_scope_t& context(CONTEXT_SCOPE(scope)); + value_t xpath_fn_text(xpath_t::call_scope_t& scope) + { + xpath_t::context_scope_t& context(CONTEXT_SCOPE(scope)); - return value_t(context.xml_node().to_value().to_string(), true); + return value_t(context.xml_node().to_value().to_string(), true); + } } xpath_t::ptr_op_t @@ -476,6 +479,7 @@ xpath_t::symbol_scope_t::lookup(const string& name) return child_scope_t::lookup(name); } + xpath_t::ptr_op_t xpath_t::parse_value_term(std::istream& in, flags_t tflags) const { @@ -531,7 +535,7 @@ xpath_t::parse_value_term(std::istream& in, flags_t tflags) const tok = next_token(in, tflags); if (tok.kind != token_t::RPAREN) - tok.unexpected(); // jww (2006-09-09): wanted ) + tok.unexpected(0xff, ')'); node = call_node; } else { @@ -605,7 +609,7 @@ xpath_t::parse_value_term(std::istream& in, flags_t tflags) const tok = next_token(in, tflags); if (tok.kind != token_t::RPAREN) - tok.unexpected(); // jww (2006-09-09): wanted ) + tok.unexpected(0xff, ')'); break; default: @@ -638,7 +642,7 @@ xpath_t::parse_predicate_expr(std::istream& in, flags_t tflags) const tok = next_token(in, tflags); if (tok.kind != token_t::RBRACKET) - tok.unexpected(); // jww (2006-09-09): wanted ] + tok.unexpected(0xff, ']'); tok = next_token(in, tflags); } @@ -953,16 +957,21 @@ xpath_t::parse_expr(std::istream& in, flags_t tflags) const return node; } + xpath_t::ptr_op_t xpath_t::op_t::compile(scope_t& scope) { switch (kind) { case VAR_NAME: case FUNC_NAME: - if (ptr_op_t def = scope.lookup(as_string())) - // jww (2007-05-16): Aren't definitions compiled when they go - // in? Does recompiling here really stand a chance of adding - // any benefit? + if (ptr_op_t def = scope.lookup(as_string())) { +#if 1 + return def; +#else + // Aren't definitions compiled when they go in? Would + // recompiling here really add any benefit? return def->compile(scope); +#endif + } return this; default: @@ -986,6 +995,7 @@ xpath_t::ptr_op_t xpath_t::op_t::compile(scope_t& scope) return intermediate; } + value_t xpath_t::op_t::current_value(scope_t& scope) { xpath_t::context_scope_t& context(CONTEXT_SCOPE(scope)); @@ -999,100 +1009,53 @@ node_t& xpath_t::op_t::current_xml_node(scope_t& scope) } namespace { - value_t search_nodes(value_t nodes, xpath_t::ptr_op_t find_op, - xpath_t::scope_t& scope, - const xpath_t::op_t::predicate_t& predicate, - const bool recurse) + value_t find_recursively(node_t& node, xpath_t::scope_t& scope, + xpath_t::selection_scope_t& sel_scope) { - value_t node_sequence = nodes.to_sequence(); value_t result; - foreach (value_t& node_value, node_sequence.as_sequence_lval()) { - if (! node_value.is_xml_node()) - throw_(xpath_t::calc_error, - "Application of / operator to non-node value '" - << node_value << "'"); - - node_t& node(*node_value.as_xml_node()); - xpath_t::context_scope_t node_scope(scope, node, node_sequence); + if (node.is_parent_node()) { + parent_node_t& parent_node(node.as_parent_node()); + + std::size_t index = 0; + std::size_t size = parent_node.size(); - result.push_back(find_op->calc(node_scope, predicate)); - - if (recurse && node.is_parent_node()) { - // jww (2007-05-17): This is horrible - parent_node_t& parent(node.as_parent_node()); - value_t::sequence_t children; - std::copy(parent.begin(), parent.end(), back_inserter(children)); - - result.push_back(search_nodes(children, find_op, scope, predicate, - recurse)); + foreach (node_t * child, parent_node) { + xpath_t::context_scope_t node_scope(scope, child, index, size); + result.push_back(sel_scope.selection_path->calc(node_scope)); } } return result; } - - value_t prune_values(const value_t& values, xpath_t::scope_t& scope, - const xpath_t::op_t::predicate_t& predicate) - { - if (! predicate) - return values; - - value_t values_seq = values.to_sequence(); - value_t result; - std::size_t index = 0; - - foreach (const value_t& value, values_seq.as_sequence()) { - xpath_t::context_scope_t value_scope(scope, value, values_seq); - value_t predval = predicate(value_scope); - if ((predval.is_long() && - predval.as_long() == (long)index + 1) || predval.to_boolean()) - result.push_back(value); - - index++; - } - return result; - } - - value_t prune_value(const value_t& value, xpath_t::scope_t& scope, - const xpath_t::op_t::predicate_t& predicate, - const optional<value_t>& sequence = none) - { - if (! predicate) - return value; - - if (value.is_sequence()) - return prune_values(value, scope, predicate); - - xpath_t::context_scope_t value_scope(scope, value, sequence); - value_t predval = predicate(value_scope); - if ((predval.is_long() && - predval.as_long() == 1) || predval.to_boolean()) - return value; - - return NULL_VALUE; - } } -value_t xpath_t::op_t::calc(scope_t& scope, const predicate_t& predicate) +value_t xpath_t::op_t::calc(scope_t& scope) { - bool all_nodes = false; + bool find_all_nodes = false; + bool checked = false; + bool have_xml_nodes = false; + + value_t result; switch (kind) { case VALUE: - return prune_values(as_value(), scope, predicate); + result = as_value(); + break; case VAR_NAME: case FUNC_NAME: - if (ptr_op_t reference = compile(scope)) - return reference->calc(scope, predicate); - else - throw_(calc_error, "Failed to lookup variable or function named '" - << as_string() << "'"); + if (ptr_op_t reference = compile(scope)) { + result = reference->calc(scope); + checked = true; + } else { + throw_(calc_error, "No " << (kind == VAR_NAME ? "variable" : "function") + << " named '" << as_string() << "'"); + } break; case FUNCTION: - // This should never be evaluated directly, but should only appear - // as the left node of an O_CALL operator. + // This should never be evaluated directly; it only appears as the + // left node of an O_CALL operator. assert(false); break; @@ -1115,92 +1078,122 @@ value_t xpath_t::op_t::calc(scope_t& scope, const predicate_t& predicate) name.empty() ? string("Attempt to call non-function") : (string("Attempt to call unknown function '") + name + "'")); - return prune_values(func->as_function()(call_args), scope, predicate); + result = func->as_function()(call_args); + break; } case ARG_INDEX: { - call_scope_t& args(scope.find_scope<call_scope_t>()); + call_scope_t& args(CALL_SCOPE(scope)); if (as_long() >= 0 && as_long() < args.size()) - return prune_values(args[as_long()], scope, predicate); + result = args[as_long()]; else - throw_(calc_error, "Reference to a non-existing argument"); + throw_(calc_error, "Reference to non-existing argument"); break; } case O_FIND: - case O_RFIND: - return search_nodes(left()->calc(scope), right(), scope, predicate, - kind == O_RFIND); + case O_RFIND: { + selection_scope_t find_scope(scope, right(), kind == O_RFIND); + result = left()->calc(find_scope); + checked = true; + break; + } + + case O_PRED: { + predicate_scope_t pred_scope(scope, op_predicate(right())); + result = left()->calc(pred_scope); + checked = true; + break; + } + + case NODE_ID: { + bool break_at_end = false; - case NODE_ID: switch (as_name()) { case document_t::CURRENT: - return prune_value(current_value(scope), scope, predicate); + result = current_value(scope); + have_xml_nodes = result.is_xml_node(); + break_at_end = true; + break; case document_t::PARENT: if (optional<parent_node_t&> parent = current_xml_node(scope).parent()) - return prune_value(&*parent, scope, predicate); + result = &*parent; else throw_(std::logic_error, "Attempt to access parent of root node"); + + have_xml_nodes = true; + break_at_end = true; break; case document_t::ROOT: - return prune_value(¤t_xml_node(scope).document(), scope, predicate); + result = ¤t_xml_node(scope).document(); + have_xml_nodes = true; + break_at_end = true; + break; case document_t::ALL: - all_nodes = true; + find_all_nodes = true; break; default: break; // pass down to the NODE_NAME case } + + if (break_at_end) + break; // fall through... + } case NODE_NAME: { node_t& current_node(current_xml_node(scope)); + if (current_node.is_parent_node()) { - bool have_name_id = kind == NODE_ID; - - // jww (2007-05-17): This is horrible - value_t children = value_t::sequence_t(); - foreach (node_t * child, current_node.as_parent_node()) - children.push_back(child); - - value_t result; - foreach (value_t& child, children.as_sequence_lval()) { - if (all_nodes || - ( have_name_id && as_name() == child.as_xml_node()->name_id()) || - (! have_name_id && as_string() == child.as_xml_node()->name())) { - value_t child_value = prune_value(child, scope, predicate, children); - if (! child_value.is_null()) - result.push_back(child_value); + const bool have_name_id = kind == NODE_ID; + + optional<predicate_scope_t&> pred_scope(PREDICATE_SCOPE(scope)); + + parent_node_t& parent(current_node.as_parent_node()); + + std::size_t index = 0; + std::size_t size = parent.size(); + + foreach (node_t * child, parent) { + if (find_all_nodes || + ( have_name_id && as_name() == child->name_id()) || + (! have_name_id && as_string() == child->name())) { + if (! pred_scope || ! pred_scope->predicate) { + result.push_back(child); + } else { + context_scope_t node_scope(scope, child, index, size); + if (pred_scope->predicate(node_scope)) + result.push_back(child); + } } + + index++; } - return result; + + checked = true; + have_xml_nodes = true; } - return NULL_VALUE; + break; } - case O_PRED: - return left()->calc(scope, op_functor(right())); - case ATTR_ID: - case ATTR_NAME: { - node_t& current_node(current_xml_node(scope)); - + case ATTR_NAME: if (optional<const string&> value = - kind == ATTR_ID ? current_node.get_attr(as_long()) : - current_node.get_attr(as_string())) - return prune_value(value_t(*value, true), scope, predicate); + kind == ATTR_ID ? current_xml_node(scope).get_attr(as_long()) : + current_xml_node(scope).get_attr(as_string())) + result = value_t(*value, true); else throw_(calc_error, "Attribute '" << (kind == ATTR_ID ? - *current_node.document().lookup_name(as_long()) : + *current_xml_node(scope).document().lookup_name(as_long()) : as_string().c_str()) << "' was not found"); break; - } case O_NEQ: return left()->calc(scope) != right()->calc(scope); @@ -1239,28 +1232,126 @@ value_t xpath_t::op_t::calc(scope_t& scope, const predicate_t& predicate) case O_COMMA: case O_UNION: { - value_t result = left()->calc(scope, predicate); + optional<predicate_scope_t&> pred_scope(PREDICATE_SCOPE(scope)); + { + value_t temp(left()->calc(scope)); + + context_scope_t value_scope(scope, temp, 0, 1); + if (! pred_scope || ! pred_scope->predicate || + pred_scope->predicate(value_scope)) + result.push_back(temp); + } + + std::size_t index = 0; + std::size_t size = 1; ptr_op_t next = right(); - while (next && (next->kind == O_COMMA || - next->kind == O_UNION)) { - result.push_back(next->left()->calc(scope, predicate)); - next = next->right(); + while (next) { + size++; + + if (next->kind == O_COMMA || next->kind == O_UNION) + next = next->right(); + else + next = NULL; } - assert(! next); - return result; + next = right(); + while (next) { + ptr_op_t value_op; + if (next->kind == O_COMMA || next->kind == O_UNION) { + value_op = next->left(); + next = next->right(); + } else { + value_op = next; + next = NULL; + } + + value_t inner_temp(value_op->calc(scope)); + + context_scope_t value_scope(scope, inner_temp, index, size); + if (! pred_scope || ! pred_scope->predicate || + pred_scope->predicate(value_scope)) + result.push_back(inner_temp); + + index++; + } + + checked = true; + break; } case LAST: default: + assert(false); break; } - assert(false); - return NULL_VALUE; + if (! result.is_null() && (! checked || have_xml_nodes)) { + if (optional<scope_t&> sel_or_pred_scope = + scope.find_first_scope(scope_t::SELECTION_SCOPE, + scope_t::PREDICATE_SCOPE)) { + value_t new_result; + + if (sel_or_pred_scope->type() == scope_t::SELECTION_SCOPE) { + selection_scope_t& sel_scope(downcast<selection_scope_t>(*sel_or_pred_scope)); + + if (! result.is_sequence()) { + context_scope_t node_scope(scope, result, 0, 1); + + new_result.push_back(sel_scope.selection_path->calc(node_scope)); + + if (sel_scope.recurse && result.is_xml_node()) + new_result.push_back(find_recursively(*result.as_xml_node(), + scope, sel_scope)); + } else { + std::size_t index = 0; + std::size_t size = result.as_sequence().size(); + + foreach (const value_t& value, result.as_sequence()) { + context_scope_t node_scope(scope, value, index, size); + + value_t item = sel_scope.selection_path->calc(node_scope); + new_result.push_back(item); + + if (sel_scope.recurse && item.is_xml_node()) + new_result.push_back(find_recursively(*item.as_xml_node(), + scope, sel_scope)); + + index++; + } + } + } + else { + predicate_scope_t& pred_scope(downcast<predicate_scope_t>(*sel_or_pred_scope)); + if (pred_scope.predicate) { + if (! result.is_sequence()) { + context_scope_t value_scope(scope, result, 0, 1); + if (! pred_scope.predicate(value_scope)) + new_result = NULL_VALUE; + else + new_result = result; + } else { + std::size_t index = 0; + std::size_t size = result.as_sequence().size(); + + foreach (const value_t& value, result.as_sequence()) { + context_scope_t value_scope(scope, value, index, size); + if (pred_scope.predicate(value_scope)) + new_result.push_back(value); + index++; + } + } + } + } + + result = new_result; + } + } + + return result; } + bool xpath_t::op_t::print(std::ostream& out, print_context_t& context) const { bool found = false; @@ -1634,6 +1725,7 @@ void xpath_t::op_t::dump(std::ostream& out, const int depth) const } // namespace xml + value_t xml_command(xml::xpath_t::call_scope_t& args) { assert(args.size() == 0); 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 |