In XPath numbers do not have leading +, so, while '-1.5' converts to -1.5,

'+1.5' converts to NaN.  Weird and counter-intuitive perhaps, but it's there
in the spec.

Sort now sets context node appropriately, so current() works in sorting 
expressions.
This commit is contained in:
jez 2008-11-03 22:19:59 +00:00
commit f74170e268
3 changed files with 81 additions and 9 deletions

View file

@ -413,7 +413,14 @@ template<class string_type, class string_adaptor>
double stringAsNumber(const string_type& str)
{
try {
return boost::lexical_cast<double>(Arabica::text::normalize_whitespace<string_type, string_adaptor>(str));
static string_type PLUS = string_adaptor::construct_from_utf8("+");
string_type n_str = Arabica::text::normalize_whitespace<string_type, string_adaptor>(str);
// '+1.5' is not a number according to XPath spec, counter intuitive as that is
if(string_adaptor::find(n_str, PLUS) == 0)
return NaN;
return boost::lexical_cast<double>(n_str);
} // try
catch(const boost::bad_lexical_cast&) {
return NaN;

View file

@ -74,8 +74,8 @@ private:
typedef bool(Sort::*sortFn)(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2) const;
bool numberAscending(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2) const
{
double v1 = select_->evaluateAsNumber(n1, context_->xpathContext());
double v2 = select_->evaluateAsNumber(n2, context_->xpathContext());
double v1 = grabAsNumber(n1);
double v2 = grabAsNumber(n2);
bool nan1 = Arabica::XPath::isNaN(v1);
bool nan2 = Arabica::XPath::isNaN(v2);
@ -92,8 +92,8 @@ private:
} // numberAscending
bool numberDescending(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2) const
{
double v1 = select_->evaluateAsNumber(n1, context_->xpathContext());
double v2 = select_->evaluateAsNumber(n2, context_->xpathContext());
double v1 = grabAsNumber(n1);
double v2 = grabAsNumber(n2);
bool nan1 = Arabica::XPath::isNaN(v1);
bool nan2 = Arabica::XPath::isNaN(v2);
@ -110,8 +110,8 @@ private:
} // numberDescending
bool stringAscending(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2) const
{
std::string v1 = select_->evaluateAsString(n1, context_->xpathContext());
std::string v2 = select_->evaluateAsString(n2, context_->xpathContext());
std::string v1 = grabAsString(n1);
std::string v2 = grabAsString(n2);
if((v1 == v2) && (sub_sort_))
return (*sub_sort_)(n1, n2);
@ -120,8 +120,8 @@ private:
} // stringAscending
bool stringDescending(const DOM::Node<std::string>& n1, const DOM::Node<std::string>& n2) const
{
std::string v1 = select_->evaluateAsString(n1, context_->xpathContext());
std::string v2 = select_->evaluateAsString(n2, context_->xpathContext());
std::string v1 = grabAsString(n1);
std::string v2 = grabAsString(n2);
if((v1 == v2) && (sub_sort_))
return (*sub_sort_)(n1, n2);
@ -129,6 +129,17 @@ private:
return v1 > v2;
} // stringAscending
std::string grabAsString(const DOM::Node<std::string>& n) const
{
context_->setPosition(n, 1);
return select_->evaluateAsString(n, context_->xpathContext());
} // grabAsString
double grabAsNumber(const DOM::Node<std::string>& n) const
{
context_->setPosition(n, 1);
return select_->evaluateAsNumber(n, context_->xpathContext());
} // grabAsString
Arabica::XPath::XPathExpressionPtr<std::string> select_;
Arabica::XPath::XPathExpressionPtr<std::string> lang_;
Arabica::XPath::XPathExpressionPtr<std::string> datatype_;

View file

@ -1116,6 +1116,54 @@ public:
assertTrue(isNaN(result.asNumber()));
} // testNumberFn7
void testNumberFn8()
{
using namespace Arabica::XPath;
XPathValue<string_type, string_adaptor> result = parser.evaluate_expr(SA::construct_from_utf8("number('-1.5')"), document_);
assertValuesEqual(NUMBER, result.type());
assertDoublesEqual(-1.5, result.asNumber(), 0.0);
} // testNumberFn8
void testNumberFn9()
{
using namespace Arabica::XPath;
XPathValue<string_type, string_adaptor> result = parser.evaluate_expr(SA::construct_from_utf8("number('+1.5')"), document_);
assertValuesEqual(NUMBER, result.type());
assertTrue(isNaN(result.asNumber()));
} // testNumberFn9
void testNumberFn10()
{
using namespace Arabica::XPath;
XPathValue<string_type, string_adaptor> result = parser.evaluate_expr(SA::construct_from_utf8("number('-1.5 ')"), document_);
assertValuesEqual(NUMBER, result.type());
assertDoublesEqual(-1.5, result.asNumber(), 0.0);
} // testNumberFn10
void testNumberFn11()
{
using namespace Arabica::XPath;
XPathValue<string_type, string_adaptor> result = parser.evaluate_expr(SA::construct_from_utf8("number('+1.5')"), document_);
assertValuesEqual(NUMBER, result.type());
assertTrue(isNaN(result.asNumber()));
} // testNumberFn11
void testNumberFn12()
{
using namespace Arabica::XPath;
XPathValue<string_type, string_adaptor> result = parser.evaluate_expr(SA::construct_from_utf8("number(' -1.5 ')"), document_);
assertValuesEqual(NUMBER, result.type());
assertDoublesEqual(-1.5, result.asNumber(), 0.0);
} // testNumberFn12
void testNumberFn13()
{
using namespace Arabica::XPath;
XPathValue<string_type, string_adaptor> result = parser.evaluate_expr(SA::construct_from_utf8("number(' +1.5 ')"), document_);
assertValuesEqual(NUMBER, result.type());
assertTrue(isNaN(result.asNumber()));
} // testNumberFn13
void testFloorFn1()
{
using namespace Arabica::XPath;
@ -2575,6 +2623,12 @@ TestSuite* ExecuteTest_suite()
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn5", &ExecuteTest<string_type, string_adaptor>::testNumberFn5));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn6", &ExecuteTest<string_type, string_adaptor>::testNumberFn6));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn7", &ExecuteTest<string_type, string_adaptor>::testNumberFn7));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn8", &ExecuteTest<string_type, string_adaptor>::testNumberFn8));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn9", &ExecuteTest<string_type, string_adaptor>::testNumberFn9));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn10", &ExecuteTest<string_type, string_adaptor>::testNumberFn10));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn11", &ExecuteTest<string_type, string_adaptor>::testNumberFn11));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn12", &ExecuteTest<string_type, string_adaptor>::testNumberFn12));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testNumberFn13", &ExecuteTest<string_type, string_adaptor>::testNumberFn13));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testFloorFn1", &ExecuteTest<string_type, string_adaptor>::testFloorFn1));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testFloorFn2", &ExecuteTest<string_type, string_adaptor>::testFloorFn2));
suiteOfTests->addTest(new TestCaller<ExecuteTest<string_type, string_adaptor> >("testFloorFn3", &ExecuteTest<string_type, string_adaptor>::testFloorFn3));