Revised xpath_t::path_t
This commit is contained in:
parent
e309cac9c1
commit
74ecceb2ba
4 changed files with 74 additions and 139 deletions
|
|
@ -75,6 +75,7 @@ class python_interpreter_t : public xml::xpath_t::scope_t
|
|||
boost::python::object func;
|
||||
public:
|
||||
functor_t(const string& name, boost::python::object _func) : func(_func) {}
|
||||
virtual ~functor_t() {}
|
||||
virtual value_t operator()(xml::xpath_t::scope_t * locals);
|
||||
};
|
||||
|
||||
|
|
|
|||
157
src/xpath.cc
157
src/xpath.cc
|
|
@ -689,7 +689,7 @@ xpath_t::parse_path_expr(std::istream& in, flags_t tflags) const
|
|||
|
||||
if (node) {
|
||||
token_t& tok = next_token(in, tflags);
|
||||
while (tok.kind == token_t::SLASH) {
|
||||
if (tok.kind == token_t::SLASH) {
|
||||
ptr_op_t prev(node);
|
||||
|
||||
tok = next_token(in, tflags);
|
||||
|
|
@ -699,14 +699,12 @@ xpath_t::parse_path_expr(std::istream& in, flags_t tflags) const
|
|||
push_token(tok);
|
||||
|
||||
node->set_left(prev);
|
||||
node->set_right(parse_predicate_expr(in, tflags));
|
||||
node->set_right(parse_path_expr(in, tflags));
|
||||
if (! node->right())
|
||||
throw_(parse_error, "/ operator not followed by a valid term");
|
||||
|
||||
tok = next_token(in, tflags);
|
||||
} else {
|
||||
push_token(tok);
|
||||
}
|
||||
|
||||
push_token(tok);
|
||||
}
|
||||
|
||||
return node;
|
||||
|
|
@ -2117,101 +2115,40 @@ void xpath_t::op_t::dump(std::ostream& out, const int depth) const
|
|||
}
|
||||
}
|
||||
|
||||
xpath_t::path_t::path_t(const xpath_t& path_expr)
|
||||
void xpath_t::path_t::check_element(node_t& start,
|
||||
const ptr_op_t& element,
|
||||
scope_t * scope,
|
||||
std::size_t index,
|
||||
std::size_t size,
|
||||
const visitor_t& func)
|
||||
{
|
||||
ptr_op_t op = path_expr.ptr;
|
||||
|
||||
while (true) {
|
||||
element_t element;
|
||||
|
||||
switch (op->kind) {
|
||||
case op_t::O_RFIND:
|
||||
element.recurse = true;
|
||||
// fall through...
|
||||
case op_t::O_FIND: {
|
||||
ptr_op_t name;
|
||||
if (op->right()->kind == op_t::O_PRED) {
|
||||
element.predicate = op_predicate(op->right()->right());
|
||||
name = op->right()->left();
|
||||
} else {
|
||||
name = op->right();
|
||||
}
|
||||
|
||||
switch (name->kind) {
|
||||
case op_t::NODE_ID: {
|
||||
//case op_t::ATTR_ID:
|
||||
node_t::nameid_t name_id = name->as_name();
|
||||
if (name_id < document_t::LAST_BUILTIN)
|
||||
element.ident = document_t::special_names_t(name_id);
|
||||
else
|
||||
element.ident = name_id;
|
||||
break;
|
||||
}
|
||||
case op_t::NODE_NAME:
|
||||
//case op_t::ATTR_NAME:
|
||||
element.ident = name->as_string();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case op_t::NODE_ID: {
|
||||
//case op_t::ATTR_ID:
|
||||
node_t::nameid_t name_id = op->as_name();
|
||||
if (name_id < document_t::LAST_BUILTIN)
|
||||
element.ident = document_t::special_names_t(name_id);
|
||||
else
|
||||
element.ident = name_id;
|
||||
break;
|
||||
}
|
||||
case op_t::NODE_NAME:
|
||||
//case op_t::ATTR_NAME:
|
||||
element.ident = op->as_string();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw_(std::logic_error, "XPath expression is not strictly a path selection");
|
||||
break;
|
||||
}
|
||||
|
||||
elements.push_front(element);
|
||||
|
||||
if (op->kind < op_t::TERMINALS)
|
||||
break;
|
||||
else
|
||||
op = op->left();
|
||||
}
|
||||
}
|
||||
|
||||
void xpath_t::path_t::check_element(node_t& start,
|
||||
const element_iterator& element,
|
||||
scope_t * scope,
|
||||
std::size_t index,
|
||||
std::size_t size,
|
||||
const visitor_t& func)
|
||||
{
|
||||
if (element->predicate) {
|
||||
if (element->kind > op_t::TERMINALS &&
|
||||
element->left()->kind == op_t::O_PRED) {
|
||||
function_scope_t xpath_fscope(start, index, size, scope);
|
||||
if (! element->predicate(start, &xpath_fscope))
|
||||
if (! op_predicate(element->left()->right())(start, &xpath_fscope))
|
||||
return;
|
||||
}
|
||||
|
||||
element_iterator next_element = next(element);
|
||||
if (next_element == elements.end())
|
||||
if (element->kind < op_t::TERMINALS)
|
||||
func(start);
|
||||
else
|
||||
walk_elements(start, next_element, scope, func);
|
||||
walk_elements(start, element->right(), element->kind == op_t::O_RFIND,
|
||||
scope, func);
|
||||
}
|
||||
|
||||
void xpath_t::path_t::walk_elements(node_t& start,
|
||||
const element_iterator& element,
|
||||
scope_t * scope,
|
||||
const visitor_t& func)
|
||||
void xpath_t::path_t::walk_elements(node_t& start,
|
||||
const ptr_op_t& element,
|
||||
const bool recurse,
|
||||
scope_t * scope,
|
||||
const visitor_t& func)
|
||||
{
|
||||
if (element->ident.type() == typeid(document_t::special_names_t)) {
|
||||
switch (boost::get<document_t::special_names_t>(element->ident)) {
|
||||
ptr_op_t name(element->kind < op_t::TERMINALS ? element : element->left());
|
||||
if (name->kind == op_t::O_PRED)
|
||||
name = name->left();
|
||||
|
||||
switch (name->kind) {
|
||||
case op_t::NODE_ID:
|
||||
switch (name->as_name()) {
|
||||
case document_t::CURRENT:
|
||||
check_element(start, element, scope, 0, 1, func);
|
||||
break;
|
||||
|
|
@ -2239,24 +2176,32 @@ void xpath_t::path_t::walk_elements(node_t& start,
|
|||
}
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
break; // pass down to the NODE_NAME case
|
||||
}
|
||||
}
|
||||
else if (start.is_parent_node()) {
|
||||
bool have_name_id = element->ident.type() == typeid(node_t::nameid_t);
|
||||
// fall through...
|
||||
|
||||
std::size_t index = 0;
|
||||
std::size_t size = start.as_parent_node().size();
|
||||
foreach (node_t * child, start.as_parent_node()) {
|
||||
if ((have_name_id &&
|
||||
boost::get<node_t::nameid_t>(element->ident) == child->name_id()) ||
|
||||
(! have_name_id &&
|
||||
boost::get<string>(element->ident) == child->name()))
|
||||
check_element(*child, element, scope, index++, size, func);
|
||||
else if (element->recurse)
|
||||
walk_elements(*child, element, scope, func);
|
||||
case op_t::NODE_NAME:
|
||||
if (start.is_parent_node()) {
|
||||
bool have_name_id = name->kind == op_t::NODE_ID;
|
||||
|
||||
std::size_t index = 0;
|
||||
std::size_t size = start.as_parent_node().size();
|
||||
foreach (node_t * child, start.as_parent_node()) {
|
||||
if ((have_name_id && name->as_name() == child->name_id()) ||
|
||||
(! have_name_id && name->as_string() == child->name()))
|
||||
check_element(*child, element, scope, index++, size, func);
|
||||
else if (recurse)
|
||||
walk_elements(*child, element, recurse, scope, func);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// jww (2007-05-15): Instead of a name, this might be an
|
||||
// expression resulting in a nodelist with respect to the current
|
||||
// context.
|
||||
throw_(std::logic_error, "XPath expression is not strictly a path selection");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
45
src/xpath.h
45
src/xpath.h
|
|
@ -219,19 +219,6 @@ public:
|
|||
typedef function<void (node_t&)> visitor_t;
|
||||
typedef function<bool (node_t&, scope_t *)> predicate_t;
|
||||
|
||||
struct element_t
|
||||
{
|
||||
variant<node_t::nameid_t, string,
|
||||
document_t::special_names_t> ident;
|
||||
|
||||
bool recurse;
|
||||
predicate_t predicate;
|
||||
};
|
||||
|
||||
std::list<element_t> elements;
|
||||
|
||||
typedef std::list<element_t>::const_iterator element_iterator;
|
||||
|
||||
struct value_node_appender_t {
|
||||
value_t::sequence_t& sequence;
|
||||
value_node_appender_t(value_t::sequence_t& _sequence)
|
||||
|
|
@ -241,34 +228,36 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
ptr_op_t path_expr;
|
||||
|
||||
public:
|
||||
path_t(const xpath_t& path_expr);
|
||||
path_t(const xpath_t& xpath) : path_expr(xpath.ptr) {}
|
||||
|
||||
value_t find_all(node_t& start, scope_t * scope) {
|
||||
value_t result = value_t::sequence_t();
|
||||
visit(start, scope,
|
||||
value_node_appender_t(result.as_sequence_lval()));
|
||||
visit(start, scope, value_node_appender_t(result.as_sequence_lval()));
|
||||
return result;
|
||||
}
|
||||
|
||||
void visit(node_t& start, scope_t * scope,
|
||||
const function<void (node_t&)>& func) {
|
||||
if (elements.begin() != elements.end())
|
||||
walk_elements(start, elements.begin(), scope, func);
|
||||
if (path_expr)
|
||||
walk_elements(start, path_expr, false, scope, func);
|
||||
}
|
||||
|
||||
private:
|
||||
void walk_elements(node_t& start,
|
||||
const element_iterator& element,
|
||||
scope_t * scope,
|
||||
const visitor_t& func);
|
||||
void walk_elements(node_t& start,
|
||||
const ptr_op_t& element,
|
||||
const bool recurse,
|
||||
scope_t * scope,
|
||||
const visitor_t& func);
|
||||
|
||||
void check_element(node_t& start,
|
||||
const element_iterator& element,
|
||||
scope_t * scope,
|
||||
std::size_t index,
|
||||
std::size_t size,
|
||||
const visitor_t& func);
|
||||
void check_element(node_t& start,
|
||||
const ptr_op_t& element,
|
||||
scope_t * scope,
|
||||
std::size_t index,
|
||||
std::size_t size,
|
||||
const visitor_t& func);
|
||||
};
|
||||
|
||||
class path_iterator_t
|
||||
|
|
|
|||
|
|
@ -357,10 +357,10 @@ void AmountTestCase::testCommodityEquality()
|
|||
assertTrue(x0.is_null());
|
||||
assertThrow(x0.is_zero(), amount_error);
|
||||
assertThrow(x0.is_realzero(), amount_error);
|
||||
assertThrow(x0.sign() == 0, amount_error);
|
||||
assertThrow(x0.compare(x1) < 0, amount_error);
|
||||
assertThrow(x0.compare(x2) > 0, amount_error);
|
||||
assertThrow(x0.compare(x0) == 0, amount_error);
|
||||
assertThrow(assert(x0.sign() == 0), amount_error);
|
||||
assertThrow(assert(x0.compare(x1) < 0), amount_error);
|
||||
assertThrow(assert(x0.compare(x2) > 0), amount_error);
|
||||
assertThrow(assert(x0.compare(x0) == 0), amount_error);
|
||||
|
||||
assertTrue(x1 != x2);
|
||||
assertTrue(x1 != x4);
|
||||
|
|
@ -1311,7 +1311,7 @@ void AmountTestCase::testTruth()
|
|||
amount_t x1("1234");
|
||||
amount_t x2("1234.56");
|
||||
|
||||
assertThrow(x0 ? 1 : 0, amount_error);
|
||||
assertThrow(assert(x0 ? 1 : 0), amount_error);
|
||||
|
||||
assertTrue(x1);
|
||||
assertTrue(x2);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue