From 31c4cb2d8bcefcdcbbb1befcba7fdc6c92f5070a Mon Sep 17 00:00:00 2001 From: "arseny.kapoulkine" Date: Mon, 17 May 2010 06:54:06 +0000 Subject: XPath refactoring (ast_filter/filter_posinv/predicates use the same function, removed greater* specializations for compare_rel, starts_with is used more extensively, const-correctness fixes) git-svn-id: http://pugixml.googlecode.com/svn/trunk@425 99668b35-9821-0410-8761-19e4c4f06640 --- src/pugixpath.cpp | 113 ++++++++++------------------------------- tests/test_xpath_functions.cpp | 5 ++ 2 files changed, 32 insertions(+), 86 deletions(-) diff --git a/src/pugixpath.cpp b/src/pugixpath.cpp index 0059f78..60f65b8 100644 --- a/src/pugixpath.cpp +++ b/src/pugixpath.cpp @@ -93,9 +93,15 @@ namespace #endif } - bool starts_with(const string_t& s, const char_t* pattern) + bool starts_with(const char_t* string, const char_t* pattern) { - return s.compare(0, impl::strlen(pattern), pattern) == 0; + while (*pattern && *string == *pattern) + { + string++; + pattern++; + } + + return *pattern == 0; } const char_t* find_char(const char_t* s, char_t c) @@ -513,14 +519,6 @@ namespace } }; - template struct greater - { - bool operator()(const T& lhs, const T& rhs) const - { - return lhs > rhs; - } - }; - template struct less { bool operator()(const T& lhs, const T& rhs) const @@ -529,14 +527,6 @@ namespace } }; - template struct greater_equal - { - bool operator()(const T& lhs, const T& rhs) const - { - return lhs >= rhs; - } - }; - template struct less_equal { bool operator()(const T& lhs, const T& rhs) const @@ -1308,7 +1298,7 @@ namespace pugi template struct compare_eq { - static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, xpath_context& c) + static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c) { if (lhs->rettype() != xpath_type_node_set && rhs->rettype() != xpath_type_node_set) { @@ -1403,7 +1393,7 @@ namespace pugi template struct compare_rel { - static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, xpath_context& c) + static bool run(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c) { if (lhs->rettype() != xpath_type_node_set && rhs->rettype() != xpath_type_node_set) return Cdouble()(lhs->eval_number(c), rhs->eval_number(c)); @@ -1504,7 +1494,7 @@ namespace pugi // There are no attribute nodes corresponding to attributes that declare namespaces // That is, "xmlns:..." or "xmlns" - if (impl::strequalrange(a.name(), PUGIXML_TEXT("xmlns"), 5) && (a.name()[5] == 0 || a.name()[5] == ':')) return; + if (starts_with(a.name(), PUGIXML_TEXT("xmlns")) && (a.name()[5] == 0 || a.name()[5] == ':')) return; switch (m_test) { @@ -1518,7 +1508,7 @@ namespace pugi break; case nodetest_all_in_namespace: - if (impl::strequalrange(a.name(), m_contents, impl::strlen(m_contents))) + if (starts_with(a.name(), m_contents)) ns.push_back(xpath_node(a, parent)); break; @@ -1567,7 +1557,7 @@ namespace pugi break; case nodetest_all_in_namespace: - if (n.type() == node_element && impl::strequalrange(n.name(), m_contents, impl::strlen(m_contents))) + if (n.type() == node_element && starts_with(n.name(), m_contents)) ns.push_back(n); break; @@ -1791,7 +1781,7 @@ namespace pugi } } - template void step_do(xpath_node_set& ns, xpath_context& c, T v) + template void step_do(xpath_node_set& ns, const xpath_context& c, T v) { const axis_t axis = T::axis; @@ -1971,7 +1961,7 @@ namespace pugi m_right = value; } - bool eval_boolean(xpath_context& c) + bool eval_boolean(const xpath_context& c) { switch (m_type) { @@ -1993,16 +1983,16 @@ namespace pugi return compare_rel >::run(m_left, m_right, c); case ast_op_greater: - return compare_rel >::run(m_left, m_right, c); + return compare_rel >::run(m_right, m_left, c); case ast_op_less_or_equal: return compare_rel >::run(m_left, m_right, c); case ast_op_greater_or_equal: - return compare_rel >::run(m_left, m_right, c); + return compare_rel >::run(m_right, m_left, c); case ast_func_starts_with: - return starts_with(m_left->eval_string(c), m_right->eval_string(c).c_str()); + return starts_with(m_left->eval_string(c).c_str(), m_right->eval_string(c).c_str()); case ast_func_contains: { @@ -2073,7 +2063,7 @@ namespace pugi } } - double eval_number(xpath_context& c) + double eval_number(const xpath_context& c) { switch (m_type) { @@ -2171,7 +2161,7 @@ namespace pugi } } - string_t eval_string(xpath_context& c) + string_t eval_string(const xpath_context& c) { switch (m_type) { @@ -2373,7 +2363,7 @@ namespace pugi } } - xpath_node_set eval_node_set(xpath_context& c) + xpath_node_set eval_node_set(const xpath_context& c) { switch (m_type) { @@ -2393,67 +2383,18 @@ namespace pugi } case ast_filter: - { - xpath_node_set set = m_left->eval_node_set(c); - set.sort(); - - xpath_context oc = c; - - size_t i = 0; - - xpath_node_set::iterator last = set.mut_begin(); - - // remove_if... or well, sort of - for (xpath_node_set::const_iterator it = set.begin(); it != set.end(); ++it, ++i) - { - c.n = *it; - c.position = i + 1; - c.size = set.size(); - - if (m_right->rettype() == xpath_type_number) - { - if (m_right->eval_number(c) == i + 1) - *last++ = *it; - } - else if (m_right->eval_boolean(c)) - *last++ = *it; - } - - c = oc; - - set.truncate(last); - - return set; - } - case ast_filter_posinv: { xpath_node_set set = m_left->eval_node_set(c); - - xpath_context oc = c; - - size_t i = 0; - - xpath_node_set::iterator last = set.mut_begin(); - - // remove_if... or well, sort of - for (xpath_node_set::const_iterator it = set.begin(); it != set.end(); ++it, ++i) - { - c.n = *it; - c.position = i + 1; - c.size = set.size(); - - if (m_right->eval_boolean(c)) - *last++ = *it; - } - - c = oc; - - set.truncate(last); + + // either expression is a number or it contains position() call; sort by document order + if (m_type == ast_filter) set.sort(); + + apply_predicate(set, 0, m_right, c); return set; } - + case ast_func_id: return xpath_node_set(); diff --git a/tests/test_xpath_functions.cpp b/tests/test_xpath_functions.cpp index 7e98181..6713a89 100644 --- a/tests/test_xpath_functions.cpp +++ b/tests/test_xpath_functions.cpp @@ -707,4 +707,9 @@ TEST_XML_FLAGS(xpath_string_value, "pcdatafoobar") +{ + CHECK_XPATH_STRING(doc, STR("concat('a', 'b', 'c', translate(node, 'o', 'a'), 'd')"), STR("abcfaabard")); +} + #endif -- cgit v1.2.3