summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main.cc14
-rw-r--r--src/value.cc10
-rw-r--r--src/value.h19
-rw-r--r--src/xpath.cc141
-rw-r--r--src/xpath.h104
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);