summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>2014-10-19 07:33:42 +0000
committerArseny Kapoulkine <arseny.kapoulkine@gmail.com>2014-10-19 07:33:42 +0000
commitf6635588758ed1b650be22903c2e2e81273e05c5 (patch)
tree636fee26ff162d178e249c779f2af8d7e668981e /src
parent72ec01c5f6d23405f30614d63fafa048279ca13d (diff)
XPath: Introduce xpath_query::evaluate_node
This method is equivalent to xml_node::select_single_node. This makes select_single_node faster in certain cases by avoiding an allocation and - more importantly - paves the way for future step optimizations. git-svn-id: https://pugixml.googlecode.com/svn/trunk@1064 99668b35-9821-0410-8761-19e4c4f06640
Diffstat (limited to 'src')
-rw-r--r--src/pugixml.cpp56
-rw-r--r--src/pugixml.hpp6
2 files changed, 45 insertions, 17 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 1d9dcfe..6f230dd 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -10581,6 +10581,25 @@ PUGI__NS_BEGIN
return impl->root->eval_string(c, sd.stack);
}
+
+ PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
+ {
+ if (!impl) return 0;
+
+ if (impl->root->rettype() != xpath_type_node_set)
+ {
+ #ifdef PUGIXML_NO_EXCEPTIONS
+ return 0;
+ #else
+ xpath_parse_result res;
+ res.error = "Expression does not evaluate to node set";
+
+ throw xpath_exception(res);
+ #endif
+ }
+
+ return impl->root;
+ }
PUGI__NS_END
namespace pugi
@@ -11082,22 +11101,9 @@ namespace pugi
PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
{
- if (!_impl) return xpath_node_set();
-
- impl::xpath_ast_node* root = static_cast<impl::xpath_query_impl*>(_impl)->root;
-
- if (root->rettype() != xpath_type_node_set)
- {
- #ifdef PUGIXML_NO_EXCEPTIONS
- return xpath_node_set();
- #else
- xpath_parse_result res;
- res.error = "Expression does not evaluate to node set";
+ impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
+ if (!root) return xpath_node_set();
- throw xpath_exception(res);
- #endif
- }
-
impl::xpath_context c(n, 1, 1);
impl::xpath_stack_data sd;
@@ -11110,6 +11116,23 @@ namespace pugi
return xpath_node_set(r.begin(), r.end(), r.type());
}
+ PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const
+ {
+ impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
+ if (!root) return xpath_node();
+
+ impl::xpath_context c(n, 1, 1);
+ impl::xpath_stack_data sd;
+
+ #ifdef PUGIXML_NO_EXCEPTIONS
+ if (setjmp(sd.error_handler)) return xpath_node();
+ #endif
+
+ impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack);
+
+ return r.first();
+ }
+
PUGI__FN const xpath_parse_result& xpath_query::result() const
{
return _result;
@@ -11137,8 +11160,7 @@ namespace pugi
PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
{
- xpath_node_set s = query.evaluate_node_set(*this);
- return s.empty() ? xpath_node() : s.first();
+ return query.evaluate_node(*this);
}
PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
diff --git a/src/pugixml.hpp b/src/pugixml.hpp
index 69b2cb2..2947bf4 100644
--- a/src/pugixml.hpp
+++ b/src/pugixml.hpp
@@ -1134,6 +1134,12 @@ namespace pugi
// If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead.
xpath_node_set evaluate_node_set(const xpath_node& n) const;
+ // Evaluate expression as node set in the specified context.
+ // Return first node in document order, or empty node if node set is empty.
+ // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
+ // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead.
+ xpath_node evaluate_node(const xpath_node& n) const;
+
// Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode)
const xpath_parse_result& result() const;