diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cc | 22 | ||||
-rw-r--r-- | src/value.cc | 9 | ||||
-rw-r--r-- | src/xpath.cc | 138 | ||||
-rw-r--r-- | src/xpath.h | 79 |
4 files changed, 218 insertions, 30 deletions
diff --git a/src/main.cc b/src/main.cc index 7aea3c2c..669afefb 100644 --- a/src/main.cc +++ b/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; } diff --git a/src/value.cc b/src/value.cc index 40167af3..3965dfbd 100644 --- a/src/value.cc +++ b/src/value.cc @@ -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 diff --git a/src/xpath.cc b/src/xpath.cc index 702aaeae..6efa214a 100644 --- a/src/xpath.cc +++ b/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 diff --git a/src/xpath.h b/src/xpath.h index ccec7b0a..f17d3ee8 100644 --- a/src/xpath.h +++ b/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; |