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
This commit is contained in:
parent
72ec01c5f6
commit
f663558875
3 changed files with 75 additions and 20 deletions
|
@ -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 = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
|
||||
if (!root) 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";
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -154,6 +154,9 @@ TEST_XML(xpath_api_evaluate, "<node attr='3'/>")
|
|||
|
||||
xpath_node_set ns = q.evaluate_node_set(doc);
|
||||
CHECK(ns.size() == 1 && ns[0].attribute() == doc.child(STR("node")).attribute(STR("attr")));
|
||||
|
||||
xpath_node nr = q.evaluate_node(doc);
|
||||
CHECK(nr.attribute() == doc.child(STR("node")).attribute(STR("attr")));
|
||||
}
|
||||
|
||||
TEST_XML(xpath_api_evaluate_attr, "<node attr='3'/>")
|
||||
|
@ -173,6 +176,9 @@ TEST_XML(xpath_api_evaluate_attr, "<node attr='3'/>")
|
|||
|
||||
xpath_node_set ns = q.evaluate_node_set(n);
|
||||
CHECK(ns.size() == 1 && ns[0] == n);
|
||||
|
||||
xpath_node nr = q.evaluate_node(n);
|
||||
CHECK(nr == n);
|
||||
}
|
||||
|
||||
#ifdef PUGIXML_NO_EXCEPTIONS
|
||||
|
@ -190,18 +196,20 @@ TEST_XML(xpath_api_evaluate_fail, "<node attr='3'/>")
|
|||
#endif
|
||||
|
||||
CHECK(q.evaluate_node_set(doc).empty());
|
||||
|
||||
CHECK(!q.evaluate_node(doc));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(xpath_api_evaluate_node_set_fail)
|
||||
{
|
||||
xpath_query q(STR("1"));
|
||||
|
||||
#ifdef PUGIXML_NO_EXCEPTIONS
|
||||
CHECK_XPATH_NODESET(xml_node(), STR("1"));
|
||||
CHECK(q.evaluate_node_set(xml_node()).empty());
|
||||
#else
|
||||
try
|
||||
{
|
||||
xpath_query q(STR("1"));
|
||||
|
||||
q.evaluate_node_set(xml_node());
|
||||
|
||||
CHECK_FORCE_FAIL("Expected exception");
|
||||
|
@ -212,6 +220,25 @@ TEST(xpath_api_evaluate_node_set_fail)
|
|||
#endif
|
||||
}
|
||||
|
||||
TEST(xpath_api_evaluate_node_fail)
|
||||
{
|
||||
xpath_query q(STR("1"));
|
||||
|
||||
#ifdef PUGIXML_NO_EXCEPTIONS
|
||||
CHECK(!q.evaluate_node(xml_node()));
|
||||
#else
|
||||
try
|
||||
{
|
||||
q.evaluate_node(xml_node());
|
||||
|
||||
CHECK_FORCE_FAIL("Expected exception");
|
||||
}
|
||||
catch (const xpath_exception&)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(xpath_api_evaluate_string)
|
||||
{
|
||||
xpath_query q(STR("\"0123456789\""));
|
||||
|
|
Loading…
Add table
Reference in a new issue