summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.cc22
-rw-r--r--src/value.cc9
-rw-r--r--src/xpath.cc138
-rw-r--r--src/xpath.h79
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;