Started working on an XPath visitor class
This commit is contained in:
parent
9e55655e0c
commit
3244c693f8
4 changed files with 218 additions and 30 deletions
22
src/main.cc
22
src/main.cc
|
|
@ -46,6 +46,10 @@
|
|||
#include <fdstream.hpp>
|
||||
#endif
|
||||
|
||||
void print_node(ledger::xml::node_t& node) {
|
||||
node.print(std::cout);
|
||||
}
|
||||
|
||||
static int read_and_report(ledger::report_t * report, int argc, char * argv[],
|
||||
char * envp[])
|
||||
{
|
||||
|
|
@ -269,12 +273,28 @@ static int read_and_report(ledger::report_t * report, int argc, char * argv[],
|
|||
xpath.print(*out, xml_document);
|
||||
*out << std::endl;
|
||||
|
||||
#if 1
|
||||
try {
|
||||
xml::xpath_t::path_t path_selection(xpath);
|
||||
|
||||
xml::xpath_t::path_t::element_t elem;
|
||||
elem.ident = xml::document_t::ROOT;
|
||||
path_selection.elements.push_back(elem);
|
||||
elem.ident = xml::TRANSACTION_NODE;
|
||||
elem.recurse = true;
|
||||
path_selection.elements.push_back(elem);
|
||||
path_selection.visit(xml_document, report, bind(print_node, _1));
|
||||
}
|
||||
catch (...) {
|
||||
throw;
|
||||
}
|
||||
#else
|
||||
value_t nodelist;
|
||||
xpath.calc(nodelist, xml_document, report);
|
||||
|
||||
foreach (const value_t& node, nodelist.as_sequence())
|
||||
node.as_xml_node()->print(*out);
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1440,9 +1440,12 @@ value_t value_t::strip_annotations(const bool keep_price,
|
|||
case POINTER:
|
||||
return *this;
|
||||
|
||||
case SEQUENCE:
|
||||
assert(false); // jww (2006-09-28): strip them all!
|
||||
break;
|
||||
case SEQUENCE: {
|
||||
sequence_t temp;
|
||||
foreach (const value_t& value, as_sequence())
|
||||
temp.push_back(value.strip_annotations(keep_price, keep_date, keep_tag));
|
||||
return temp;
|
||||
}
|
||||
|
||||
case AMOUNT:
|
||||
return as_amount().strip_annotations
|
||||
|
|
|
|||
138
src/xpath.cc
138
src/xpath.cc
|
|
@ -699,7 +699,7 @@ xpath_t::parse_path_expr(std::istream& in, flags_t tflags) const
|
|||
while (tok.kind == token_t::SLASH) {
|
||||
ptr_op_t prev(node);
|
||||
|
||||
tok = next_token(in, tflags);
|
||||
tok = next_token(in, tflags);
|
||||
node = new op_t(tok.kind == token_t::SLASH ?
|
||||
op_t::O_RFIND : op_t::O_FIND);
|
||||
if (tok.kind != token_t::SLASH)
|
||||
|
|
@ -1143,8 +1143,8 @@ void xpath_t::op_t::append_value(value_t& val,
|
|||
result_seq.push_back(val);
|
||||
}
|
||||
|
||||
xpath_t::ptr_op_t xpath_t::op_t::compile(value_t& context, scope_t * scope,
|
||||
bool resolve)
|
||||
xpath_t::ptr_op_t
|
||||
xpath_t::op_t::compile(value_t& context, scope_t * scope, bool resolve)
|
||||
{
|
||||
#if 0
|
||||
try {
|
||||
|
|
@ -1661,7 +1661,6 @@ xpath_t::ptr_op_t xpath_t::op_t::compile(value_t& context, scope_t * scope,
|
|||
throw_(compile_error, "Attempting to apply path selection "
|
||||
"to non-node(s)");
|
||||
}
|
||||
|
||||
return wrap_value(result_seq);
|
||||
}
|
||||
|
||||
|
|
@ -2103,37 +2102,37 @@ void xpath_t::op_t::dump(std::ostream& out, const int depth) const
|
|||
out << "FUNCTION - " << as_function();
|
||||
break;
|
||||
|
||||
case O_NOT: out << "O_NOT"; break;
|
||||
case O_NEG: out << "O_NEG"; break;
|
||||
case O_NOT: out << "O_NOT"; break;
|
||||
case O_NEG: out << "O_NEG"; break;
|
||||
|
||||
case O_UNION: out << "O_UNION"; break;
|
||||
case O_UNION: out << "O_UNION"; break;
|
||||
|
||||
case O_ADD: out << "O_ADD"; break;
|
||||
case O_SUB: out << "O_SUB"; break;
|
||||
case O_MUL: out << "O_MUL"; break;
|
||||
case O_DIV: out << "O_DIV"; break;
|
||||
case O_ADD: out << "O_ADD"; break;
|
||||
case O_SUB: out << "O_SUB"; break;
|
||||
case O_MUL: out << "O_MUL"; break;
|
||||
case O_DIV: out << "O_DIV"; break;
|
||||
|
||||
case O_NEQ: out << "O_NEQ"; break;
|
||||
case O_EQ: out << "O_EQ"; break;
|
||||
case O_LT: out << "O_LT"; break;
|
||||
case O_LTE: out << "O_LTE"; break;
|
||||
case O_GT: out << "O_GT"; break;
|
||||
case O_GTE: out << "O_GTE"; break;
|
||||
case O_NEQ: out << "O_NEQ"; break;
|
||||
case O_EQ: out << "O_EQ"; break;
|
||||
case O_LT: out << "O_LT"; break;
|
||||
case O_LTE: out << "O_LTE"; break;
|
||||
case O_GT: out << "O_GT"; break;
|
||||
case O_GTE: out << "O_GTE"; break;
|
||||
|
||||
case O_AND: out << "O_AND"; break;
|
||||
case O_OR: out << "O_OR"; break;
|
||||
case O_AND: out << "O_AND"; break;
|
||||
case O_OR: out << "O_OR"; break;
|
||||
|
||||
case O_QUES: out << "O_QUES"; break;
|
||||
case O_COLON: out << "O_COLON"; break;
|
||||
case O_QUES: out << "O_QUES"; break;
|
||||
case O_COLON: out << "O_COLON"; break;
|
||||
|
||||
case O_COMMA: out << "O_COMMA"; break;
|
||||
case O_COMMA: out << "O_COMMA"; break;
|
||||
|
||||
case O_DEFINE: out << "O_DEFINE"; break;
|
||||
case O_EVAL: out << "O_EVAL"; break;
|
||||
case O_EVAL: out << "O_EVAL"; break;
|
||||
|
||||
case O_FIND: out << "O_FIND"; break;
|
||||
case O_RFIND: out << "O_RFIND"; break;
|
||||
case O_PRED: out << "O_PRED"; break;
|
||||
case O_FIND: out << "O_FIND"; break;
|
||||
case O_RFIND: out << "O_RFIND"; break;
|
||||
case O_PRED: out << "O_PRED"; break;
|
||||
|
||||
case LAST:
|
||||
default:
|
||||
|
|
@ -2156,5 +2155,92 @@ void xpath_t::op_t::dump(std::ostream& out, const int depth) const
|
|||
}
|
||||
}
|
||||
|
||||
xpath_t::path_t::path_t(const xpath_t& path_expr)
|
||||
{
|
||||
ptr_op_t op = path_expr.ptr;
|
||||
|
||||
while (true) {
|
||||
switch (op->kind) {
|
||||
case op_t::O_FIND:
|
||||
case op_t::O_RFIND:
|
||||
case op_t::O_PRED:
|
||||
break;
|
||||
|
||||
case op_t::NODE_ID:
|
||||
case op_t::NODE_NAME:
|
||||
case op_t::ATTR_ID:
|
||||
case op_t::ATTR_NAME:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw_(std::logic_error, "XPath expression is not strictly a path selection");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void xpath_t::path_t::check_element(node_t& start,
|
||||
const element_iterator& element,
|
||||
scope_t * scope,
|
||||
const visitor_t& func)
|
||||
{
|
||||
if (! element->predicate || element->predicate(start, scope)) {
|
||||
element_iterator next_element = next(element);
|
||||
if (next_element == elements.end())
|
||||
func(start);
|
||||
else
|
||||
walk_elements(start, next_element, scope, func);
|
||||
}
|
||||
}
|
||||
|
||||
void xpath_t::path_t::walk_elements(node_t& start,
|
||||
const element_iterator& element,
|
||||
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)) {
|
||||
case document_t::CURRENT:
|
||||
check_element(start, element, scope, func);
|
||||
break;
|
||||
|
||||
case document_t::PARENT:
|
||||
if (optional<parent_node_t&> parent = start.parent())
|
||||
check_element(*parent, element, scope, func);
|
||||
else
|
||||
throw_(std::logic_error, "Attempt to access parent of root node");
|
||||
break;
|
||||
|
||||
case document_t::ROOT:
|
||||
check_element(start.document(), element, scope, func);
|
||||
break;
|
||||
|
||||
case document_t::ALL:
|
||||
if (! start.is_parent_node())
|
||||
throw_(compile_error, "Referencing child nodes from a non-parent value");
|
||||
|
||||
foreach (node_t * node, start.as_parent_node())
|
||||
check_element(*node, element, scope, func);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (start.is_parent_node()) {
|
||||
bool have_name_id = element->ident.type() == typeid(node_t::nameid_t);
|
||||
|
||||
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, func);
|
||||
}
|
||||
}
|
||||
|
||||
if (element->recurse && start.is_parent_node())
|
||||
foreach (node_t * child, start.as_parent_node())
|
||||
walk_elements(*child, element, scope, func);
|
||||
}
|
||||
|
||||
} // namespace xml
|
||||
} // namespace ledger
|
||||
|
|
|
|||
79
src/xpath.h
79
src/xpath.h
|
|
@ -212,6 +212,55 @@ private:
|
|||
};
|
||||
|
||||
public:
|
||||
class path_t : public noncopyable
|
||||
{
|
||||
public: // jww (2007-05-14): for testing
|
||||
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 node_appender_t {
|
||||
value_t::sequence_t& sequence;
|
||||
node_appender_t(value_t::sequence_t& _sequence)
|
||||
: sequence(_sequence) {}
|
||||
void operator()(node_t& node) {
|
||||
sequence.push_back(&node);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
path_t(const xpath_t& path_expr);
|
||||
|
||||
void find_all(value_t::sequence_t& result,
|
||||
node_t& start, scope_t * scope) {
|
||||
visit(start, scope, node_appender_t(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);
|
||||
}
|
||||
|
||||
private:
|
||||
void walk_elements(node_t& start, const element_iterator& element,
|
||||
scope_t * scope, const function<void (node_t&)>& func);
|
||||
void check_element(node_t& start, const element_iterator& element,
|
||||
scope_t * scope, const function<void (node_t&)>& func);
|
||||
};
|
||||
|
||||
struct op_t : public noncopyable
|
||||
{
|
||||
enum kind_t {
|
||||
|
|
@ -366,6 +415,22 @@ public:
|
|||
data = val;
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool is_path() const {
|
||||
return kind == PATH;
|
||||
}
|
||||
path_t& as_path() {
|
||||
assert(kind == PATH);
|
||||
return boost::get<path_t>(data);
|
||||
}
|
||||
const path_t& as_path() const {
|
||||
return const_cast<op_t *>(this)->as_path();
|
||||
}
|
||||
void set_path(const path_t& val) {
|
||||
data = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
ptr_op_t& as_op() {
|
||||
assert(kind > TERMINALS);
|
||||
return boost::get<ptr_op_t>(data);
|
||||
|
|
@ -437,6 +502,20 @@ public:
|
|||
void dump(std::ostream& out, const int depth) const;
|
||||
};
|
||||
|
||||
class op_predicate
|
||||
{
|
||||
ptr_op_t op;
|
||||
|
||||
public:
|
||||
op_predicate(ptr_op_t _op) : op(_op) {}
|
||||
|
||||
bool operator()(node_t& node, scope_t * scope) {
|
||||
value_t context_node(&node);
|
||||
xpath_t result(op->compile(context_node, scope, true));
|
||||
return result.ptr->as_value().to_boolean();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
ptr_op_t ptr;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue