diff options
-rw-r--r-- | src/main.cc | 14 | ||||
-rw-r--r-- | src/value.cc | 10 | ||||
-rw-r--r-- | src/value.h | 19 | ||||
-rw-r--r-- | src/xpath.cc | 141 | ||||
-rw-r--r-- | src/xpath.h | 104 |
5 files changed, 160 insertions, 128 deletions
diff --git a/src/main.cc b/src/main.cc index db34f183..fbda5c3d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -268,17 +268,11 @@ static int read_and_report(ledger::report_t * report, int argc, char * argv[], xpath.print(*out, xml_document); *out << std::endl; - value_t result = xpath.calc(xml_document, report); - - if (result.is_sequence()) { - foreach (const value_t& value, result.as_sequence()) { - if (value.is_xml_node()) { - value.as_xml_node()->print(std::cout); - std::cout << std::endl; - } + foreach (const value_t& value, xpath.find_all(xml_document, report)) { + if (value.is_xml_node()) { + value.as_xml_node()->print(std::cout); + std::cout << std::endl; } - } else { - std::cout << result << std::endl; } return 0; } diff --git a/src/value.cc b/src/value.cc index dd2b3a11..949ae696 100644 --- a/src/value.cc +++ b/src/value.cc @@ -82,16 +82,6 @@ void value_t::shutdown() false_value = intrusive_ptr<storage_t>(); } -value_t& value_t::operator=(const value_t& val) -{ - if (this == &val || storage == val.storage) - return *this; - - storage = val.storage; - - return *this; -} - value_t::operator bool() const { switch (type()) { diff --git a/src/value.h b/src/value.h index f8674864..148d5bd6 100644 --- a/src/value.h +++ b/src/value.h @@ -229,7 +229,12 @@ public: TRACE_DTOR(value_t); } - value_t& operator=(const value_t& val); + value_t& operator=(const value_t& val) { + if (this == &val || storage == val.storage) + return *this; + storage = val.storage; + return *this; + } /** * _dup() makes a private copy of the current value so that it can @@ -427,6 +432,11 @@ public: assert(is_xml_node()); return *(const xml::node_t **) storage->data; } + template <typename T> + T * as_xml_node() const { + assert(is_xml_node()); + return *(T **) storage->data; + } void set_xml_node(xml::node_t * val) { set_type(XML_NODE); *(xml::node_t **) storage->data = val; @@ -592,6 +602,13 @@ public: friend std::ostream& operator<<(std::ostream& out, const value_t& val); }; +template <> +inline const xml::node_t * value_t::as_xml_node() const { + assert(is_xml_node()); + assert(! is_type(CONST_XML_NODE)); + return *(const xml::node_t **) storage->data; +} + std::ostream& operator<<(std::ostream& out, const value_t& val); DECLARE_EXCEPTION(value_error); diff --git a/src/xpath.cc b/src/xpath.cc index 3799e260..d56aa2f1 100644 --- a/src/xpath.cc +++ b/src/xpath.cc @@ -1484,7 +1484,10 @@ xpath_t::op_t::compile(const node_t& context, scope_t * scope, bool resolve) case O_RFIND: case NODE_ID: case NODE_NAME: - return wrap_value(path_t(ptr_op_t(this)).find_all(context, scope)); + if (resolve) + return wrap_value(path_t(ptr_op_t(this)).find_all(context, scope)); + else + return this; case O_PRED: assert(false); // this should never occur by itself @@ -1981,13 +1984,13 @@ void xpath_t::op_t::dump(std::ostream& out, const int depth) const } } -template <typename NodeType, typename FuncType> -void xpath_t::path_t::check_element(NodeType& start, - const ptr_op_t& element, - scope_t * scope, - std::size_t index, - std::size_t size, - const FuncType& func) +template <typename NodeType> +void xpath_t::path_t::check_element(NodeType& start, + const ptr_op_t& element, + scope_t * scope, + std::size_t index, + std::size_t size, + const visitor_t& func) { if (element->kind > op_t::TERMINALS && element->left()->kind == op_t::O_PRED) { @@ -1996,40 +1999,49 @@ void xpath_t::path_t::check_element(NodeType& start, return; } - if (element->kind < op_t::TERMINALS) - func(start); - else - walk_elements<NodeType, FuncType> - (start, element->right(), element->kind == op_t::O_RFIND, scope, func); + if (element->kind < op_t::TERMINALS) { + value_t temp(&start); + assert(temp.is_xml_node()); + func(temp); + } else { + walk_elements<NodeType>(start, element->right(), + element->kind == op_t::O_RFIND, scope, func); + } } -template <typename NodeType, typename FuncType> -void xpath_t::path_t::walk_elements(NodeType& start, - const ptr_op_t& element, - const bool recurse, - scope_t * scope, - const FuncType& func) +template <typename NodeType> +void xpath_t::path_t::walk_elements(NodeType& start, + const ptr_op_t& element, + const bool recurse, + scope_t * scope, + const visitor_t& func) { - ptr_op_t name(element->kind < op_t::TERMINALS ? element : element->left()); - if (name->kind == op_t::O_PRED) - name = name->left(); + ptr_op_t name(element); + + if (name->kind > op_t::TERMINALS && + (name->kind == op_t::O_FIND || name->kind == op_t::O_RFIND)) { + name = 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); + check_element<NodeType>(start, element, scope, 0, 1, func); break; case document_t::PARENT: if (optional<parent_node_t&> parent = start.parent()) - check_element(*parent, element, scope, 0, 1, func); + check_element<NodeType>(*parent, element, scope, 0, 1, func); else throw_(std::logic_error, "Attempt to access parent of root node"); break; case document_t::ROOT: - check_element(start.document(), element, scope, 0, 1, func); + check_element<NodeType>(start.document(), element, scope, 0, 1, func); break; case document_t::ALL: { @@ -2038,8 +2050,8 @@ void xpath_t::path_t::walk_elements(NodeType& start, std::size_t index = 0; std::size_t size = start.as_parent_node().size(); - foreach (node_t * node, start.as_parent_node()) - check_element(*node, element, scope, index++, size, func); + foreach (NodeType * node, start.as_parent_node()) + check_element<NodeType>(*node, element, scope, index++, size, func); break; } @@ -2054,27 +2066,63 @@ void xpath_t::path_t::walk_elements(NodeType& start, std::size_t index = 0; std::size_t size = start.as_parent_node().size(); - foreach (node_t * child, start.as_parent_node()) { + foreach (NodeType * 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); + check_element<NodeType>(*child, element, scope, index++, size, func); else if (recurse) - walk_elements(*child, element, recurse, scope, func); + walk_elements<NodeType>(*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"); + default: { + xpath_t final(name->compile(start, scope, true)); + + if (final.ptr->is_value()) { + value_t& result(final.ptr->as_value()); + + if (result.is_xml_node()) { + check_element<NodeType>(*result.template as_xml_node<NodeType>(), + element, scope, 0, 1, func); + } + else if (result.is_sequence()) { + std::size_t index = 0; + std::size_t size = start.as_parent_node().size(); + + foreach (const value_t& value, result.as_sequence()) { + if (value.is_xml_node()) { + check_element<NodeType>(*value.template as_xml_node<NodeType>(), + element, scope, index++, size, func); + + // Apply to every child if this part is recursive + if (recurse) + walk_elements<NodeType>(*value.template as_xml_node<NodeType>(), + element, recurse, scope, func); + } else { + if (element->kind > op_t::TERMINALS) + throw_(compile_error, + "Non-final expression in XPath selection returns non-node"); + func(value); + } + } + } + else { + if (element->kind > op_t::TERMINALS) + throw_(compile_error, + "Non-final expression in XPath selection returns non-node"); + func(result); + } + } else { + throw_(compile_error, "Expression in XPath selection is invalid"); + } break; } + } } template -void xpath_t::path_t::walk_elements<node_t, xpath_t::path_t::visitor_t> +void xpath_t::path_t::walk_elements<node_t> (node_t& start, const ptr_op_t& element, const bool recurse, @@ -2082,30 +2130,13 @@ void xpath_t::path_t::walk_elements<node_t, xpath_t::path_t::visitor_t> const visitor_t& func); template -void xpath_t::path_t::walk_elements<const node_t, xpath_t::path_t::const_visitor_t> - (const node_t& start, - const ptr_op_t& element, - const bool recurse, - scope_t * scope, - const const_visitor_t& func); - -template -void xpath_t::path_t::check_element<node_t, xpath_t::path_t::visitor_t> - (node_t& start, +void xpath_t::path_t::check_element<const node_t> + (const node_t& start, const ptr_op_t& element, scope_t * scope, std::size_t index, std::size_t size, const visitor_t& func); -template -void xpath_t::path_t::check_element<const node_t, xpath_t::path_t::const_visitor_t> - (const node_t& start, - const ptr_op_t& element, - scope_t * scope, - std::size_t index, - std::size_t size, - const const_visitor_t& func); - } // namespace xml } // namespace ledger diff --git a/src/xpath.h b/src/xpath.h index 7b358976..09ebc1ae 100644 --- a/src/xpath.h +++ b/src/xpath.h @@ -216,45 +216,36 @@ private: public: class path_t { - typedef function<void (node_t&)> visitor_t; - typedef function<void (const node_t&)> const_visitor_t; - + public: + typedef function<void (const value_t&)> visitor_t; typedef function<bool (const node_t&, scope_t *)> predicate_t; - struct value_node_appender_t { - value_t::sequence_t& sequence; - value_node_appender_t(value_t::sequence_t& _sequence) - : sequence(_sequence) {} - void operator()(node_t& node) { - sequence.push_back(&node); - } - }; - - struct const_value_node_appender_t { + private: + struct value_appender_t { value_t::sequence_t& sequence; - const_value_node_appender_t(value_t::sequence_t& _sequence) + value_appender_t(value_t::sequence_t& _sequence) : sequence(_sequence) {} - void operator()(const node_t& node) { - sequence.push_back(&node); + void operator()(const value_t& val) { + sequence.push_back(val); } }; ptr_op_t path_expr; - template <typename NodeType, typename FuncType> - void walk_elements(NodeType& start, - const ptr_op_t& element, - const bool recurse, - scope_t * scope, - const FuncType& func); - - template <typename NodeType, typename FuncType> - void check_element(NodeType& start, - const ptr_op_t& element, - scope_t * scope, - std::size_t index, - std::size_t size, - const FuncType& func); + template <typename NodeType> + void walk_elements(NodeType& start, + const ptr_op_t& element, + const bool recurse, + scope_t * scope, + const visitor_t& func); + + template <typename NodeType> + void check_element(NodeType& start, + const ptr_op_t& element, + scope_t * scope, + std::size_t index, + std::size_t size, + const visitor_t& func); public: path_t(const xpath_t& xpath) : path_expr(xpath.ptr) {} @@ -262,53 +253,53 @@ public: 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_appender_t(result.as_sequence_lval())); return result; } value_t find_all(const node_t& start, scope_t * scope) { value_t result = value_t::sequence_t(); - visit(start, scope, - const_value_node_appender_t(result.as_sequence_lval())); + visit(start, scope, value_appender_t(result.as_sequence_lval())); return result; } void visit(node_t& start, scope_t * scope, const visitor_t& func) { if (path_expr) - walk_elements<node_t, visitor_t> - (start, path_expr, false, scope, func); + walk_elements<node_t>(start, path_expr, false, scope, func); } - void visit(const node_t& start, scope_t * scope, - const const_visitor_t& func) { + void visit(const node_t& start, scope_t * scope, const visitor_t& func) { if (path_expr) - walk_elements<const node_t, const_visitor_t> - (start, path_expr, false, scope, func); + walk_elements<const node_t>(start, path_expr, false, scope, func); } }; + template <typename NodeType> class path_iterator_t { + typedef NodeType * pointer; + typedef NodeType& reference; + path_t path; - node_t& start; + reference start; scope_t * scope; - mutable std::vector<node_t *> sequence; + mutable value_t::sequence_t sequence; mutable bool searched; struct node_appender_t { - std::vector<node_t *>& sequence; - node_appender_t(std::vector<node_t *>& _sequence) + value_t::sequence_t& sequence; + node_appender_t(value_t::sequence_t& _sequence) : sequence(_sequence) {} - void operator()(node_t& node) { - sequence.push_back(&node); + void operator()(const value_t& node) { + sequence.push_back(node); } }; public: - typedef std::vector<node_t *>::iterator iterator; - typedef std::vector<node_t *>::const_iterator const_iterator; + typedef value_t::sequence_t::iterator iterator; + typedef value_t::sequence_t::const_iterator const_iterator; path_iterator_t(const xpath_t& path_expr, - node_t& _start, scope_t * _scope) + reference _start, scope_t * _scope) : path(path_expr), start(_start), scope(_scope), searched(false) { } @@ -753,18 +744,27 @@ public: return xpath_t(_expr).calc(context, scope); } - path_iterator_t find_all(node_t& start, scope_t * scope) { - return path_iterator_t(*this, start, scope); + path_iterator_t<node_t> + find_all(node_t& start, scope_t * scope) { + return path_iterator_t<node_t>(*this, start, scope); + } + path_iterator_t<const node_t> + find_all(const node_t& start, scope_t * scope) { + return path_iterator_t<const node_t>(*this, start, scope); } - void visit(node_t& start, scope_t * scope, - const function<void (node_t&)>& func) { + void visit(node_t& start, scope_t * scope, const path_t::visitor_t& func) { + path_t(*this).visit(start, scope, func); + } + void visit(const node_t& start, scope_t * scope, const + path_t::visitor_t& func) { path_t(*this).visit(start, scope, func); } void print(std::ostream& out, xml::document_t& document) const { print(out, document, true, NULL, NULL, NULL); } + void dump(std::ostream& out) const { if (ptr) ptr->dump(out, 0); |