mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Cleanup BooleanFunctionCall and StringFunctionCall, fixes bugs in lang(), substring() and a few more.
b=104758 r=Pike sr=jag
This commit is contained in:
parent
d89447a076
commit
0a836b98e9
@ -1,4 +1,5 @@
|
||||
/*
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
@ -32,9 +33,10 @@
|
||||
/**
|
||||
* Creates a default BooleanFunctionCall, which always evaluates to False
|
||||
**/
|
||||
BooleanFunctionCall::BooleanFunctionCall(short type) : FunctionCall()
|
||||
BooleanFunctionCall::BooleanFunctionCall(BooleanFunctions aType)
|
||||
: mType(aType)
|
||||
{
|
||||
switch ( type ) {
|
||||
switch (aType) {
|
||||
case TX_BOOLEAN :
|
||||
name = XPathNames::BOOLEAN_FN;
|
||||
break;
|
||||
@ -51,7 +53,6 @@ BooleanFunctionCall::BooleanFunctionCall(short type) : FunctionCall()
|
||||
name = XPathNames::FALSE_FN;
|
||||
break;
|
||||
}
|
||||
this->type = type;
|
||||
} //-- BooleanFunctionCall
|
||||
|
||||
/**
|
||||
@ -61,49 +62,77 @@ BooleanFunctionCall::BooleanFunctionCall(short type) : FunctionCall()
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
**/
|
||||
ExprResult* BooleanFunctionCall::evaluate(Node* context, ContextState* cs) {
|
||||
ExprResult* BooleanFunctionCall::evaluate(Node* aContext, ContextState* aCs)
|
||||
{
|
||||
ListIterator iter(¶ms);
|
||||
|
||||
MBool result = MB_FALSE;
|
||||
ListIterator* iter = params.iterator();
|
||||
Expr* param = 0;
|
||||
String err;
|
||||
switch (mType) {
|
||||
case TX_BOOLEAN:
|
||||
{
|
||||
if (!requireParams(1, 1, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
|
||||
switch ( type ) {
|
||||
case TX_BOOLEAN :
|
||||
if ( requireParams(1,1,cs) ) {
|
||||
param = (Expr*)iter->next();
|
||||
ExprResult* exprResult = param->evaluate(context, cs);
|
||||
result = exprResult->booleanValue();
|
||||
delete exprResult;
|
||||
}
|
||||
break;
|
||||
return new BooleanResult(evaluateToBoolean((Expr*)iter.next(),
|
||||
aContext,
|
||||
aCs));
|
||||
}
|
||||
case TX_LANG:
|
||||
if ( requireParams(1,1,cs) ) {
|
||||
String arg1, lang;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg1);
|
||||
((Element*)context)->getAttr(txXMLAtoms::lang,
|
||||
kNameSpaceID_XML, lang);
|
||||
arg1.toUpperCase(); // case-insensitive comparison
|
||||
lang.toUpperCase();
|
||||
result = (MBool)(lang.indexOf(arg1) == 0);
|
||||
}
|
||||
break;
|
||||
case TX_NOT :
|
||||
if ( requireParams(1,1,cs) ) {
|
||||
param = (Expr*)iter->next();
|
||||
ExprResult* exprResult = param->evaluate(context, cs);
|
||||
result = (MBool)(!exprResult->booleanValue());
|
||||
delete exprResult;
|
||||
}
|
||||
break;
|
||||
case TX_TRUE :
|
||||
result = MB_TRUE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
delete iter;
|
||||
return new BooleanResult(result);
|
||||
} //-- evaluate
|
||||
{
|
||||
if (!requireParams(1, 1, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String lang;
|
||||
Node* node = aContext;
|
||||
while (node) {
|
||||
if (node->getNodeType() == Node::ELEMENT_NODE) {
|
||||
Element* elem = (Element*)node;
|
||||
if (elem->getAttr(txXMLAtoms::lang,
|
||||
kNameSpaceID_XML, lang))
|
||||
break;
|
||||
}
|
||||
node = node->getParentNode();
|
||||
}
|
||||
|
||||
MBool result = MB_FALSE;
|
||||
if (node) {
|
||||
String arg;
|
||||
evaluateToString((Expr*)iter.next(),aContext, aCs, arg);
|
||||
arg.toUpperCase(); // case-insensitive comparison
|
||||
lang.toUpperCase();
|
||||
result = lang.indexOf(arg) == 0 &&
|
||||
(lang.length() == arg.length() ||
|
||||
lang.charAt(arg.length()) == '-');
|
||||
}
|
||||
|
||||
return new BooleanResult(result);
|
||||
}
|
||||
case TX_NOT:
|
||||
{
|
||||
if (!requireParams(1, 1, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
return new BooleanResult(!evaluateToBoolean((Expr*)iter.next(),
|
||||
aContext,
|
||||
aCs));
|
||||
}
|
||||
case TX_TRUE:
|
||||
{
|
||||
if (!requireParams(0, 0, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
return new BooleanResult(MB_TRUE);
|
||||
}
|
||||
case TX_FALSE:
|
||||
{
|
||||
if (!requireParams(0, 0, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
return new BooleanResult(MB_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
String err("Internal error");
|
||||
aCs->recieveError(err);
|
||||
return new StringResult("error");
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
@ -188,20 +189,25 @@ protected:
|
||||
FunctionCall();
|
||||
FunctionCall(const String& name);
|
||||
|
||||
/**
|
||||
* Evaluates the given Expression and converts it's result to a String.
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a String.
|
||||
* The value is appended to the given destination String
|
||||
**/
|
||||
void evaluateToString
|
||||
(Expr* expr, Node* context, ContextState* cs, String& dest);
|
||||
|
||||
/**
|
||||
* Evaluates the given Expression and converts it's result to a number.
|
||||
**/
|
||||
double evaluateToNumber(Expr* expr, Node* context, ContextState* cs);
|
||||
*/
|
||||
void evaluateToString(Expr* aExpr, Node* aContext,
|
||||
ContextState* aCs, String& aDest);
|
||||
|
||||
/*
|
||||
* Evaluates the given Expression and converts it's result to a NodeSet.
|
||||
* Evaluates the given Expression and converts its result to a number.
|
||||
*/
|
||||
double evaluateToNumber(Expr* aExpr, Node* aContext, ContextState* aCs);
|
||||
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a boolean.
|
||||
*/
|
||||
MBool evaluateToBoolean(Expr* aExpr, Node* aContext, ContextState* aCs);
|
||||
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a NodeSet.
|
||||
* If the result is not a NodeSet NULL is returned.
|
||||
*/
|
||||
NodeSet* evaluateToNodeSet(Expr* aExpr, Node* aContext, ContextState* aCs);
|
||||
|
@ -110,34 +110,57 @@ MBool FunctionCall::matches(Node* node, Node* context, ContextState* cs)
|
||||
return result;
|
||||
} //-- matches
|
||||
|
||||
/**
|
||||
* Evaluates the given Expression and converts it's result to a String.
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a String.
|
||||
* The value is appended to the given destination String
|
||||
**/
|
||||
void FunctionCall::evaluateToString(Expr* expr, Node* context,
|
||||
ContextState* cs, String& dest)
|
||||
*/
|
||||
void FunctionCall::evaluateToString(Expr* aExpr,
|
||||
Node* aContext,
|
||||
ContextState* aCs,
|
||||
String& aDest)
|
||||
{
|
||||
if (!expr)
|
||||
NS_ASSERTION(aExpr, "missing expression");
|
||||
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
|
||||
if (!exprResult)
|
||||
return;
|
||||
ExprResult* exprResult = expr->evaluate(context, cs);
|
||||
exprResult->stringValue(dest);
|
||||
delete exprResult;
|
||||
} //-- evaluateToString
|
||||
|
||||
/**
|
||||
* Evaluates the given Expression and converts it's result to a number.
|
||||
**/
|
||||
double FunctionCall::evaluateToNumber(Expr* expr, Node* context,
|
||||
ContextState* cs)
|
||||
exprResult->stringValue(aDest);
|
||||
delete exprResult;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a number.
|
||||
*/
|
||||
double FunctionCall::evaluateToNumber(Expr* aExpr,
|
||||
Node* aContext,
|
||||
ContextState* aCs)
|
||||
{
|
||||
double result = Double::NaN;
|
||||
if (!expr)
|
||||
return result;
|
||||
ExprResult* exprResult = expr->evaluate(context, cs);
|
||||
result = exprResult->numberValue();
|
||||
NS_ASSERTION(aExpr, "missing expression");
|
||||
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
|
||||
if (!exprResult)
|
||||
return Double::NaN;
|
||||
|
||||
double result = exprResult->numberValue();
|
||||
delete exprResult;
|
||||
return result;
|
||||
} //-- evaluateToNumber
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a boolean.
|
||||
*/
|
||||
MBool FunctionCall::evaluateToBoolean(Expr* aExpr,
|
||||
Node* aContext,
|
||||
ContextState* aCs)
|
||||
{
|
||||
NS_ASSERTION(aExpr, "missing expression");
|
||||
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
|
||||
if (!exprResult)
|
||||
return MB_FALSE;
|
||||
|
||||
MBool result = exprResult->booleanValue();
|
||||
delete exprResult;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluates the given Expression and converts its result to a NodeSet.
|
||||
@ -148,7 +171,6 @@ NodeSet* FunctionCall::evaluateToNodeSet(Expr* aExpr,
|
||||
ContextState* aCs)
|
||||
{
|
||||
NS_ASSERTION(aExpr, "Missing expression to evaluate");
|
||||
|
||||
ExprResult* exprResult = aExpr->evaluate(aContext, aCs);
|
||||
if (!exprResult)
|
||||
return 0;
|
||||
|
@ -112,12 +112,18 @@ class BooleanFunctionCall : public FunctionCall {
|
||||
|
||||
public:
|
||||
|
||||
enum booleanFunctions { TX_BOOLEAN = 1, TX_FALSE, TX_LANG, TX_NOT, TX_TRUE };
|
||||
enum BooleanFunctions {
|
||||
TX_BOOLEAN, // boolean()
|
||||
TX_FALSE, // false()
|
||||
TX_LANG, // lang()
|
||||
TX_NOT, // not()
|
||||
TX_TRUE // true()
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a BooleanFunctionCall of the given type
|
||||
**/
|
||||
BooleanFunctionCall(short type);
|
||||
BooleanFunctionCall(BooleanFunctions aType);
|
||||
|
||||
/**
|
||||
* Evaluates this Expr based on the given context node and processor state
|
||||
@ -126,10 +132,10 @@ public:
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
**/
|
||||
virtual ExprResult* evaluate(Node* context, ContextState* cs);
|
||||
ExprResult* evaluate(Node* aContext, ContextState* aCs);
|
||||
|
||||
private:
|
||||
short type;
|
||||
BooleanFunctions mType;
|
||||
}; //-- BooleanFunctionCall
|
||||
|
||||
/**
|
||||
@ -271,7 +277,7 @@ public:
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
*/
|
||||
virtual ExprResult* evaluate(Node* context, ContextState* cs);
|
||||
ExprResult* evaluate(Node* aContext, ContextState* aCs);
|
||||
|
||||
private:
|
||||
NodeSetFunctions mType;
|
||||
@ -285,23 +291,23 @@ class StringFunctionCall : public FunctionCall {
|
||||
|
||||
public:
|
||||
|
||||
enum stringFunctions {
|
||||
CONCAT = 1, //-- concat()
|
||||
CONTAINS, //-- contains()
|
||||
NORMALIZE_SPACE, //-- normalize-space()
|
||||
STARTS_WITH, //-- starts-with()
|
||||
STRING, //-- string()
|
||||
STRING_LENGTH, //-- string-length()
|
||||
SUBSTRING, //-- substring()
|
||||
SUBSTRING_AFTER, //-- substring-after()
|
||||
SUBSTRING_BEFORE, //-- substring-before()
|
||||
TRANSLATE //-- translate()
|
||||
enum StringFunctions {
|
||||
CONCAT, // concat()
|
||||
CONTAINS, // contains()
|
||||
NORMALIZE_SPACE, // normalize-space()
|
||||
STARTS_WITH, // starts-with()
|
||||
STRING, // string()
|
||||
STRING_LENGTH, // string-length()
|
||||
SUBSTRING, // substring()
|
||||
SUBSTRING_AFTER, // substring-after()
|
||||
SUBSTRING_BEFORE, // substring-before()
|
||||
TRANSLATE // translate()
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a String function of the given type
|
||||
**/
|
||||
StringFunctionCall(short type);
|
||||
StringFunctionCall(StringFunctions aType);
|
||||
|
||||
/**
|
||||
* Evaluates this Expr based on the given context node and processor state
|
||||
@ -310,10 +316,10 @@ public:
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
**/
|
||||
virtual ExprResult* evaluate(Node* context, ContextState* cs);
|
||||
ExprResult* evaluate(Node* aContext, ContextState* aCs);
|
||||
|
||||
private:
|
||||
short type;
|
||||
StringFunctions mType;
|
||||
}; //-- StringFunctionCall
|
||||
|
||||
|
||||
@ -335,7 +341,7 @@ public:
|
||||
/*
|
||||
* Creates a Number function of the given type
|
||||
*/
|
||||
NumberFunctionCall(NumberFunctions type);
|
||||
NumberFunctionCall(NumberFunctions aType);
|
||||
|
||||
/*
|
||||
* Evaluates this Expr based on the given context node and processor state
|
||||
@ -344,7 +350,7 @@ public:
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
*/
|
||||
virtual ExprResult* evaluate(Node* context, ContextState* cs);
|
||||
ExprResult* evaluate(Node* aContext, ContextState* aCs);
|
||||
|
||||
private:
|
||||
NumberFunctions mType;
|
||||
|
@ -68,22 +68,23 @@ NumberFunctionCall::NumberFunctionCall(NumberFunctions aType) {
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
*/
|
||||
ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
|
||||
ExprResult* NumberFunctionCall::evaluate(Node* aContext, ContextState* aCs)
|
||||
{
|
||||
ListIterator iter(¶ms);
|
||||
|
||||
if (mType == NUMBER) {
|
||||
if (!requireParams(0, 1, cs))
|
||||
if (!requireParams(0, 1, aCs))
|
||||
return new StringResult("error");
|
||||
}
|
||||
else {
|
||||
if (!requireParams(1, 1, cs))
|
||||
if (!requireParams(1, 1, aCs))
|
||||
return new StringResult("error");
|
||||
}
|
||||
|
||||
switch (mType) {
|
||||
case CEILING:
|
||||
{
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
|
||||
if (Double::isNaN(dbl) || Double::isInfinite(dbl))
|
||||
return new NumberResult(dbl);
|
||||
|
||||
@ -94,7 +95,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
|
||||
}
|
||||
case FLOOR:
|
||||
{
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
|
||||
if (Double::isNaN(dbl) ||
|
||||
Double::isInfinite(dbl) ||
|
||||
(dbl == 0 && Double::isNeg(dbl)))
|
||||
@ -104,7 +105,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
|
||||
}
|
||||
case ROUND:
|
||||
{
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), context, cs);
|
||||
double dbl = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
|
||||
if (Double::isNaN(dbl) || Double::isInfinite(dbl))
|
||||
return new NumberResult(dbl);
|
||||
|
||||
@ -116,7 +117,7 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
|
||||
case SUM:
|
||||
{
|
||||
NodeSet* nodes;
|
||||
nodes = evaluateToNodeSet((Expr*)iter.next(), context, cs);
|
||||
nodes = evaluateToNodeSet((Expr*)iter.next(), aContext, aCs);
|
||||
|
||||
if (!nodes)
|
||||
return new StringResult("error");
|
||||
@ -134,14 +135,18 @@ ExprResult* NumberFunctionCall::evaluate(Node* context, ContextState* cs) {
|
||||
}
|
||||
case NUMBER:
|
||||
{
|
||||
if (iter.hasNext())
|
||||
if (iter.hasNext()) {
|
||||
return new NumberResult(
|
||||
evaluateToNumber((Expr*)iter.next(), context, cs));
|
||||
evaluateToNumber((Expr*)iter.next(), aContext, aCs));
|
||||
}
|
||||
|
||||
String resultStr;
|
||||
XMLDOMUtils::getNodeValue(context, resultStr);
|
||||
XMLDOMUtils::getNodeValue(aContext, resultStr);
|
||||
return new NumberResult(Double::toDouble(resultStr));
|
||||
}
|
||||
}
|
||||
|
||||
String err("Internal error");
|
||||
aCs->recieveError(err);
|
||||
return new StringResult("error");
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
@ -29,16 +30,15 @@
|
||||
**/
|
||||
|
||||
#include "FunctionLib.h"
|
||||
#include "XMLUtils.h"
|
||||
#include "XMLDOMUtils.h"
|
||||
#include <math.h>
|
||||
|
||||
/**
|
||||
* Creates a StringFunctionCall of the given type
|
||||
**/
|
||||
StringFunctionCall::StringFunctionCall(short type) : FunctionCall() {
|
||||
this->type = type;
|
||||
switch ( type ) {
|
||||
StringFunctionCall::StringFunctionCall(StringFunctions aType) : mType(aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case CONCAT:
|
||||
name = XPathNames::CONCAT_FN;
|
||||
break;
|
||||
@ -67,7 +67,7 @@ StringFunctionCall::StringFunctionCall(short type) : FunctionCall() {
|
||||
name = XPathNames::STRING_FN;
|
||||
break;
|
||||
}
|
||||
} //-- StringFunctionCall
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates this Expr based on the given context node and processor state
|
||||
@ -76,214 +76,202 @@ StringFunctionCall::StringFunctionCall(short type) : FunctionCall() {
|
||||
* for evaluation
|
||||
* @return the result of the evaluation
|
||||
**/
|
||||
ExprResult* StringFunctionCall::evaluate(Node* context, ContextState* cs) {
|
||||
ListIterator* iter = params.iterator();
|
||||
PRInt32 argc = params.getLength();
|
||||
String err;
|
||||
ExprResult* result = 0;
|
||||
switch ( type ) {
|
||||
case CONCAT :
|
||||
if ( requireParams(2, cs) ) {
|
||||
String resultStr;
|
||||
while(iter->hasNext()) {
|
||||
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
|
||||
}
|
||||
result = new StringResult(resultStr);
|
||||
ExprResult* StringFunctionCall::evaluate(Node* aContext, ContextState* aCs)
|
||||
{
|
||||
ListIterator iter(¶ms);
|
||||
switch (mType) {
|
||||
case CONCAT:
|
||||
{
|
||||
if (!requireParams(2, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String resultStr;
|
||||
while (iter.hasNext()) {
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
|
||||
}
|
||||
else result = new StringResult("");
|
||||
break;
|
||||
case CONTAINS :
|
||||
if ( requireParams(2, 2, cs) ) {
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg1);
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg2);
|
||||
result = new BooleanResult((MBool)(arg1.indexOf(arg2) >= 0));
|
||||
}
|
||||
else result = new BooleanResult(MB_FALSE);
|
||||
break;
|
||||
return new StringResult(resultStr);
|
||||
}
|
||||
case CONTAINS:
|
||||
{
|
||||
if (!requireParams(2, 2, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
|
||||
return new BooleanResult(arg1.indexOf(arg2) >= 0);
|
||||
}
|
||||
case NORMALIZE_SPACE:
|
||||
if ( requireParams(0, 1, cs) ) {
|
||||
String resultStr;
|
||||
if ( argc == 1)
|
||||
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
|
||||
else
|
||||
XMLDOMUtils::getNodeValue(context, resultStr);
|
||||
// Leading & Trailing Whitespace
|
||||
resultStr.trim();
|
||||
MBool hasSpace = MB_FALSE;
|
||||
PRInt32 dest=0;
|
||||
String normed(resultStr.length());
|
||||
UNICODE_CHAR current;
|
||||
for (PRInt32 src=0; src<resultStr.length(); src++) {
|
||||
current=resultStr.charAt(src);
|
||||
if (current==' ' || current=='\n' ||
|
||||
current=='\t' || current=='\r') {
|
||||
if (!hasSpace) {
|
||||
normed.replace(dest,' ');
|
||||
dest++;
|
||||
hasSpace=MB_TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
normed.replace(dest,current);
|
||||
dest++;
|
||||
hasSpace=MB_FALSE;
|
||||
}
|
||||
}
|
||||
result = new StringResult(normed);
|
||||
}
|
||||
else result = new StringResult("");
|
||||
break;
|
||||
case STARTS_WITH :
|
||||
if ( requireParams(2, 2, cs) ) {
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg1);
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg2);
|
||||
result = new BooleanResult((MBool)(arg1.indexOf(arg2) == 0));
|
||||
}
|
||||
else result = new BooleanResult(MB_FALSE);
|
||||
break;
|
||||
case STRING_LENGTH:
|
||||
if ( requireParams(0, 1, cs) ) {
|
||||
String resultStr;
|
||||
if ( argc == 1) {
|
||||
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
|
||||
}
|
||||
else XMLDOMUtils::getNodeValue(context, resultStr);
|
||||
result = new NumberResult( (double) resultStr.length());
|
||||
}
|
||||
else result = new NumberResult(0.0);
|
||||
break;
|
||||
case SUBSTRING:
|
||||
if ( requireParams(2, 3, cs) ) {
|
||||
String src;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, src);
|
||||
double dbl = evaluateToNumber((Expr*)iter->next(), context, cs);
|
||||
{
|
||||
if (!requireParams(0, 1, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
//-- check for NaN
|
||||
if ( Double::isNaN(dbl)) {
|
||||
result = new StringResult("");
|
||||
break;
|
||||
}
|
||||
|
||||
//-- check for -Infinity
|
||||
MBool startsNegInf = (dbl==Double::NEGATIVE_INFINITY);
|
||||
|
||||
PRInt32 startIdx = startsNegInf?0:(PRInt32)floor(dbl+.5);
|
||||
PRInt32 endIdx = src.length()+1;
|
||||
if ( argc == 3) {
|
||||
dbl = evaluateToNumber((Expr*)iter->next(),context, cs);
|
||||
if (startsNegInf) {
|
||||
result = new StringResult("");
|
||||
break;
|
||||
}
|
||||
if (dbl == Double::POSITIVE_INFINITY) ; //already complete
|
||||
else if ( Double::isNaN(dbl) ||
|
||||
dbl == Double::NEGATIVE_INFINITY ||
|
||||
dbl < 0 )
|
||||
endIdx = 0;
|
||||
else endIdx = startIdx+(PRInt32)floor(dbl+.5);
|
||||
}
|
||||
String resultStr;
|
||||
//-- strings are indexed starting at 1 for XSL
|
||||
//-- adjust to a 0-based index
|
||||
endIdx--;
|
||||
if (startIdx<1){
|
||||
startIdx = 0;
|
||||
} else {
|
||||
startIdx--;
|
||||
}
|
||||
|
||||
src.subString(startIdx,endIdx,resultStr);
|
||||
result = new StringResult(resultStr);
|
||||
}
|
||||
else result = new StringResult("");
|
||||
break;
|
||||
|
||||
case SUBSTRING_AFTER:
|
||||
if ( requireParams(2, 2, cs) ) {
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg1);
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg2);
|
||||
PRInt32 idx = arg1.indexOf(arg2);
|
||||
if ((idx >= 0)&&(idx<arg1.length())) {
|
||||
PRInt32 len = arg2.length();
|
||||
arg2.clear();
|
||||
arg1.subString(idx+len,arg2);
|
||||
result = new StringResult(arg2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = new StringResult("");
|
||||
break;
|
||||
case SUBSTRING_BEFORE:
|
||||
if ( requireParams(2, 2, cs) ) {
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg1);
|
||||
evaluateToString((Expr*)iter->next(),context, cs, arg2);
|
||||
PRInt32 idx = arg1.indexOf(arg2);
|
||||
if ((idx >= 0)&&(idx<arg1.length())) {
|
||||
arg2.clear();
|
||||
arg1.subString(0,idx,arg2);
|
||||
result = new StringResult(arg2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = new StringResult("");
|
||||
break;
|
||||
case TRANSLATE:
|
||||
if ( requireParams(3, 3, cs) ) {
|
||||
String src;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, src);
|
||||
|
||||
if (src.isEmpty()) {
|
||||
result = new StringResult("");
|
||||
break;
|
||||
}
|
||||
|
||||
String oldChars, newChars;
|
||||
evaluateToString((Expr*)iter->next(),context, cs, oldChars);
|
||||
evaluateToString((Expr*)iter->next(),context, cs, newChars);
|
||||
PRInt32 size = src.length();
|
||||
UNICODE_CHAR* chars = src.toUnicode(new UNICODE_CHAR[size]);
|
||||
src.clear();
|
||||
PRInt32 i;
|
||||
for (i = 0; i < size; i++) {
|
||||
PRInt32 idx = oldChars.indexOf(chars[i]);
|
||||
if (idx >= 0) {
|
||||
if (idx < newChars.length())
|
||||
src.append(newChars.charAt(idx));
|
||||
}
|
||||
else {
|
||||
src.append(chars[i]);
|
||||
}
|
||||
}
|
||||
delete chars;
|
||||
result = new StringResult(src);
|
||||
}
|
||||
String resultStr;
|
||||
if (iter.hasNext())
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
|
||||
else
|
||||
result = new StringResult("");
|
||||
break;
|
||||
XMLDOMUtils::getNodeValue(aContext, resultStr);
|
||||
|
||||
default : //-- string( object? )
|
||||
if ( requireParams(0, 1, cs) ) {
|
||||
String resultStr;
|
||||
if (iter->hasNext()) {
|
||||
evaluateToString((Expr*)iter->next(),context, cs, resultStr);
|
||||
MBool addSpace = MB_FALSE;
|
||||
MBool first = MB_TRUE;
|
||||
String normed(resultStr.length());
|
||||
UNICODE_CHAR c;
|
||||
PRInt32 src;
|
||||
for (src = 0; src < resultStr.length(); src++) {
|
||||
c = resultStr.charAt(src);
|
||||
if (c == ' ' || c == '\n' ||
|
||||
c == '\t' || c == '\r') {
|
||||
addSpace = MB_TRUE;
|
||||
}
|
||||
else {
|
||||
XMLDOMUtils::getNodeValue(context, resultStr);
|
||||
if ( cs->isStripSpaceAllowed(context) &&
|
||||
XMLUtils::shouldStripTextnode(resultStr))
|
||||
resultStr = "";
|
||||
}
|
||||
result = new StringResult(resultStr);
|
||||
}
|
||||
else result = new StringResult("");
|
||||
break;
|
||||
}
|
||||
delete iter;
|
||||
return result;
|
||||
} //-- evaluate
|
||||
if (addSpace && !first)
|
||||
normed.append(' ');
|
||||
|
||||
normed.append(c);
|
||||
addSpace = MB_FALSE;
|
||||
first = MB_FALSE;
|
||||
}
|
||||
}
|
||||
return new StringResult(normed);
|
||||
}
|
||||
case STARTS_WITH:
|
||||
{
|
||||
if (!requireParams(2, 2, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
|
||||
return new BooleanResult(arg1.indexOf(arg2) == 0);
|
||||
}
|
||||
case STRING_LENGTH:
|
||||
{
|
||||
if (!requireParams(0, 1, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String resultStr;
|
||||
if (iter.hasNext())
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
|
||||
else
|
||||
XMLDOMUtils::getNodeValue(aContext, resultStr);
|
||||
return new NumberResult(resultStr.length());
|
||||
}
|
||||
case SUBSTRING:
|
||||
{
|
||||
if (!requireParams(2, 3, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String src;
|
||||
double start, end;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, src);
|
||||
start = evaluateToNumber((Expr*)iter.next(), aContext, aCs);
|
||||
|
||||
// check for NaN or +/-Inf
|
||||
if (Double::isNaN(start) ||
|
||||
Double::isInfinite(start) ||
|
||||
start + 0.5 >= src.length())
|
||||
return new StringResult();
|
||||
|
||||
start = floor(start + 0.5) - 1;
|
||||
if (iter.hasNext()) {
|
||||
end = start + evaluateToNumber((Expr*)iter.next(),
|
||||
aContext,
|
||||
aCs);
|
||||
if (Double::isNaN(end) || end < 0)
|
||||
return new StringResult();
|
||||
|
||||
if (end > src.length())
|
||||
end = src.length();
|
||||
else
|
||||
end = floor(end + 0.5);
|
||||
}
|
||||
else {
|
||||
end = src.length();
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
|
||||
if (start > end)
|
||||
return new StringResult();
|
||||
|
||||
String resultStr;
|
||||
src.subString((PRInt32)start, (PRInt32)end, resultStr);
|
||||
return new StringResult(resultStr);
|
||||
}
|
||||
case SUBSTRING_AFTER:
|
||||
{
|
||||
if (!requireParams(2, 2, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
|
||||
PRInt32 idx = arg1.indexOf(arg2);
|
||||
if (idx >= 0) {
|
||||
PRInt32 len = arg2.length();
|
||||
arg1.subString(idx + len, arg2);
|
||||
return new StringResult(arg2);
|
||||
}
|
||||
return new StringResult();
|
||||
}
|
||||
case SUBSTRING_BEFORE:
|
||||
{
|
||||
if (!requireParams(2, 2, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String arg1, arg2;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg1);
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, arg2);
|
||||
PRInt32 idx = arg1.indexOf(arg2);
|
||||
if (idx >= 0) {
|
||||
arg2.clear();
|
||||
arg1.subString(0, idx, arg2);
|
||||
return new StringResult(arg2);
|
||||
}
|
||||
return new StringResult();
|
||||
}
|
||||
case TRANSLATE:
|
||||
{
|
||||
if (!requireParams(3, 3, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String src;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, src);
|
||||
if (src.isEmpty())
|
||||
return new StringResult();
|
||||
|
||||
String oldChars, newChars, dest;
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, oldChars);
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, newChars);
|
||||
PRInt32 i;
|
||||
for (i = 0; i < src.length(); i++) {
|
||||
PRInt32 idx = oldChars.indexOf(src.charAt(i));
|
||||
if (idx >= 0) {
|
||||
if (idx < newChars.length())
|
||||
dest.append(newChars.charAt(idx));
|
||||
}
|
||||
else {
|
||||
dest.append(src.charAt(i));
|
||||
}
|
||||
}
|
||||
return new StringResult(dest);
|
||||
}
|
||||
case STRING:
|
||||
{
|
||||
if (!requireParams(0, 1, aCs))
|
||||
return new StringResult("error");
|
||||
|
||||
String resultStr;
|
||||
if (iter.hasNext())
|
||||
evaluateToString((Expr*)iter.next(), aContext, aCs, resultStr);
|
||||
else
|
||||
XMLDOMUtils::getNodeValue(aContext, resultStr);
|
||||
return new StringResult(resultStr);
|
||||
}
|
||||
}
|
||||
|
||||
String err("Internal error");
|
||||
aCs->recieveError(err);
|
||||
return new StringResult("error");
|
||||
}
|
||||
|
@ -296,8 +296,12 @@ ExprResult* txFormatNumberFunctionCall::evaluate(Node* aContext,
|
||||
return new StringResult;
|
||||
}
|
||||
|
||||
int totalSize = minIntegerSize + maxFractionSize;
|
||||
if (maxFractionSize > 0)
|
||||
totalSize++; //to account for decimal point
|
||||
|
||||
char formatBuf[30];
|
||||
sprintf(formatBuf, "%%0%d.%df", minIntegerSize, maxFractionSize);
|
||||
sprintf(formatBuf, "%%0%d.%df", totalSize, maxFractionSize);
|
||||
|
||||
sprintf(buf, formatBuf, value);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user