//*********************************************************************
// xpath.cpp
//
// Copyright 2003 Paul J. Medlock all rights reserved
//
//*********************************************************************
//
// Synopsis of the XPath Recommendation
//
// The following material is taken from the XML Path Language (XPath
// Version 1.0 W3C Recommendation 16 November 1999 at
//
// http://www.w3.org/TR/xpath#section-Expressions
//
// The primary syntactic construct in XPath is the expression.
An
// expression matches the production Expr. An expression is evaluated
// to yield an object, which has one of the following four basic
types:
// node-set (an unordered collection of nodes
without duplicates)
// boolean (true or false)
// number (a floating-point number)
// string (a sequence of UCS characters)
//
// Expression evaluation occurs with respect to a context. XSLT
and
// XPointer specify how the context is determined for XPath expressions
// used in XSLT and XPointer respectively. The context consists
of:
// a node (the context node)
// a pair of non-zero positive integers (the context
position and the
// context size)
// a set of variable bindings
// a function library
// the set of namespace declarations in scope for the
expression
//
// The context position is always less than or equal to the context
// size.
//
//---------------------------------------------------------------------
//
// Syntax
//
// [1] LocationPath
RelativeLocationPath
//
| AbsoluteLocationPath
// [2] AbsoluteLocationPath
'/' RelativeLocationPath?
//
| AbbreviatedAbsoluteLocationPath
// [3] RelativeLocationPath
Step
//
| RelativeLocationPath '/' Step
//
| AbbreviatedRelativeLocationPath
// [4] Step
AxisSpecifier NodeTest Predicate*
//
| AbbreviatedStep
// [5] AxisSpecifier
AxisName '::'
//
| AbbreviatedAxisSpecifier
// [6] AxisName
'ancestor'
//
| 'ancestor-or-self'
//
| 'attribute'
//
| 'child'
//
| 'descendant'
//
| 'descendant-or-self'
//
| 'following'
//
| 'following-sibling'
//
| 'namespace'
//
| 'parent'
//
| 'preceding'
//
| 'preceding-sibling'
//
| 'self'
// [7] NodeTest
NameTest
//
| NodeType '(' ')'
//
| 'processing-instruction'
//
'(' Literal ')'
// [8] Predicate
'[' PredicateExpr ']'
// [9] PredicateExpr
Expr
// [10] AbbreviatedAbsoluteLocationPath
//
'//' RelativeLocationPath
// [11] AbbreviatedRelativeLocationPath
//
RelativeLocationPath '//' Step
// [12] AbbreviatedStep
'.'
//
| '..'
// [13] AbbreviatedAxisSpecifier '@'?
// [14] Expr
OrExpr
// [15] PrimaryExpr
VariableReference
//
| '(' Expr ')'
//
| Literal
//
| Number
//
| FunctionCall
// [16] FunctionCall
FunctionName
//
'(' ( Argument ( ',' Argument )* )? ')'
// [17] Argument
Expr
// [18] UnionExpr
PathExpr
//
| UnionExpr '|' PathExpr
// [19] PathExpr
LocationPath
//
| FilterExpr
//
| FilterExpr '/' RelativeLocationPath
//
| FilterExpr '//' RelativeLocationPath
// [20] FilterExpr
PrimaryExpr
//
| FilterExpr Predicate
// [21] OrExpr
AndExpr
//
| OrExpr 'or' AndExpr
// [22] AndExpr
EqualityExpr
//
| AndExpr 'and' EqualityExpr
// [23] EqualityExpr
RelationalExpr
//
| EqualityExpr '=' RelationalExpr
//
| EqualityExpr '!=' RelationalExpr
// [24] RelationalExpr
AdditiveExpr
//
| RelationalExpr '<' AdditiveExpr
//
| RelationalExpr '>' AdditiveExpr
//
| RelationalExpr '<=' AdditiveExpr
//
| RelationalExpr '>=' AdditiveExpr
// [25] AdditiveExpr
MultiplicativeExpr
//
| AdditiveExpr '+' MultiplicativeExpr
//
| AdditiveExpr '-' MultiplicativeExpr
// [26] MultiplicativeExpr
UnaryExpr
//
| MultiplicativeExpr MultiplyOperator UnaryExpr
//
| MultiplicativeExpr 'div' UnaryExpr
//
| MultiplicativeExpr 'mod' UnaryExpr
// [27] UnaryExpr
UnionExpr
//
| '-' UnaryExpr
//
//---------------------------------------------------------------------
// Lexical Structure
//
// When tokenizing, the longest possible token is always returned.
//
// For readability, whitespace may be used in expressions even
though
// not explicitly allowed by the grammar: ExprWhitespace may be
freely
// added within patterns before or after any ExprToken.
//
// The following special tokenization rules must be applied in
the
// order specified to disambiguate the ExprToken grammar:
//
// * If there is a preceding token and the preceding
token is not one
// of @, ::, (, [, , or an Operator, then
a * must be recognized as
// a MultiplyOperator and an NCName must
be recognized as an
// OperatorName.
//
// * If the character following an NCName (possibly
after intervening
// ExprWhitespace) is (, then the token
must be recognized as a
// NodeType or a FunctionName.
//
// * If the two characters following an NCName (possibly
after
// intervening ExprWhitespace) are ::,
then the token must be
// recognized as an AxisName.
//
// * Otherwise, the token must not be recognized as
a
// MultiplyOperator, an OperatorName, a
NodeType, a FunctionName,
// or an AxisName.
//
//
// [28] ExprToken
'(' | ')' | '[' | ']' | '.' | '..'
//
| '@' | ',' | '::'
//
| NameTest
//
| NodeType
//
| Operator
//
| FunctionName
//
| AxisName
//
| Literal
//
| Number
//
| VariableReference
// [29] Literal
'"' [^"]* '"'
//
| "'" [^']* "'"
// [30] Number
Digits ('.' Digits?)?
//
| '.' Digits
// [31] Digits
[0-9]+
// [32] Operator
OperatorName
//
| MultiplyOperator
//
| '/' | '//' | '|' | '+' | '-' | '='
//
| '!=' | '<' | '<=' | '>' | '>='
// [33] OperatorName
'and' | 'or' | 'mod' | 'div'
// [34] MultiplyOperator
'*'
// [35] FunctionName
QName - NodeType
// [36] VariableReference
'$' QName
// [37] NameTest
'*'
//
| NCName ':' '*'
//
| QName
// [38] NodeType
'comment'
//
| 'text'
//
| 'processing-instruction'
//
| 'node'
// [39] ExprWhitespace
S (space)
//
// Boolean Functions
//
// Function: boolean boolean(object)
// Function: boolean not(boolean)
// Function: boolean true()
// Function: boolean false()
// Function: boolean lang(string)
//
// Number Functions
//
// Function: number number(object?)
// Function: number sum(node-set)
// Function: number floor(number)
// Function: number ceiling(number)
// Function: number round(number)
//
// String Functions
//
// Function: string string(object?)
// Function: string concat(string, string, string*)
// Function: boolean starts-with(string, string)
// Function: boolean contains(string, string)
// Function: string substring-before(string,
string)
// Function: string substring-after(string, string)
// Function: string substring(string, number,
number?)
// Function: number string-length(string?)
// Function: string normalize-space(string?)
// Function: string translate(string, string,
string)
//
// Node Set Functions
//
// Function: number last()
// Function: number position()
// Function: number count(node-set)
// Function: node-set id(object)
// Function: string local-name(node-set?)
// Function: string namespace-uri(node-set?)
// Function: string name(node-set?)
//
//*********************************************************************
//
// Implementation notes:
//
// This XPath implementation operates in two phases:
//
// 1. Parse the input expression, validating
and preparing it for
// input into phase 2.
//
// 2. Evaluate the parsed expression against
the specified node.
//
// The Parser
//
// The parser applies the XPath production rules against the input
// expression to output symbols into an intermediate buffer. It
mixes
// postfix notation with sequential notation, depending on the
applied
// production rule; viz., location path parts are output in the
order
// they are received while other expressions, such as binary operators
// and funtions and their parameters, are output in postfix order.
//
// The parser prepends each output symbol with a special character
// (XP_ALL to XP_VARIABLE listed below) to indicate the type of
the
// symbol. Errors in the input expression cause the parser to throw
an
// error code (see errs.h) back to the user.
//
// The parser generates special context-stack unwind operator symbols
// at the end of each LocationPath in the input XPath expression.
The
// unwinder operator specifies the number of items to pop from
the
// context stack to get it back to a correct state for the context
of
// the LocationPath.
//
// The parser uses the outputPostfix() / method to output symbols.
This
// method prepends a space character before each output symbol
to make
// it easy for the evaluator to tokenize.
//
// The Evaluator
//
// The evaluator maintains two stacks:
//
// 1. The evaluation stack - contains the results
of the evaluation.
//
// 2. The context stack - presents the context
nodes and their
// associated information.
//
// The results of operations are pushed onto the evaluation stack,
and
// removed as needed by other operations. Because some functions
allow
// an arbitrary number of arguments, the left parenthesis is pushed
// onto the stack before arguments are computed so that the function
// can verify the number of arguments it actually receives by popping
// the evaluation stack down to the left paranthesis.
//
// Each of the three user interface methods (SelectSingleNode,
// SelectNodes, and Evaluate) prepare the context stack by pushing
the
// specified node onto it. The Root operator (first /) pushes the
// document root node onto the context stack, while the Path operator
// (/) pops the top of the evaluation stack and pushes that value
onto
// the context stack. (It's an error if the top of the evaluation
stack
// is not a nodeSet.) The evalPredicate() and the stringValue()
methods
// also push a node onto the context stack before using the eval()
// method for their special purposes. The Unwind operator along
with
// the evalPredicate(), and the stringValue() methods pop items
off the
// context stack.
//
//*********************************************************************
#include "math.h"
#include "prefixb.h"
#include "common.h"
#include "domtree.h"
#include "errs.h"
#include "regx.h"
#include "xpath.h"
//---------------------------------------------------------------------
//
const uchar XP_IGNORE
= '%';
const uchar XP_NOTKNOWN =
0;
const uchar XP_EMPTY
= 1;
const uchar XP_ALL
= 128;
const uchar XP_ALLNAME
= 129;
const uchar XP_AND
= 130;
const uchar XP_ATTR
= 131;
const uchar XP_AXISNAME = 132;
const uchar XP_COLON
= 133;
const uchar XP_COMMA
= 134;
const uchar XP_DBLCOLON = 135;
const uchar XP_DBLDOT
= 136;
const uchar XP_DBLPATH
= 137;
const uchar XP_DIV
= 138;
const uchar XP_DOT
= 139;
const uchar XP_EQUAL
= 140;
const uchar XP_FUNNAME
= 141;
const uchar XP_GREATEROREQUAL = 142;
const uchar XP_GREATERTHAN = 143;
const uchar XP_LBOX
= 144;
const uchar XP_LESSOREQUAL = 145;
const uchar XP_LESSTHAN = 146;
const uchar XP_LPAREN
= 147;
const uchar XP_MINUS
= 148;
const uchar XP_MOD
= 149;
const uchar XP_NODETYPE = 150;
const uchar XP_MUL
= 151;
const uchar XP_NOT
= 152;
const uchar XP_NOTEQUAL = 153;
const uchar XP_OR
= 154;
const uchar XP_PARSEERROR = 155;
const uchar XP_PATH
= 156;
const uchar XP_PLUS
= 157;
const uchar XP_QNAME
= 158;
const uchar XP_QUOTEDSTR = 159;
const uchar XP_RBOX
= 160;
const uchar XP_ROOT
= 161;
const uchar XP_RPAREN
= 162;
const uchar XP_SPACE
= 163;
const uchar XP_UNARYMINUS = 164;
const uchar XP_UNION
= 165;
const uchar XP_UNWIND
= 166;
const uchar XP_VARIABLE = 167;
#define _ROUND(a) (floor(a+0.5))
//=====================================================================
// CXPath Implementation
//=====================================================================
//---------------------------------------------------------------------
//
CXPath::CXPath(void):
CAtom (),
stoken (0),
op (XP_NOTKNOWN),
ch (spacer),
iExp (0),
extend (false),
atEnd (false),
isOp (false),
wasOp (false),
lop (XP_NOTKNOWN),
inFixExp (0),
pInFixExp (0),
postFixExp(0) {
ctxtStack = new CXPathStack();
evalStack = new CXPathStack();
} // CXPath
//---------------------------------------------------------------------
//
CXPath::~CXPath() {
delete[] stoken;
stoken = 0;
delete[] inFixExp;
inFixExp = 0;
delete[] postFixExp;
postFixExp = 0;
} // ~CXPath
//---------------------------------------------------------------------
//
RTTI_CPP(XPath, Atom)
//---------------------------------------------------------------------
//
PCNode CXPath::SelectSingleNode(RPCNode _node,
Pchar _path,
bool _extend) {
extend = _extend;
if (!_node
||
(!_node->Isa(iDocument) &&
!_node->Isa(iElement)))
{
err = XPE_NODEEXPECTED;
return 0;
}
node = _node;
//?if (node->Isa(iDocument))
//? node = TYPECAST(node, Document)->DocumentElement();
// Prepare the context stack
ctxtStack->Init();
PCXPathItem item = new CXPathItem(node);
item->node = node;
item->position = 1;
item->size = 1;
ctxtStack->PushX(item);
// and the evaluation stack
evalStack->Init();
// Parse the XPath expression
char work[sizeString];
Strcpy(work, Parse(_path), sizeString);
if (err)
return 0;
// Evaluate the parsed expression
try {
eval(work);
}
catch (ulong _err) {
err = _err;
return 0;
}
// Make sure the evaluator used up everything on the
stack
if (evalStack->Number()
!= 1) {
err = XPE_STACKNOTEMPTY;
return 0;
}
// Return the item at TOS
item = evalStack->Pop();
// Make sure that the result of the evaluation is a
node list
if (item->type != XP_NODESET) {
err = XPE_NODESETEXPECTED;
return 0;
}
// Check that there is at least one node to return
if (item->nValue->Length() == 0) {
err = XPE_EMPTYRESULT;
return 0;
}
node = item->nValue->Item(0);
return node;
} // SelectSingleNode
//---------------------------------------------------------------------
//
PCNodeList CXPath::SelectNodes(RPCNode _node, Pchar _path) {
extend = false;
if (!_node
||
(!_node->Isa(iDocument) &&
!_node->Isa(iElement)))
{
err = XPE_NODEEXPECTED;
return 0;
}
node = _node;
//?if (node->Isa(iDocument))
//? node = TYPECAST(node, Document)->DocumentElement();
// Prepare the context stack
ctxtStack->Init();
PCXPathItem item = new CXPathItem(node);
item->node = node;
item->position = 1;
item->size = 1;
ctxtStack->PushX(item);
// and the evaluation stack
evalStack->Init();
// Parse the XPath expression
char work[sizeString];
Strcpy(work, Parse(_path), sizeString);
if (err)
return 0;
// Evaluate the parsed expression
try {
eval(work);
}
catch (ulong _err) {
err = _err;
return 0;
}
// Make sure the evaluator used up everything on the
stack
if (evalStack->Number()
!= 1) {
err = XPE_STACKNOTEMPTY;
return 0;
}
// Return the item at TOS
item = evalStack->Pop();
// Make sure that the result of the evaluation is a
node list
if (item->type != XP_NODESET) {
err = XPE_NODESETEXPECTED;
return 0;
}
return item->nValue;
} // SelectNodes
//---------------------------------------------------------------------
//
PCXPathItem CXPath::Evaluate(RPCNode _node, Pchar _path) {
extend = false;
if (!_node
||
(!_node->Isa(iDocument) &&
!_node->Isa(iElement)))
{
err = XPE_NODEEXPECTED;
return 0;
}
node = _node;
//?if (node->Isa(iDocument))
//? node = TYPECAST(node, Document)->DocumentElement();
// Prepare the context stack
ctxtStack->Init();
PCXPathItem item = new CXPathItem(node);
item->node = node;
item->position = 1;
item->size = 1;
ctxtStack->PushX(item);
// and the evaluation stack
evalStack->Init();
// Parse the XPath expression
char work[sizeString];
Strcpy(work, Parse(_path), sizeString);
if (err)
return 0;
// Evaluate the parsed XPath expression
try {
eval(work);
}
catch (ulong _err) {
err = _err;
}
// Make sure the evaluator used up everything on the
stack
if (evalStack->Number()
!= 1) {
err = XPE_STACKNOTEMPTY;
return 0;
}
// Return the item at TOS
item = evalStack->Pop();
item->clear();
return item;
} // Evaluate
//=====================================================================
// Evaluator
//=====================================================================
//---------------------------------------------------------------------
//
void CXPath::eval(Pchar _postFixExp) {
initEvalTokenizer(_postFixExp);
getEvalToken();
while (op != XP_EMPTY)
switch (op) {
case XP_IGNORE:
// ignore tokens beginning with a %-sign
break;
// they are present for debugging only
case XP_ALL:
throw(XPE_OPNOTEXPECTED);
case XP_ALLNAME:
throw(XPE_OPNOTEXPECTED);
case XP_AND:
evalAnd();
break;
case XP_ATTR:
throw(XPE_OPNOTEXPECTED);
case XP_AXISNAME:
evalStep();
break;
case XP_COLON:
throw(XPE_OPNOTEXPECTED);
case XP_COMMA:
throw(XPE_OPNOTEXPECTED);
case XP_DBLCOLON:
throw(XPE_OPNOTEXPECTED);
case XP_DBLDOT:
throw(XPE_OPNOTEXPECTED);
case XP_DBLPATH:
throw(XPE_OPNOTEXPECTED);
case XP_DIV:
evalDiv();
break;
case XP_DOT:
throw(XPE_OPNOTEXPECTED);
case XP_EQUAL:
evalEQ();
break;
case XP_FUNNAME:
evalFunction();
break;
case XP_GREATEROREQUAL:
evalGTE();
break;
case XP_GREATERTHAN:
evalGT();
break;
case XP_LBOX:
evalLBox();
break;
case XP_LESSOREQUAL:
evalLTE();
break;
case XP_LESSTHAN:
evalLT();
break;
case XP_LPAREN:
evalStack->PushL();
getEvalToken();
break;
case XP_MINUS:
evalMinus();
break;
case XP_MOD:
evalMod();
break;
case XP_MUL:
evalMul();
break;
case XP_NODETYPE:
throw(XPE_OPNOTEXPECTED);
case XP_NOT:
evalNegate();
break;
case XP_NOTEQUAL:
evalNE();
break;
case XP_NUMBER:
evalNmbr();
break;
case XP_OR:
evalOr();
break;
case XP_PATH:
evalPath();
break;
case XP_PLUS:
evalPlus();
break;
case XP_QNAME:
evalStack->PushS(stoken);
getEvalToken();
break;
case XP_QUOTEDSTR:
evalQuotedString();
break;
case XP_RBOX:
throw(XPE_OPNOTEXPECTED);
case XP_ROOT:
evalRoot();
break;
case XP_RPAREN:
throw(XPE_OPNOTEXPECTED);
case XP_UNARYMINUS:
evalUnaryMinus();
break;
case XP_UNION:
evalUnion();
break;
case XP_UNWIND:
evalUnwind();
break;
case XP_VARIABLE:
evalVariable();
break;
default:
evalStack->PushS(stoken);
getEvalToken();
}
} // eval
//---------------------------------------------------------------------
// Evaluate a and b
//
void CXPath::evalAnd(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack and convert it to boolean
PCXPathItem b = convertToBoolean(evalStack->Pop());
// Pop a off the stack and convert it to boolean
PCXPathItem a = convertToBoolean(evalStack->Pop());
// Push (a and b) onto the stack
evalStack->PushB(a->bValue & b->bValue);
// Get the next token
getEvalToken();
} // evalAnd
//---------------------------------------------------------------------
// Evaluate a / b
//
void CXPath::evalDiv(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack and convert it to numeric
PCXPathItem b = convertToNumber(evalStack->Pop());
// Pop a off the stack and convert it to numeric
PCXPathItem a = convertToNumber(evalStack->Pop());
if (b->dValue == 0)
throw(XPE_DIVIDEBYZERO);
// Push (a div b) onto the stack
evalStack->PushD(a->dValue / b->dValue);
// Get the next token
getEvalToken();
} // evalDiv
//---------------------------------------------------------------------
// Evaluate a = b
//
void CXPath::evalEQ(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack
PCXPathItem b = evalStack->Pop();
// Pop a off the stack
PCXPathItem a = evalStack->Pop();
// Compare the operands according to their type
if (a->type == XP_NODESET)
if
(b->type == XP_NODESET)
evalEQ_NDS_NDS(a,
b);
else if (b->type == XP_STRING)
evalEQ_NDS_STR(a,
b);
else if (b->type == XP_NUMBER)
evalEQ_NDS_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalEQ_NDS_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_STRING)
if
(b->type == XP_NODESET)
evalEQ_NDS_STR(b,
a);
else if (b->type == XP_STRING)
evalEQ_STR_STR(a,
b);
else if (b->type == XP_NUMBER)
evalEQ_STR_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalEQ_STR_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_NUMBER)
if
(b->type == XP_NODESET)
evalEQ_NDS_DBL(b,
a);
else if (b->type == XP_STRING)
evalEQ_STR_DBL(b,
a);
else if (b->type == XP_NUMBER)
evalEQ_DBL_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalEQ_DBL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_BOOLEAN)
if
(b->type == XP_NODESET)
evalEQ_NDS_BOL(b,
a);
else if (b->type == XP_STRING)
evalEQ_STR_BOL(b,
a);
else if (b->type == XP_NUMBER)
evalEQ_DBL_BOL(b,
a);
else if (b->type == XP_BOOLEAN)
evalEQ_BOL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else
throw(XPE_BADOPERANDTYPE);
// Push (a = b) onto the stack
// Get the next token
getEvalToken();
} // evalEQ
//---------------------------------------------------------------------
//
void CXPath::evalFunction(void) {
// Boolean functions
if (strcmp(stoken+1,
"boolean") == 0)
evalBoolean();
else if (strcmp(stoken+1, "not")
== 0)
evalNot();
else if (strcmp(stoken+1, "true")
== 0)
evalTrue();
else if (strcmp(stoken+1, "false")
== 0)
evalFalse();
// Number functions
else if (strcmp(stoken+1, "number")
== 0)
evalNumber();
else if (strcmp(stoken+1, "sum")
== 0)
evalSum();
else if (strcmp(stoken+1, "floor")
== 0)
evalFloor();
else if (strcmp(stoken+1, "ceiling")
== 0)
evalCeiling();
else if (strcmp(stoken+1, "round")
== 0)
evalRound();
// String functions
else if (strcmp(stoken+1, "string")
== 0)
evalString();
else if (strcmp(stoken+1, "concat")
== 0)
evalConcat();
else if (strcmp(stoken+1, "starts-with")
== 0)
evalStarts_with();
else if (strcmp(stoken+1, "contains")
== 0)
evalContains();
else if (strcmp(stoken+1, "substring-before") == 0)
evalSubstring_before();
else if (strcmp(stoken+1, "substring-after")
== 0)
evalSubstring_after();
else if (strcmp(stoken+1, "substring")
== 0)
evalSubstring();
else if (strcmp(stoken+1, "string-length")
== 0)
evalString_length();
else if (strcmp(stoken+1, "normalize-space")
== 0)
evalNormalize_space();
else if (strcmp(stoken+1, "translate")
== 0)
evalTranslate();
// Regular expression functions
else if (strcmp(stoken+1, "match")
== 0)
evalMatch();
//? TBD
//?else if (strcmp(stoken+1, "replace")
== 0)
//? evalReplace();
//?else if (strcmp(stoken+1, "tokenize")
== 0)
//? evalTokenize();
// Nodeset functions
else if (strcmp(stoken+1, "last")
== 0)
evalLast();
else if (strcmp(stoken+1, "position")
== 0)
evalPosition();
else if (strcmp(stoken+1, "count")
== 0)
evalCount();
else if (strcmp(stoken+1, "id")
== 0)
evalId();
else if (strcmp(stoken+1, "local-name")
== 0)
evalLocal_Name();
else if (strcmp(stoken+1, "name")
== 0)
evalName();
else if (strcmp(stoken+1, "namespace-uri")
== 0)
evalNamespace_uri();
else
throw(XPE_FUNCTIONUNKNOWN);
// Get the next token
getEvalToken();
} // evalFunction
//---------------------------------------------------------------------
// Evaluate a >= b
//
void CXPath::evalGTE(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack
PCXPathItem b = evalStack->Pop();
// Pop a off the stack
PCXPathItem a = evalStack->Pop();
// Compare the operands according to their type
if (a->type == XP_NODESET)
if
(b->type == XP_NODESET)
evalGTE_NDS_NDS(a,
b);
else if (b->type == XP_STRING)
evalGTE_NDS_STR(a,
b);
else if (b->type == XP_NUMBER)
evalGTE_NDS_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalGTE_NDS_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_STRING)
if
(b->type == XP_NODESET)
evalGTE_STR_NDS(a,
b);
else if (b->type == XP_STRING)
evalGTE_STR_STR(a,
b);
else if (b->type == XP_NUMBER)
evalGTE_STR_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalGTE_STR_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_NUMBER)
if
(b->type == XP_NODESET)
evalGTE_DBL_NDS(a,
b);
else if (b->type == XP_STRING)
evalGTE_DBL_STR(a,
b);
else if (b->type == XP_NUMBER)
evalGTE_DBL_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalGTE_DBL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_BOOLEAN)
if
(b->type == XP_NODESET)
evalGTE_BOL_NDS(a,
b);
else if (b->type == XP_STRING)
evalGTE_BOL_STR(a,
b);
else if (b->type == XP_NUMBER)
evalGTE_BOL_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalGTE_BOL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else
throw(XPE_BADOPERANDTYPE);
// Push (a = b) onto the stack
// Get the next token
getEvalToken();
} // evalGTE
//---------------------------------------------------------------------
// Evaluate a > b
//
void CXPath::evalGT(void) {
evalLTE();
// Reverse the sense of the result
evalStack->SetTOS(!evalStack->BoolAtTOS());
// Get the next token
getEvalToken();
} // evalGT
//---------------------------------------------------------------------
//
void CXPath::evalLBox(void) {
// Copy the parsed predicate into separate string
objects, adding
// each to my predicate list. Include nested predicates
PCStrList predicates = new CStrList();
char work[sizeString];
while (op == XP_LBOX) {
work[0] = 0;
int iPred = 1;
getEvalToken();
if
(op == XP_RBOX)
iPred--;
else if (op == XP_LBOX)
iPred++;
while (iPred != 0) {
ChrCat(work, '
', sizeString);
Strcat(work, stoken,
sizeString);
getEvalToken();
if
(op == XP_RBOX)
iPred--;
else if (op ==
XP_LBOX)
iPred++;
}
predicates->StrInsert(work);
getEvalToken();
}
// Evaluate the filter ---------------------------------------------
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
PCXPathItem item = evalStack->ItemAtTOS();
if (!item || item->type != XP_NODESET)
throw(XPE_NODESETEXPECTED);
// For each node in item.nodeset, apply the filtering
predicates,
// putting keepers in the rslts nodelist
PCNodeList rslts = new CNodeList();
PCNodeList nodes = item->nValue;
if (predicates->GotoHead()) do {
char exp[sizeString];
predicates->StrItem(exp, sizeString);
nodes = evalPredicate(nodes, exp,
item->order);
Assert(nodes);
} while (predicates->GotoNext());
// Collect the results of the predicate filtering
for (int j = 0; j < nodes->Length(); j++) {
PCNode node = nodes->Item(j);
rslts->InsertNode(node);
}
// Push the resulting NodeList onto the stack
evalStack->PushNL(rslts);
} // evalLBox
//---------------------------------------------------------------------
// Evaluate a <= b
//
void CXPath::evalLTE(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack
PCXPathItem b = evalStack->Pop();
// Pop a off the stack
PCXPathItem a = evalStack->Pop();
// Compare the operands according to their type
if (a->type == XP_NODESET)
if
(b->type == XP_NODESET)
evalLTE_NDS_NDS(a,
b);
else if (b->type == XP_STRING)
evalLTE_NDS_STR(a,
b);
else if (b->type == XP_NUMBER)
evalLTE_NDS_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalLTE_NDS_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_STRING)
if
(b->type == XP_NODESET)
evalLTE_STR_NDS(a,
b);
else if (b->type == XP_STRING)
evalLTE_STR_STR(a,
b);
else if (b->type == XP_NUMBER)
evalLTE_STR_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalLTE_STR_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_NUMBER)
if
(b->type == XP_NODESET)
evalLTE_DBL_NDS(a,
b);
else if (b->type == XP_STRING)
evalLTE_DBL_STR(a,
b);
else if (b->type == XP_NUMBER)
evalLTE_DBL_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalLTE_DBL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_BOOLEAN)
if
(b->type == XP_NODESET)
evalLTE_BOL_NDS(a,
b);
else if (b->type == XP_STRING)
evalLTE_BOL_STR(a,
b);
else if (b->type == XP_NUMBER)
evalLTE_BOL_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalLTE_BOL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else
throw(XPE_BADOPERANDTYPE);
// Push (a <= b) onto the stack
// Get the next token
getEvalToken();
} // evalLTE
//---------------------------------------------------------------------
// Evaluate a < b
//
void CXPath::evalLT(void) {
// Compare the arguments
evalGTE();
// Reverse the sense of the result
evalStack->SetTOS(!evalStack->BoolAtTOS());
// Get the next token
getEvalToken();
} // evalLT
//---------------------------------------------------------------------
// Evaluate a - b
//
void CXPath::evalMinus(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack and convert it to numeric
PCXPathItem b = convertToNumber(evalStack->Pop());
// Pop a off the stack and convert it to numeric
PCXPathItem a = convertToNumber(evalStack->Pop());
// Push (a - b) onto the stack
evalStack->PushD(a->dValue - b->dValue);
// Get the next token
getEvalToken();
} // evalMinus
//---------------------------------------------------------------------
// Evaluate a mod b
//
// The mod operator returns the remainder from a truncating
// division. For example,
// * 5 mod 2 returns 1
// * 5 mod -2 returns 1
// * -5 mod 2 returns -1
// * -5 mod -2 returns -1
// NOTE: This is the same as the % operator in Java and ECMAScript.
// NOTE: This is not the same as the IEEE 754 remainder operation,
// which returns the remainder from a rounding division.
//
void CXPath::evalMod(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack and convert it to numeric
PCXPathItem b = convertToNumber(evalStack->Pop());
// Pop a off the stack and convert it to numeric
PCXPathItem a = convertToNumber(evalStack->Pop());
if (b->dValue == 0)
throw(XPE_DIVIDEBYZERO);
// Push (a mod b) onto the stack (TBD)
double mod = fmod(a->dValue, b->dValue);
evalStack->PushD(mod);
// Get the next token
getEvalToken();
} // evalMod
//---------------------------------------------------------------------
// Evaluate a * b
//
void CXPath::evalMul(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack and convert it to numeric
PCXPathItem b = convertToNumber(evalStack->Pop());
// Pop a off the stack and convert it to numeric
PCXPathItem a = convertToNumber(evalStack->Pop());
// Push (a * b) onto the stack
evalStack->PushD(a->dValue * b->dValue);
// Get the next token
getEvalToken();
} // evalMul
//---------------------------------------------------------------------
// Evaluate not a
//
void CXPath::evalNegate(void) {
if (evalStack->Number() < 1)
throw(XPE_WRONGNRARGUMENTS);
// Pop a off the stack and convert it to boolean
PCXPathItem a = convertToBoolean(evalStack->Pop());
// Push (not a) onto the stack
evalStack->PushB(~a->bValue);
// Get the next token
getEvalToken();
} // evalNegate
//---------------------------------------------------------------------
// Evaluate a <> b
//
void CXPath::evalNE(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack
PCXPathItem b = evalStack->Pop();
// Pop a off the stack
PCXPathItem a = evalStack->Pop();
// Compare the operands according to their type
if (a->type == XP_NODESET)
if
(b->type == XP_NODESET)
evalNE_NDS_NDS(a,
b);
else if (b->type == XP_STRING)
evalNE_NDS_STR(a,
b);
else if (b->type == XP_NUMBER)
evalNE_NDS_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalNE_NDS_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
else if (a->type == XP_STRING) {
if
(b->type == XP_NODESET)
evalEQ_NDS_STR(b,
a);
else if (b->type == XP_STRING)
evalEQ_STR_STR(a,
b);
else if (b->type == XP_NUMBER)
evalEQ_STR_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalEQ_STR_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
// Reverse the sense of the result
evalStack->SetTOS(!evalStack->BoolAtTOS());
}
else if (a->type == XP_NUMBER) {
if
(b->type == XP_NODESET)
evalEQ_NDS_DBL(b,
a);
else if (b->type == XP_STRING)
evalEQ_STR_DBL(b,
a);
else if (b->type == XP_NUMBER)
evalEQ_DBL_DBL(a,
b);
else if (b->type == XP_BOOLEAN)
evalEQ_DBL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
// Reverse the sense of the result
evalStack->SetTOS(!evalStack->BoolAtTOS());
}
else if (a->type == XP_BOOLEAN) {
if
(b->type == XP_NODESET)
evalEQ_NDS_BOL(b,
a);
else if (b->type == XP_STRING)
evalEQ_STR_BOL(b,
a);
else if (b->type == XP_NUMBER)
evalEQ_DBL_BOL(b,
a);
else if (b->type == XP_BOOLEAN)
evalEQ_BOL_BOL(a,
b);
else
throw(XPE_BADOPERANDTYPE);
// Reverse the sense of the result
evalStack->SetTOS(!evalStack->BoolAtTOS());
}
else
throw(XPE_BADOPERANDTYPE);
// Get the next token
getEvalToken();
} // evalNE
//---------------------------------------------------------------------
// Push a number onto the stack
//
void CXPath::evalNmbr(void) {
evalStack->PushD(StrToDouble(stoken+1));
getEvalToken();
} // evalNmbr
//---------------------------------------------------------------------
// Evaluate a or b
//
void CXPath::evalOr(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack and convert it to boolean
PCXPathItem b = convertToBoolean(evalStack->Pop());
// Pop a off the stack and convert it to boolean
PCXPathItem a = convertToBoolean(evalStack->Pop());
// Push (a or b) onto the stack
evalStack->PushB(a->bValue | b->bValue);
// Get the next token
getEvalToken();
} // evalOr
//---------------------------------------------------------------------
//
void CXPath::evalPath(void) {
PCXPathItem item = evalStack->Pop();
if (item->type != XP_NODESET)
throw(XPE_NODESETEXPECTED);
item->node = item->nValue->Item(0);
item->position = 1;
// will have to check the direction???
item->size = item->nValue->Length();
ctxtStack->PushX(item);
getEvalToken();
} // evalPath
//---------------------------------------------------------------------
// Evaluate a + b
//
void CXPath::evalPlus(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack and convert it to numeric
PCXPathItem b = convertToNumber(evalStack->Pop());
// Pop a off the stack and convert it to numeric
PCXPathItem a = convertToNumber(evalStack->Pop());
// Push (a + b) onto the stack
evalStack->PushD(a->dValue + b->dValue);
// Get the next token
getEvalToken();
} // evalPlus
//---------------------------------------------------------------------
//
void CXPath::evalQuotedString(void) {
for (Pchar p = stoken; *p; p++)
if (uchar(*p) == XP_SPACE)
*p = ' ';
evalStack->PushS(stoken+1);
// Get the next token
getEvalToken();
} // evalQuotedString
//---------------------------------------------------------------------
//
void CXPath::evalRoot(void) {
// Push the root node onto the context stack
PCNode document = TYPECAST(node->OwnerDocument(),
Node);
ctxtStack->PushN(document);
// Get the next token
getEvalToken();
} // evalRoot
//---------------------------------------------------------------------
// Evaluate the step
//
void CXPath::evalStep(void) {
Assert(op == XP_AXISNAME);
// Save the axisName token
char axisName[sizeName];
Strcpy(axisName, stoken, sizeName);
// Save the quoted string (for processing-instruction)
getEvalToken();
char qstring[sizeLine];
qstring[0] = 0;
if (op == XP_QUOTEDSTR) {
Strcpy(qstring, stoken, sizeLine);
getEvalToken();
}
// Save the nodeTest token
if (op != XP_NODETYPE &&
op != XP_QNAME
&&
op != XP_ALL
&&
op != XP_ALLNAME)
throw(XPE_OPNOTEXPECTED);
char nodeTest[sizeLine];
Strcpy(nodeTest, stoken, sizeLine);
// Validate quoted string
if (!StrEmpty(qstring) &&
strcmp(stoken+1, "proceessing-instruction")
!= 0)
throw(XPE_PROCINSTEXPECTED);
// Copy the parsed predicate into separate string objects,
adding
// each to my predicate list. Include nested predicates
PCStrList predicates = new CStrList();
char work[sizeString];
getEvalToken();
while (op == XP_LBOX) {
work[0] = 0;
int iPred = 1;
getEvalToken();
if
(op == XP_RBOX)
iPred--;
else if (op == XP_LBOX)
iPred++;
while (iPred != 0) {
ChrCat(work, '
', sizeString);
Strcat(work, stoken,
sizeString);
getEvalToken();
if
(op == XP_RBOX)
iPred--;
else if (op ==
XP_LBOX)
iPred++;
}
predicates->StrInsert(work);
getEvalToken();
}
// Evaluate the step------------------------------------------------
if (ctxtStack->Empty())
Assert(XPE_STACKEMPTY);
PCXPathItem context = ctxtStack->ItemAtTOS();
if (!context || context->type != XP_NODESET)
throw(XPE_NODESETEXPECTED);
// For each node in context.nodeset, traverse the DOM,
putting the
// keepers in the rslts nodelist
PCNodeList rslts = new CNodeList();
PCNodeList nodes = context->nValue;
for (int i = 0; i < nodes->Length(); i++) {
PCNodeList finds = travelOnAxis(nodes->Item(i),
axisName,
nodeTest);
// For each predicate, evaluate the
predicate against the
// per-node traversal results.
if (finds->Length() > 0 &&
predicates->GotoHead()) do {
char exp[sizeString];
predicates->StrItem(exp,
sizeString);
finds = evalPredicate(finds,
exp, down);
Assert(finds);
} while (predicates->GotoNext());
// Collect the results of the predicate
filtering
for (int j = 0; j < finds->Length();
j++) {
PCNode node =
finds->Item(j);
rslts->InsertNode(node);
}
}
// Push the resulting NodeList onto the stack
evalStack->PushNL(rslts);
} // evalStep
//---------------------------------------------------------------------
//
//
PCNodeList CXPath::evalPredicate(RPCNodeList _nodes,
Pchar _exp,
direction _order) {
PCNodeList rslts = new CNodeList();
// Save the pre-predicate expression state
int hiExp = iExp;
PCRecord hExp = new CRecord(exp);
ushort hop = op;
char htoken[sizeLine];
Strcpy(htoken, stoken, sizeLine);
// Evaluate the predicate expression for each node
in the CNodeList
for (int i = 0; i < _nodes->Length(); i++) {
PCXPathItem item;
if (_order == down)
item = ctxtStack->PushN(_nodes->Item(i));
else
item = ctxtStack->PushN(_nodes->Item(_nodes->Length()-i-1));
{ // need to keep the following in
the stack context object:
// context node
item->node
=_nodes->Item(i);
// context position
(=i+1)
item->position
= i+1;
// context size
item->size
=_nodes->Length();
}
// Evaluate the predicate expression
eval(_exp);
// Is the current node a keeper?
item = evalStack->Pop();
if
(item->type == XP_BOOLEAN) {
if (item->bValue)
rslts->InsertNode(_nodes->Item(i));
}
else if (item->type == XP_NUMBER)
{
if (long(item->dValue)
== i+1)
rslts->InsertNode(_nodes->Item(i));
}
else {
item = convertToBoolean(item);
if (item->bValue)
rslts->InsertNode(_nodes->Item(i));
}
ctxtStack->Pop();
}
// restore the pre-predicate expression state
strcpy(stoken, htoken);
op
= hop;
iExp
= hiExp;
exp
= hExp;
return rslts;
} // evalPredicate
//---------------------------------------------------------------------
// Evaluate -a
//
void CXPath::evalUnaryMinus(void) {
if (evalStack->Number() < 1)
throw(XPE_WRONGNRARGUMENTS);
// Pop a off the stack and convert it to numeric
PCXPathItem a = convertToNumber(evalStack->Pop());
// Push (-a) onto the stack
evalStack->PushD(-a->dValue);
// Get the next token
getEvalToken();
} // evalUnaryMinus
//---------------------------------------------------------------------
// Evaluate a union b
//
void CXPath::evalUnion(void) {
if (evalStack->Number() < 2)
throw(XPE_WRONGNRARGUMENTS);
// Pop b off the stack
// Pop a off the stack
// Push (a union b) onto the stack
// Get the next token
getEvalToken();
} // evalUnion
//---------------------------------------------------------------------
//
void CXPath::evalUnwind(void) {
// Unwind the context stack
ushort steps = StrToShort(stoken+1);
for (ushort i = steps; i; i--)
ctxtStack->Pop();
// Get the next token
getEvalToken();
} // evalUnwind
//---------------------------------------------------------------------
// Intend that an XPath variable is a farSlang global.
//
void CXPath::evalVariable(void) {
// TBD
// Get the next token
getEvalToken();
} // evalVariable
//=====================================================================
// Comparison evaluators
//=====================================================================
//=====================================================================
// evalEqual methods
//=====================================================================
//---------------------------------------------------------------------
// True if any node in a is equal to any node in b (intersection
not
// empty)
//
void CXPath::evalEQ_NDS_NDS(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NODESET);
for (int i = 0; i < _a->nValue->Length(); i++) {
Pchar valA = stringValue(_a->nValue->Item(i));
for (int j = 0; j < _b->nValue->Length();
j++) {
Pchar valB = stringValue(_b->nValue->Item(j));
if
(StrEmpty(valA) &&
StrEmpty(valB)) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA)
&&
!StrEmpty(valB) &&
strcmp(valA, valB) == 0) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
delete[] valB;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalEQ_NDS_NDS
//---------------------------------------------------------------------
// True if the string value of any node is equal to b
//
void CXPath::evalEQ_NDS_STR(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_STRING);
Pchar valB = _b->sValue;
// Traverse the nodelist looking for a match
for (int i = 0; i < _a->nValue->Length(); i++)
{
Pchar valA = stringValue(_a->nValue->Item(i));
if
(StrEmpty(valA) &&
StrEmpty(valB)) {
delete[] valA;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA) &&
!StrEmpty(valB) &&
strcmp(valA, valB) == 0) {
delete[] valA;
evalStack->PushB(true);
return;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalEQ_NDS_STR
//---------------------------------------------------------------------
// True if the number value of any node in a is equal to b
//
void CXPath::evalEQ_NDS_DBL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NUMBER);
double valB = _b->dValue;
for (int i = 0; i < _a->nValue->Length(); i++) {
double valA = numberValue(_a->nValue->Item(i));
if (valA == valB) {
evalStack->PushB(true);
return;
}
}
evalStack->PushB(false);
} // evalEQ_NDS_DBL
//---------------------------------------------------------------------
// True if the boolean value of the node set in a is equal to b
//
void CXPath::evalEQ_NDS_BOL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_BOOLEAN);
bool valB = _b->bValue;
if (_a->nValue->Length()
> 0 && valB) {
evalStack->PushB(true);
return;
}
else if (_a->nValue->Length() == 0 && !valB)
{
evalStack->PushB(true);
return;
}
evalStack->PushB(false);
} // evalEQ_NDS_BOL
//---------------------------------------------------------------------
// True if the specified strings are equal.
//
void CXPath::evalEQ_STR_STR(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_STRING);
evalStack->PushB(strcmp(_a->sValue, _b->sValue) ==
0);
} // evalEQ_STR_STR
//---------------------------------------------------------------------
// True if the converted string is equal to the number
//
void CXPath::evalEQ_STR_DBL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(StrToDouble(_a->sValue) == _b->dValue);
} // evalEQ_STR_DBL
//---------------------------------------------------------------------
// True if the converted string is equal to the boolean
//
void CXPath::evalEQ_STR_BOL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(convertToBoolean(_a)->bValue == _b->bValue);
} // evalEQ_STR_BOL
//---------------------------------------------------------------------
// True if the specified numbers are equal
//
void CXPath::evalEQ_DBL_DBL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(_a->dValue == _b->dValue);
} // evalEQ_DBL_DBL
//---------------------------------------------------------------------
// True if the converted number is equal to the boolean
//
void CXPath::evalEQ_DBL_BOL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(convertToBoolean(_a)->bValue == _b->bValue);
} // evalEQ_DBL_BOL
//---------------------------------------------------------------------
// True if the specified booleans are equal
//
void CXPath::evalEQ_BOL_BOL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(_a->bValue == _b->bValue);
} // evalEQ_BOL_BOL
//=====================================================================
// evalNotEqual methods
//=====================================================================
//---------------------------------------------------------------------
// True if no node in a is equal to any node in b (intersection
empty)
//
void CXPath::evalNE_NDS_NDS(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NODESET);
for (int i = 0; i < _a->nValue->Length(); i++) {
Pchar valA = stringValue(_a->nValue->Item(i));
for (int j = 0; j < _b->nValue->Length();
j++) {
Pchar valB = stringValue(_b->nValue->Item(j));
if
(!StrEmpty(valA) &&
StrEmpty(valB)) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
else if (StrEmpty(valA)
&&
!StrEmpty(valB)) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
else if (strcmp(valA,
valB) != 0) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
delete[] valB;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalNE_NDS_NDS
//---------------------------------------------------------------------
// True if the string value of the node set is not equal to the
// specified string
//
void CXPath::evalNE_NDS_STR(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_STRING);
Pchar valB = _b->sValue;
for (int i = 0; i < _a->nValue->Length(); i++) {
Pchar valA = stringValue(_a->nValue->Item(i));
if
(!StrEmpty(valA) &&
StrEmpty(valB)) {
delete[] valA;
evalStack->PushB(true);
return;
}
else if (StrEmpty(valA) &&
!StrEmpty(valB)) {
delete[] valA;
evalStack->PushB(true);
return;
}
else if (strcmp(valA, valB) != 0)
{
delete[] valA;
evalStack->PushB(true);
return;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalNE_NDS_STR
//---------------------------------------------------------------------
// True if the number value of the node set is not equal to the
// specified number
//
void CXPath::evalNE_NDS_DBL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NUMBER);
double valB = _b->dValue;
for (int i = 0; i < _a->nValue->Length(); i++) {
double valA = numberValue(_a->nValue->Item(i));
if (valA != valB) {
evalStack->PushB(true);
return;
}
}
evalStack->PushB(false);
} // evalNE_NDS_DBL
//---------------------------------------------------------------------
// True if the boolean value of the node set is not equal to the
// specified boolean
//
void CXPath::evalNE_NDS_BOL(RPCXPathItem _a, RPCXPathItem _b) {
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_BOOLEAN);
bool valB = _b->bValue;
if (_a->nValue->Length()
> 0 && !valB) {
evalStack->PushB(true);
return;
}
else if (_a->nValue->Length() == 0 &&
valB) {
evalStack->PushB(true);
return;
}
evalStack->PushB(false);
} // evalNE_NDS_BOL
//=====================================================================
// evalGTE methods
//=====================================================================
//---------------------------------------------------------------------
//
void CXPath::evalGTE_NDS_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NODESET);
for (int i = 0; i < _a->nValue->Length(); i++) {
Pchar valA = stringValue(_a->nValue->Item(i));
for (int j = 0; j < _b->nValue->Length();
j++) {
Pchar valB = stringValue(_b->nValue->Item(j));
if
(StrEmpty(valB)) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA)
&&
!StrEmpty(valB) &&
strcmp(valA, valB) >= 0) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
delete[] valB;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalGTE_NDS_NDS
//---------------------------------------------------------------------
//
void CXPath::evalGTE_NDS_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_STRING);
Pchar valB = _b->sValue;
for (int i = 0; i < _a->nValue->Length(); i++) {
Pchar valA = stringValue(_a->nValue->Item(i));
if
(StrEmpty(valB)) {
delete[] valA;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA) &&
!StrEmpty(valB) &&
strcmp(valA, valB) >= 0) {
delete[] valA;
evalStack->PushB(true);
return;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalGTE_NDS_STR
//---------------------------------------------------------------------
//
void CXPath::evalGTE_NDS_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NUMBER);
double valB = _b->dValue;
for (int i = 0; i < _a->nValue->Length(); i++) {
double valA = numberValue(_a->nValue->Item(i));
if (valA >= valB) {
evalStack->PushB(true);
return;
}
}
evalStack->PushB(false);
} // evalGTE_NDS_DBL
//---------------------------------------------------------------------
//
void CXPath::evalGTE_NDS_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_BOOLEAN);
bool valB = _b->bValue;
if (!valB || _a->nValue->Length()
> 0) {
evalStack->PushB(true);
return;
}
evalStack->PushB(false);
} // evalGTE_NDS_BOL
//---------------------------------------------------------------------
//
void CXPath::evalGTE_STR_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_NODESET);
Pchar valA = _a->sValue;
for (int i = 0; i < _b->nValue->Length(); i++) {
Pchar valB = stringValue(_b->nValue->Item(i));
if
(StrEmpty(valB)) {
delete[] valB;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA) &&
!StrEmpty(valB) &&
strcmp(valA, valB) >= 0) {
delete[] valB;
evalStack->PushB(true);
return;
}
delete[] valB;
}
evalStack->PushB(false);
} // evalGTE_STR_NDS
//---------------------------------------------------------------------
//
void CXPath::evalGTE_STR_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_STRING);
evalStack->PushB(strcmp(_a->sValue, _b->sValue) >=
0);
} // evalGTE_STR_STR
//---------------------------------------------------------------------
//
void CXPath::evalGTE_STR_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(StrToDouble(_a->sValue) >= _b->dValue);
} // evalGTE_STR_DBL
//---------------------------------------------------------------------
//
void CXPath::evalGTE_STR_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(convertToBoolean(_a)->bValue >= _b->bValue);
} // evalGTE_STR_BOL
//---------------------------------------------------------------------
//
void CXPath::evalGTE_DBL_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_NUMBER);
double valA = _a->dValue;
for (int i = 0; i < _b->nValue->Length(); i++) {
double valB = numberValue(_b->nValue->Item(i));
if (valA >= valB) {
evalStack->PushB(true);
return;
}
}
evalStack->PushB(false);
} // evalGTE_DBL_NDS
//---------------------------------------------------------------------
//
void CXPath::evalGTE_DBL_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_STRING);
evalStack->PushB(_a->dValue >= StrToDouble(_b->sValue));
} // evalGTE_DBL_STR
//---------------------------------------------------------------------
//
void CXPath::evalGTE_DBL_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(_a->dValue >= _b->dValue);
} // evalGTE_DBL_DBL
//---------------------------------------------------------------------
//
void CXPath::evalGTE_DBL_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(convertToBoolean(_a)->bValue >= _b->bValue);
} // evalGTE_DBL_BOL
//---------------------------------------------------------------------
//
void CXPath::evalGTE_BOL_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_NODESET);
bool valA = _a->bValue;
if (valA || _b->nValue->Length()
== 0) {
evalStack->PushB(true);
return;
}
evalStack->PushB(false);
} // evalGTE_BOL_NDS
//---------------------------------------------------------------------
//
void CXPath::evalGTE_BOL_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_STRING);
evalStack->PushB(_a->bValue >= convertToBoolean(_b)->bValue);
} // evalGTE_BOL_STR
//---------------------------------------------------------------------
//
void CXPath::evalGTE_BOL_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(_a->bValue >= convertToBoolean(_b)->bValue);
} // evalGTE_BOL_DBL
//---------------------------------------------------------------------
//
void CXPath::evalGTE_BOL_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(_a->bValue >= _b->bValue);
} // evalGTE_BOL_BOL
//=====================================================================
// evalLTE methods
//=====================================================================
//---------------------------------------------------------------------
//
void CXPath::evalLTE_NDS_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NODESET);
for (int i = 0; i < _a->nValue->Length(); i++) {
Pchar valA = stringValue(_a->nValue->Item(i));
for (int j = 0; j < _b->nValue->Length();
j++) {
Pchar valB = stringValue(_b->nValue->Item(j));
if
(StrEmpty(valA)) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA)
&&
!StrEmpty(valB) &&
strcmp(valA, valB) <= 0) {
delete[] valA;
delete[] valB;
evalStack->PushB(true);
return;
}
delete[] valB;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalLTE_NDS_NDS
//---------------------------------------------------------------------
//
void CXPath::evalLTE_NDS_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_STRING);
Pchar valB = _b->sValue;
for (int i = 0; i < _a->nValue->Length(); i++) {
Pchar valA = stringValue(_a->nValue->Item(i));
if
(StrEmpty(valA)) {
delete[] valA;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA) &&
!StrEmpty(valB) &&
strcmp(valA, valB) <= 0) {
delete[] valA;
evalStack->PushB(true);
return;
}
delete[] valA;
}
evalStack->PushB(false);
} // evalLTE_NDS_STR
//---------------------------------------------------------------------
//
void CXPath::evalLTE_NDS_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_NUMBER);
double valB = _b->dValue;
for (int i = 0; i < _a->nValue->Length(); i++) {
double valA = numberValue(_a->nValue->Item(i));
if (valA <= valB) {
evalStack->PushB(true);
return;
}
}
evalStack->PushB(false);
} // evalLTE_NDS_DBL
//---------------------------------------------------------------------
//
void CXPath::evalLTE_NDS_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NODESET);
Assert(_b->type == XP_BOOLEAN);
bool valB = _b->bValue;
if (valB || _a->nValue->Length()
== 0) {
evalStack->PushB(true);
return;
}
evalStack->PushB(false);
} // evalLTE_NDS_BOL
//---------------------------------------------------------------------
//
void CXPath::evalLTE_STR_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_NODESET);
Pchar valA = _a->sValue;
for (int i = 0; i < _b->nValue->Length(); i++) {
Pchar valB = stringValue(_b->nValue->Item(i));
if
(StrEmpty(valA)) {
delete[] valB;
evalStack->PushB(true);
return;
}
else if (!StrEmpty(valA) &&
!StrEmpty(valB) &&
strcmp(valA, valB) <= 0) {
delete[] valB;
evalStack->PushB(true);
return;
}
delete[] valB;
}
evalStack->PushB(false);
} // evalLTE_STR_NDS
//---------------------------------------------------------------------
//
void CXPath::evalLTE_STR_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_STRING);
evalStack->PushB(strcmp(_a->sValue, _b->sValue) <=
0);
} // evalLTE_STR_STR
//---------------------------------------------------------------------
//
void CXPath::evalLTE_STR_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(StrToDouble(_a->sValue) <= _b->dValue);
} // evalLTE_STR_DBL
//---------------------------------------------------------------------
//
void CXPath::evalLTE_STR_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_STRING);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(convertToBoolean(_a)->bValue <=
_b->bValue);
} // evalLTE_STR_BOL
//---------------------------------------------------------------------
//
void CXPath::evalLTE_DBL_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_NUMBER);
double valA = _a->dValue;
for (int i = 0; i < _b->nValue->Length(); i++) {
double valB = numberValue(_b->nValue->Item(i));
if (valA <= valB) {
evalStack->PushB(true);
return;
}
}
evalStack->PushB(false);
} // evalLTE_DBL_NDS
//---------------------------------------------------------------------
//
void CXPath::evalLTE_DBL_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_STRING);
evalStack->PushB(_a->dValue <= StrToDouble(_b->sValue));
} // evalLTE_DBL_STR
//---------------------------------------------------------------------
//
void CXPath::evalLTE_DBL_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(_a->dValue <= _b->dValue);
} // evalLTE_DBL_DBL
//---------------------------------------------------------------------
//
void CXPath::evalLTE_DBL_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_NUMBER);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(convertToBoolean(_a)->bValue <=
_b->bValue);
} // evalLTE_DBL_BOL
//---------------------------------------------------------------------
//
void CXPath::evalLTE_BOL_NDS(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_NODESET);
bool valA = _a->bValue;
if (!valA || _b->nValue->Length()
> 0) {
evalStack->PushB(true);
return;
}
evalStack->PushB(false);
} // evalLTE_BOL_NDS
//---------------------------------------------------------------------
//
void CXPath::evalLTE_BOL_STR(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_STRING);
evalStack->PushB(_a->bValue <= convertToBoolean(_b)->bValue);
} // evalLTE_BOL_STR
//---------------------------------------------------------------------
//
void CXPath::evalLTE_BOL_DBL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_NUMBER);
evalStack->PushB(_a->bValue <= convertToBoolean(_b)->bValue);
} // evalLTE_BOL_DBL
//---------------------------------------------------------------------
//
void CXPath::evalLTE_BOL_BOL(RPCXPathItem _a, RPCXPathItem _b)
{
Assert(_a->type == XP_BOOLEAN);
Assert(_b->type == XP_BOOLEAN);
evalStack->PushB(_a->bValue <= _b->bValue);
} // evalLTE_BOL_BOL
//=====================================================================
// Core Functions
//
// check for a special item on the stack that indicates that all
the
// parameters have been consumed
//
//=====================================================================
//---------------------------------------------------------------------
// Boolean functions
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// Function: boolean boolean(object)
//
// The boolean function converts its argument to a boolean as follows:
// * a number is true if and only if it is neither
positive or
// negative zero nor NaN
// * a node-set is true if and only if it is
non-empty
// * a string is true if and only if its length
is non-zero
// * an object of a type other than the four
basic types is
// converted to a boolean in a way
that is dependent on that type
//
void CXPath::evalBoolean(void) {
// Obtain the arguments
PCXPathItem p;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (!p)
p = item;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 1)
throw(XPE_WRONGNRARGUMENTS);
if (evalStack->Number() < 2)
Assert(XPE_STACKEMPTY);
evalStack->PushX(convertToBoolean(evalStack->Pop()));
} // evalBoolean
//---------------------------------------------------------------------
// Function: boolean not(boolean)
//
// The not function returns true if its argument is false, and
false
// otherwise.
//
void CXPath::evalNot(void) {
// Obtain the argument
PCXPathItem p;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_BOOLEAN &&
!p)
p = item;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 1)
throw(XPE_WRONGNRARGUMENTS);
evalStack->PushB(!(p->bValue));
} // evalNot
//---------------------------------------------------------------------
// Function: boolean true()
//
// The true function returns true.
//
void CXPath::evalTrue(void) {
// Obtain the argument
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 0)
throw(XPE_WRONGNRARGUMENTS);
item = new CXPathItem(bool(true));
evalStack->PushX(item);
} // evalTrue
//---------------------------------------------------------------------
// Function: boolean false()
//
// The false function returns false.
//
void CXPath::evalFalse(void) {
// Obtain the argument
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 0)
throw(XPE_WRONGNRARGUMENTS);
item = new CXPathItem(bool(false));
evalStack->PushX(item);
} // evalFalse
//---------------------------------------------------------------------
// Number functions
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// Function: number number(object?)
//
// The number function converts its argument to a number as follows:
// * a string that consists of optional whitespace
followed by an
// optional minus sign followed by
a Number followed by whitespace
// is converted to the IEEE 754 number
that is nearest (according
// to the IEEE 754 round-to-nearest
rule) to the mathematical
// value represented by the string;
any other string is converted
// to NaN
// * boolean true is converted to 1; boolean
false is converted to 0
// * a node-set is first converted to a string
as if by a call to
// the string function and then converted
in the same way as a
// string argument
// * an object of a type other than the four
basic types is
// converted to a number in a way
that is dependent on that type
//
// If the argument is omitted, it defaults to a node-set with the
// context node as its only member.
//
// NOTE: The number function should not be used for conversion
of
// numeric data occurring in an element in an XML document unless
the
// element is of a type that represents numeric data in a language-
// neutral format (which would typically be transformed into a
// language-specific format for presentation to a user). In addition,
// the number function cannot be used unless the language-neutral
// format used by the element is consistent with the XPath syntax
for a
// Number.
//
void CXPath::evalNumber(void) {
// Obtain the arguments
PCXPathItem p;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (!p)
p = item;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs > 1)
throw(XPE_WRONGNRARGUMENTS);
if (!p) {
if (ctxtStack->Empty())
throw(XPE_CONTEXTEXPECTED);
p = ctxtStack->ItemAtTOS();
}
evalStack->PushX(convertToNumber(p));
} // evalNumber
//---------------------------------------------------------------------
// Function: number sum(node-set)
//
// The sum function returns the sum, for each node in the argument
// node-set, of the result of converting the string-values of the
node
// to a number.
//
void CXPath::evalSum(void) {
// Obtain the argument
PCNodeList p;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_NODESET)
p = item->nValue;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 1)
throw(XPE_WRONGNRARGUMENTS);
ulong sum
= 0;
PCNodeList nodes = evalStack->Pop()->nValue;
for (int i = 0; i < nodes->Length(); i++) {
PCNode node = nodes->Item(i);
sum += numberValue(node);
}
evalStack->PushD(sum);
} // evalSum
//---------------------------------------------------------------------
// Function: number floor(number)
//
// The floor function returns the largest (closest to positive
// infinity) number that is not greater than the argument and that
is
// an integer.
//
void CXPath::evalFloor(void) {
// Obtain the argument
double p = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_NUMBER)
p = item->dValue;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 1)
throw(XPE_WRONGNRARGUMENTS);
evalStack->PushD(floor(p));
} // evalFloor
//---------------------------------------------------------------------
// Function: number ceiling(number)
//
// The ceiling function returns the smallest (closest to negative
// infinity) number that is not less than the argument and that
is an
// integer.
//
void CXPath::evalCeiling(void) {
// Obtain the argument
double p = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_NUMBER)
p = item->dValue;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 1)
throw(XPE_WRONGNRARGUMENTS);
evalStack->PushD(ceil(p));
} // evalCeiling
//---------------------------------------------------------------------
// Function: number round(number)
//
// The round function returns the number that is closest to the
// argument and that is an integer. If there are two such numbers,
then
// the one that is closest to positive infinity is returned. If
the
// argument is NaN, then NaN is returned. If the argument is positive
// infinity, then positive infinity is returned. If the argument
is
// negative infinity, then negative infinity is returned. If the
// argument is positive zero, then positive zero is returned. If
the
// argument is negative zero, then negative zero is returned. If
the
// argument is less than zero, but greater than or equal to -0.5,
then
// negative zero is returned.
//
// NOTE: For these last two cases, the result of calling the round
// function is not the same as the result of adding 0.5 and then
// calling the floor function.
//
void CXPath::evalRound(void) {
// Obtain the argument
double p = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_NUMBER)
p = item->dValue;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 1)
throw(XPE_WRONGNRARGUMENTS);
if (p == +0.0)
p = +0.0;
else if (p == -0.0)
p = -0.0;
else if (p < 0.0 && p >= -0.5)
p = -0.0;
else
p = floor(p + 0.5);
evalStack->PushD(p);
} // evalRound
//---------------------------------------------------------------------
// String functions
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// Function: string string(object?)
//
// The string function converts an object to a string as follows:
// * A node-set is converted to a string by returning
the string-
// value of the node in the node-set
that is first in document
// order. If the node-set is empty,
an empty string is returned.
// * A number is converted to a string as follows
// o NaN is converted to the
string NaN
// o positive zero is converted
to the string 0
// o negative zero is converted
to the string 0
// o positive infinity is converted
to the string Infinity
// o negative infinity is converted
to the string -Infinity
// o if the number is an integer,
the number is represented in
// decimal form
as a Number with no decimal point and no
// leading zeros,
preceded by a minus sign (-) if the number is
// negative
// o otherwise, the number
is represented in decimal form as a
// Number including
a decimal point with at least one digit
// before the decimal
point and at least one digit after the
// decimal point,
preceded by a minus sign (-) if the number is
// negative; there
must be no leading zeros before the decimal
// point apart
possibly from the one required digit immediately
// before the decimal
point; beyond the one required digit
// after the decimal
point there must be as many, but only as
// many, more digits
as are needed to uniquely distinguish the
// number from
all other IEEE 754 numeric values.
// * The boolean false value is converted to
the string false. The
// boolean true value is converted
to the string true.
// * An object of a type other than the four
basic types is
// converted to a string in a way
that is dependent on that type.
//
// If the argument is omitted, it defaults to a node-set with the
// context node as its only member.
//
// NOTE: The string function is not intended for converting numbers
// into strings for presentation to users. The format-number function
// and xsl:number element in [XSLT] provide this functionality.
//
void CXPath::evalString(void) {
// Obtain the arguments
PCXPathItem p;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (!p)
p = item;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs > 1)
throw(XPE_WRONGNRARGUMENTS);
if (!p) {
if (ctxtStack->Empty())
throw(XPE_CONTEXTEXPECTED);
p = ctxtStack->ItemAtTOS();
}
evalStack->PushX(convertToString(p));
} // evalString
//---------------------------------------------------------------------
// Function: string concat(string, string, string*)
//
// The concat function returns the concatenation of its arguments.
//
void CXPath::evalConcat(void) {
// Obtain the arguments
PCStrList list = new CStrList();
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING)
list ->StrInsert(item->sValue,
atTop);
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs < 2)
throw(XPE_WRONGNRARGUMENTS);
ulong size = list->ListSize();
Pchar str = new char[size];
memset(str, 0, size);
Pchar p = str;
if (list->GotoHead()) do {
Pchar q = list->StrItem();
strcpy(p, q);
p
+= strlen(q);
} while (list->GotoNext());
evalStack->PushS(str);
delete[] str;
} // evalConcat
//---------------------------------------------------------------------
// Function: boolean starts-with(string, string)
//
// The starts-with function returns true if the first argument
string
// starts with the second argument string, and otherwise returns
false.
//
void CXPath::evalStarts_with(void) {
// Obtain the arguments
Pchar a = 0;
Pchar b = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING)
if
(!b) {
b = new char[strlen(item->sValue)+1];
strcpy(b, item->sValue);
}
else if (!a) {
a = new char[strlen(item->sValue)+1];
strcpy(a, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 2)
throw(XPE_WRONGNRARGUMENTS);
// Restriction: can't handle sub-strings larger than
sizeString
char work[sizeString];
evalStack->PushB(StrPos(b, a) == 0);
delete[] a;
delete[] b;
} // evalStarts_with
//---------------------------------------------------------------------
// Function: boolean contains(string, string)
//
// The contains function returns true if the first argument string
// contains the second argument string, and otherwise returns false.
//
void CXPath::evalContains(void) {
// Obtain the arguments
Pchar a = 0;
Pchar b = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING)
if
(!b) {
b = new char[strlen(item->sValue)+1];
strcpy(b, item->sValue);
}
else if (!a) {
a = new char[strlen(item->sValue)+1];
strcpy(a, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 2)
throw(XPE_WRONGNRARGUMENTS);
// Restriction: can't handle sub-strings larger than
sizeString
char work[sizeString];
evalStack->PushB(StrPos(b, a) >= 0);
delete[] a;
delete[] b;
} // evalContains
//---------------------------------------------------------------------
// Function: string substring-before(string, string)
//
// The substring-before function returns the substring of the first
// argument string that precedes the first occurrence of the second
// argument string in the first argument string, or the empty string
if
// the first argument string does not contain the second argument
// string. For example, substring-before("1999/04/01","/") returns
// 1999.
//
void CXPath::evalSubstring_before(void) {
// Obtain the arguments
Pchar a = 0;
Pchar b = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING)
if
(!b) {
b = new char[strlen(item->sValue)+1];
strcpy(b, item->sValue);
}
else if (!a) {
a = new char[strlen(item->sValue)+1];
strcpy(a, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 2)
throw(XPE_WRONGNRARGUMENTS);
// Restriction: can't handle sub-strings larger than
sizeString
char work[sizeString];
Before(b, a, work, sizeString);
evalStack->PushS(work);
delete[] a;
delete[] b;
} // evalSubstring_before
//---------------------------------------------------------------------
// Function: string substring-after(string, string)
//
// The substring-after function returns the substring of the first
// argument string that follows the first occurrence of the second
// argument string in the first argument string, or the empty string
if
// the first argument string does not contain the second argument
// string. For example, substring-after("1999/04/01","/") returns
// 04/01, and substring-after("1999/04/01","19") returns 99/04/01.
//
void CXPath::evalSubstring_after(void) {
// Obtain the arguments
Pchar a = 0;
Pchar b = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING)
if
(!b) {
b = new char[strlen(item->sValue)+1];
strcpy(b, item->sValue);
}
else if (!a) {
a = new char[strlen(item->sValue)+1];
strcpy(a, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 2)
throw(XPE_WRONGNRARGUMENTS);
// Restriction: can't handle sub-strings larger than
sizeString
char work[sizeString];
After(b, a, work, sizeString);
evalStack->PushS(work);
delete[] a;
delete[] b;
} // evalSubstring_after
//---------------------------------------------------------------------
// Function: string substring(string, number, number?)
//
// The substring function returns the substring of the first argument
// starting at the position specified in the second argument with
// length specified in the third argument. For example,
// substring("12345",2,3) returns "234". If the third argument
is not
// specified, it returns the substring starting at the position
// specified in the second argument and continuing to the end of
the
// string. For example, substring("12345",2) returns "2345".
//
// More precisely, each character in the string (see [3.6 Strings])
is
// considered to have a numeric position: the position of the first
// character is 1, the position of the second character is 2 and
so on.
//
// NOTE: This differs from Java and ECMAScript, in which the
// String.substring method treats the position of the first character
// as 0.
//
// The returned substring contains those characters for which the
// position of the character is greater than or equal to the rounded
// value of the second argument and, if the third argument is
// specified, less than the sum of the rounded value of the second
// argument and the rounded value of the third argument; the
// comparisons and addition used for the above follow the standard
// IEEE 754 rules; rounding is done as if by a call to the round
// function. The following examples illustrate various unusual
cases:
// * substring("12345", 1.5, 2.6) returns "234"
// * substring("12345", 0, 3) returns "12"
// * substring("12345", 0 div 0, 3) returns ""
// * substring("12345", 1, 0 div 0) returns ""
// * substring("12345", -42, 1 div 0) returns
"12345"
// * substring("12345", -1 div 0, 1 div 0) returns
""
//
void CXPath::evalSubstring(void) {
// Obtain the arguments from the evaluation stack
Pchar p = 0;
double begin = -1.0;
double size = -1.0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if
(item->type == XP_NUMBER) {
if
(size < 0.0)
size = item->dValue;
else if (begin
< 0.0)
begin = item->dValue;
}
else if (item->type == XP_STRING
&& !p) {
p = new char[strlen(item->sValue)+1];
strcpy(p, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs > 3)
throw(XPE_WRONGNRARGUMENTS);
// Check if there is a string to work with
if (!p) {
evalStack->PushS("");
return;
}
// Provide a size if no third parameter
if (nrArgs == 2)
size = strlen(p);
// Copy the substring
ushort sz = _ROUND(begin) + _ROUND(size);
ushort i;
ushort j = 0;
for (i = 1; p[i-1] && i < sz; i++)
if (i >= _ROUND(begin))
p[j++] = p[i-1];
p[j] = 0;
evalStack->PushS(p);
delete[] p;
} // evalSubstring
//---------------------------------------------------------------------
// Function: number string-length(string?)
//
// The string-length returns the number of characters in the string
// (see [3.6 Strings]). If the argument is omitted, it defaults
to the
// context node converted to a string, in other words the string-value
// of the context node.
//
void CXPath::evalString_length(void) {
// Obtain the argument
Pchar p = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING &&
!p) {
p = new char[strlen(item->sValue)+1];
strcpy(p, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs > 1)
throw(XPE_WRONGNRARGUMENTS);
// Default to the string value of the context node
if (!p) {
if (ctxtStack->Empty())
throw(XPE_CONTEXTEXPECTED);
item = convertToString(ctxtStack->ItemAtTOS());
p = new char[strlen(item->sValue)+1];
strcpy(p, item->sValue);
}
evalStack->PushD(strlen(p));
delete[] p;
} // evalString_length
//---------------------------------------------------------------------
// Function: string normalize-space(string?)
//
// The normalize-space function returns the argument string with
// whitespace normalized by stripping leading and trailing whitespace
// and replacing sequences of whitespace characters by a single
space.
// Whitespace characters are the same as those allowed by the S
// production in XML. If the argument is omitted, it defaults to
the
// context node converted to a string, in other words the string-value
// of the context node.
//
void CXPath::evalNormalize_space(void) {
// Obtain the argument
Pchar p = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING &&
!p) {
p = new char[strlen(item->sValue)+1];
strcpy(p, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs > 1)
throw(XPE_WRONGNRARGUMENTS);
// Default to the string value of the context node
if (!p) {
if (ctxtStack->Empty())
throw(XPE_CONTEXTEXPECTED);
item = convertToString(ctxtStack->ItemAtTOS());
p = new char[strlen(item->sValue)+1];
strcpy(p, item->sValue);
}
// Clean up the string
TrimDlm(p);
SqueezeWS(p);
evalStack->PushS(p);
delete[] p;
} // evalNormalize_space
//---------------------------------------------------------------------
// Function: string translate(string, string, string)
//
// The translate function returns the first argument string with
// occurrences of characters in the second argument string replaced
by
// the character at the corresponding position in the third argument
// string. For example, translate("bar","abc","ABC") returns the
string
// BAr. If there is a character in the second argument string with
no
// character at a corresponding position in the third argument
string
// (because the second argument string is longer than the third
// argument string), then occurrences of that character in the
first
// argument string are removed. For example, translate("--aaa--",
// "abc-","ABC") returns "AAA". If a character occurs more than
once in
// the second argument string, then the first occurrence determines
the
// replacement character. If the third argument string is longer
than
// the second argument string, then excess characters are ignored.
//
// NOTE: The translate function is not a sufficient solution for
case
// conversion in all languages. A future version of XPath may provide
// additional functions for case conversion.
//
void CXPath::evalTranslate(void) {
// Obtain the arguments
Pchar p1 = 0;
Pchar p2 = 0;
Pchar p3 = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING)
if
(p3 == 0) {
p3 = new char[strlen(item->sValue)+1];
strcpy(p3, item->sValue);
}
else if (p2 ==
0) {
p2 = new char[strlen(item->sValue)+1];
strcpy(p2, item->sValue);
}
else if (p1 ==
0) {
p1 = new char[strlen(item->sValue)+1];
strcpy(p1, item->sValue);
}
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 3)
throw(XPE_WRONGNRARGUMENTS);
if (!p1 || !p2 || !p3)
throw(XPE_WRONGNRARGUMENTS);
// Translate the string in p1 using p2 and p3
Pchar p = p1;
ushort len3 = strlen(p3);
while (*p) {
ushort inc = 1;
for (ushort ofst = 0; p2[ofst];
ofst++) {
if (*p == p2[ofst])
{
if (ofst < len3)
*p = p3[ofst];
else {
strcpy(p, p+1);
inc = 0;
}
break;
}
}
p += inc;
}
// Return the translated string
evalStack->PushS(p1);
delete[] p1;
delete[] p2;
delete[] p3;
} // evalTranslate
//---------------------------------------------------------------------
// Function: boolean match(string, string)
//
// The match function returns true if a substring in the first
// parameter matches the regular expression in the second parameter.
//
void CXPath::evalMatch(void) {
// Obtain the arguments
Pchar a = 0;
Pchar b = 0;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_STRING)
if
(!b)
STRINIT(b, item->sValue)
else if (!a)
STRINIT(a, item->sValue)
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 2)
throw(XPE_WRONGNRARGUMENTS);
evalStack->PushB(CRegX().Match(b, a));
delete[] a;
delete[] b;
} // evalMatch
//---------------------------------------------------------------------
// Nodeset functions
//---------------------------------------------------------------------
//---------------------------------------------------------------------
// Function: number last()
//
// The last function returns a number equal to the context size
from
// the expression evaluation context.
//
void CXPath::evalLast(void) {
if (ctxtStack->Empty())
throw(XPE_CONTEXTEXPECTED);
PCXPathItem context = ctxtStack->ItemAtTOS();
if (!context)
throw(XPE_CONTEXTEXPECTED);
// Count the number of arguments
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 0)
throw(XPE_WRONGNRARGUMENTS);
evalStack->PushD(context->size);
} // evalLast
//---------------------------------------------------------------------
// Function: number position()
//
// The position function returns a number equal to the context
position
// from the expression evaluation context.
//
void CXPath::evalPosition(void) {
if (ctxtStack->Empty())
throw(XPE_CONTEXTEXPECTED);
PCXPathItem context = ctxtStack->ItemAtTOS();
if (!context)
throw(XPE_CONTEXTEXPECTED);
// Count the number of arguments
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 0)
throw(XPE_WRONGNRARGUMENTS);
evalStack->PushD(context->position);
} // evalPosition
//---------------------------------------------------------------------
// Function: number count(node-set)
//
// The count function returns the number of nodes in the argument
// node-set.
//
void CXPath::evalCount(void) {
// Count the number of arguments
int count;
int nrArgs = -1;
PCXPathItem item;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type != XP_NODESET)
throw(XPE_NODESETEXPECTED);
count = item->nValue->Length();
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs != 1)
throw(XPE_WRONGNRARGUMENTS);
evalStack->PushD(count);
} // evalCount
//---------------------------------------------------------------------
// Function: node-set id(object)
//
// The id function selects elements by their unique ID (see [5.2.1
// Unique IDs]).
//
// 1. When the argument to id is of type node-set, then the result
is
// the union of the result of applying id to
the string-value of
// each of the nodes in the argument node-set.
//
// 2. When the argument to id is of any other type, the argument
is
// converted to a string as if by a call to the
string function; the
// string is split into a whitespace-separated
list of tokens
// (whitespace is any sequence of characters
matching the production
// S); the result is a node-set containing the
elements in the same
// document as the context node that have a unique
ID equal to any
// of the tokens in the list.
//
// * id("foo") selects the element with the unique
ID foo
// * id("foo")/child::para[position()=5] selects
the fifth para
// child of the element with unique
ID foo
//
void CXPath::evalId(void) {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
Assert("not ready for primetime" == 0);
// TBD
if (evalStack->TypeAtTOS() == XP_NODESET) {
}
else {
}
} // evalId
//---------------------------------------------------------------------
// Function: string local-name(node-set?)
//
// The local-name function returns the local part of the expanded-name
// of the node in the argument node-set that is first in document
// order. If the argument node-set is empty or the first node has
no
// expanded-name, an empty string is returned. If the argument
is
// omitted, it defaults to a node-set with the context node as
its only
// member.
//
void CXPath::evalLocal_Name(void) {
// Obtain the argument
int nrArgs = -1;
PCXPathItem item;
PCNodeList nodes;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_NODESET &&
!nodes)
nodes = item->nValue;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs > 1)
throw(XPE_WRONGNRARGUMENTS);
if (!nodes) {
if (ctxtStack->Empty())
Assert(XPE_STACKEMPTY);
nodes
= new CNodeList();
PCXPathItem context = ctxtStack->ItemAtTOS();
nodes->InsertNode(context->nValue->Item(context->position-1));
}
if (nodes->Length() == 0)
evalStack->PushS("");
else {
Pchar p = nodes->Item(0)->NodeValue();
evalStack->PushS(p);
delete[] p;
}
} // evalLocal_Name
//---------------------------------------------------------------------
// Function: string name(node-set?)
//
// The name function returns a string containing a QName representing
// the expanded-name of the node in the argument node-set that
is first
// in document order. The QName must represent the expanded-name
with
// respect to the namespace declarations in effect on the node
whose
// expanded-name is being represented. Typically, this will be
the
// QName that occurred in the XML source. This need not be the
case if
// there are namespace declarations in effect on the node that
// associate multiple prefixes with the same namespace. However,
an
// implementation may include information about the original prefix
in
// its representation of nodes; in this case, an implementation
can
// ensure that the returned string is always the same as the QName
used
// in the XML source. If the argument node-set is empty or the
first
// node has no expanded-name, an empty string is returned. If the
// argument it omitted, it defaults to a node-set with the context
node
// as its only member.
//
// NOTE: The string returned by the name function will be the same
as
// the string returned by the local-name function except for element
// nodes and attribute nodes.
//
void CXPath::evalName(void) {
// Obtain the argument
int nrArgs = -1;
PCXPathItem item;
PCNodeList nodes;
do {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
item = evalStack->Pop();
nrArgs++;
if (item->type == XP_NODESET &&
!nodes)
nodes = item->nValue;
} while (item->type != XP_LPAREN);
// Check the number of arguments
if (nrArgs > 1)
throw(XPE_WRONGNRARGUMENTS);
if (!nodes) {
if (ctxtStack->Empty())
Assert(XPE_STACKEMPTY);
nodes
= new CNodeList();
PCXPathItem context = ctxtStack->ItemAtTOS();
nodes->InsertNode(context->nValue->Item(context->position-1));
}
if (nodes->Length() == 0)
evalStack->PushS("");
else {
Pchar p = nodes->Item(0)->NodeValue();
evalStack->PushS(p);
delete[] p;
}
} // evalName
//---------------------------------------------------------------------
// Function: string namespace-uri(node-set?)
//
// The namespace-uri function returns the namespace URI of the
// expanded-name of the node in the argument node-set that is first
in
// document order. If the argument node-set is empty, the first
node
// has no expanded-name, or the namespace URI of the expanded-name
is
// null, an empty string is returned. If the argument is omitted,
it
// defaults to a node-set with the context node as its only member.
//
// NOTE: The string returned by the namespace-uri function will
be
// empty except for element nodes and attribute nodes.
//
void CXPath::evalNamespace_uri(void) {
if (evalStack->Empty())
Assert(XPE_STACKEMPTY);
if (evalStack->TypeAtTOS() != XP_NODESET)
throw(XPE_NODESETEXPECTED);
Assert("cant use" == "namespace_uri");
} // evalNamespace_uri
//=====================================================================
// Conversion methods
//=====================================================================
//---------------------------------------------------------------------
// Note that the user of this method must delete[] the returned
memory
// after using it.
//
Pchar CXPath::stringValue(RPCNode _node) {
if (_node->NodeType() == ELEMENT_NODE ||
_node->NodeType() == DOCUMENT_NODE)
{
ctxtStack->PushN(_node);
{ // Use the evaluator to collect
the text() children of the
// specified element/document
node
// Save the current
expression state
int hiExp
= iExp;
PCRecord hExp
= new CRecord(exp);
ushort hop
= op;
char htoken[sizeLine];
Strcpy(htoken,
stoken, sizeLine);
// Run eval("descendant::text()")
to get the element text
char myExp[sizeLine];
sprintf(myExp,
" %cdescendant %ctext()",
XP_AXISNAME,
XP_NODETYPE);
eval(myExp);
// restore the
pre-predicate expression
strcpy(stoken,
htoken);
op
= hop;
iExp
= hiExp;
exp
= hExp;
}
// Remove the nodeList we pushed
off the context stack
ctxtStack->Pop();
// Get the result of the evaluation
PCXPathItem item = evalStack->Pop();
// Verify that the item is a nodeset
if (item->type != XP_NODESET)
return 0;
// Compute the size of the buffer
needed to carry the text
long size = 0;
for (int i = 0; i < item->nValue->Length();
i++) {
PCNode node =
item->nValue->Item(i);
Assert(node->NodeType()
== TEXT_NODE);
size += node->Length();
}
// Transfer the text into the buffer
Pchar p = new char[size+1];
memset(p, 0, size+1);
size = 0;
for (int i = 0; i < item->nValue->Length();
i++) {
Pchar t = item->nValue->Item(i)->NodeValue();
strcpy(p+size,
t);
size += strlen(t);
delete[] t;
}
// Return the buffer address
return p;
}
else // NodeValue() works for attributes, text nodes,
etc.
return _node->NodeValue();
} // stringValue
//---------------------------------------------------------------------
//
double CXPath::numberValue(RPCNode _node) {
Pchar str = stringValue(_node);
double dbl = StrToDouble(str);
delete[] str;
return dbl;
} // numberValue
//---------------------------------------------------------------------
// The boolean function converts its argument to a boolean as follows:
// * a number is true if and only if it is neither
positive or
// negative zero nor NaN
// * a node-set is true if and only if it is
non-empty
// * a string is true if and only if its length
is non-zero
// * an object of a type other than the four
basic types is
// converted to a boolean in a way
that is dependent on that type.
//
PCXPathItem CXPath::convertToBoolean(RPCXPathItem _item) {
PCXPathItem item;
if (_item->type == XP_NOTYPE)
Assert(false);
else if (_item->type == XP_BOOLEAN)
item = new CXPathItem(_item->bValue);
else if (_item->type == XP_NUMBER)
item = new CXPathItem(_item->dValue
!= 0.0 &&
_item->dValue != -0.0);
else if (_item->type == XP_STRING)
item = new CXPathItem(strlen(_item->sValue)
> 0);
else if (_item->type == XP_NODESET)
item = new CXPathItem(_item->nValue->Length()
> 0);
return _item;
} // convertToBoolean
//---------------------------------------------------------------------
// Function: number number(object?)
//
// The number function converts its argument to a number as follows:
// * a string that consists of optional whitespace
followed by an
// optional minus sign followed by
a Number followed by whitespace
// is converted to the IEEE 754 number
that is nearest (according
// to the IEEE 754 round-to-nearest
rule) to the mathematical
// value represented by the string;
any other string is converted
// to NaN
// * boolean true is converted to 1; boolean
false is converted to 0
// * a node-set is first converted to a string
as if by a call to
// the string function and then converted
in the same way as a
// string argument
// * an object of a type other than the four
basic types is
// converted to a number in a way
that is dependent on that type
//
// If the argument is omitted, it defaults to a node-set with the
// context node as its only member.
//
// NOTE: The number function should not be used for conversion
of
// numeric data occurring in an element in an XML document unless
the
// element is of a type that represents numeric data in a language-
// neutral format (which would typically be transformed into a
// language-specific format for presentation to a user). In addition,
// the number function cannot be used unless the language-neutral
// format used by the element is consistent with the XPath syntax
for a
// Number.
//
PCXPathItem CXPath::convertToNumber(RPCXPathItem _item) {
PCXPathItem item;
if (_item->type == XP_NOTYPE)
Assert(false);
else if (_item->type == XP_BOOLEAN)
item = new CXPathItem(_item->bValue
? 1.0 : 0.0);
else if (_item->type == XP_NUMBER)
item = new CXPathItem(_item->dValue);
else if (_item->type == XP_STRING)
item = new CXPathItem(StrToDouble(_item->sValue));
else if (_item->type == XP_NODESET)
item = new CXPathItem(numberValue(_item->nValue->Item(0)));
return item;
} // convertToNumber
//---------------------------------------------------------------------
// Function: string string(object?)
//
// The string function converts an object to a string as follows:
// * A node-set is converted to a string by returning
the string-
// value of the node in the node-set
that is first in document
// order. If the node-set is empty,
an empty string is returned.
// * A number is converted to a string as follows
// o NaN is converted to the
string NaN
// o positive zero is converted
to the string 0
// o negative zero is converted
to the string 0
// o positive infinity is converted
to the string Infinity
// o negative infinity is converted
to the string -Infinity
// o if the number is an integer,
the number is represented in
// decimal form
as a Number with no decimal point and no
// leading zeros,
preceded by a minus sign (-) if the number is
// negative
// o otherwise, the number
is represented in decimal form as a
// Number including
a decimal point with at least one digit
// before the decimal
point and at least one digit after the
// decimal point,
preceded by a minus sign (-) if the number is
// negative; there
must be no leading zeros before the decimal
// point apart
possibly from the one required digit immediately
// before the decimal
point; beyond the one required digit
// after the decimal
point there must be as many, but only as
// many, more digits
as are needed to uniquely distinguish the
// number from
all other IEEE 754 numeric values.
// * The boolean false value is converted to
the string false. The
// boolean true value is converted
to the string true.
// * An object of a type other than the four
basic types is
// converted to a string in a way
that is dependent on that type.
//
// If the argument is omitted, it defaults to a node-set with the
// context node as its only member.
//
// NOTE: The string function is not intended for converting numbers
// into strings for presentation to users. The format-number function
// provides this functionality.
//
PCXPathItem CXPath::convertToString(RPCXPathItem _item) {
PCXPathItem item;
if (_item->type == XP_NOTYPE)
Assert(false);
// probably a bug in my code
else if (_item->type == XP_BOOLEAN)
if (_item->bValue)
item = new CXPathItem("true");
else
item = new CXPathItem("false");
else if (_item->type == XP_NUMBER)
if (_item->dValue == 0)
item = new CXPathItem("0");
else {
char work[sizeName];
sprintf(work,
"%G", _item->dValue);
item = new CXPathItem(work);
}
else if (_item->type == XP_STRING)
item = new CXPathItem(_item->sValue);
else if (_item->type == XP_NODESET)
if (_item->nValue->Length() == 0)
item
= new CXPathItem("");
else {
Pchar str = stringValue(_item->nValue->Item(0));
item
= new CXPathItem(str);
delete[] str;
}
return item;
} // convertToString
//=====================================================================
// Axis Traversal methods
//=====================================================================
//---------------------------------------------------------------------
//
PCNodeList CXPath::travelOnAxis(PCNode _contextNode,
Pchar _axisName,
Pchar _name) {
Pchar axisName = _axisName+1;
if (strcmp(axisName,
"ancestor")
== 0)
return ancestor
(_contextNode, _name);
else if (strcmp(axisName, "ancestor-or-self")
== 0)
return ancestorOrSelf (_contextNode,
_name);
else if (strcmp(axisName, "attribute")
== 0)
return attribute
(_contextNode, _name);
else if (strcmp(axisName, "child")
== 0)
return child
(_contextNode, _name);
else if (strcmp(axisName, "descendant")
== 0)
return descendant
(_contextNode, _name);
else if (strcmp(axisName, "descendant-or-self") ==
0)
return descendantOrSelf(_contextNode,
_name);
else if (strcmp(axisName, "following")
== 0)
return following
(_contextNode, _name);
else if (strcmp(axisName, "following-sibling")
== 0)
return followingSibling(_contextNode,
_name);
else if (strcmp(axisName, "nameSpace")
== 0)
return nameSpace
(_contextNode, _name);
else if (strcmp(axisName, "parent")
== 0)
return parent
(_contextNode, _name);
else if (strcmp(axisName, "preceding")
== 0)
return preceding
(_contextNode, _name);
else if (strcmp(axisName, "preceding-sibling")
== 0)
return precedingSibling(_contextNode,
_name);
else if (strcmp(axisName, "self")
== 0)
return self
(_contextNode, _name);
throw(XPE_AXISNAMEUNKNOWN);
} // travelOnAxis
//---------------------------------------------------------------------
// Recurse into the DOM proceeding in document order
//
void CXPath::downInDocOrder(PCNodeList _list, PCNode _node, Pchar
_name) {
PCNode node = _node->FirstChild();
while (node) {
if
(node->m_type == TEXT_NODE &&
strcmp(_name, "text()") == 0)
_list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(_name, "comment()") == 0)
_list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(_name, "*") == 0 ||
strcmp(_name, node->text) == 0))
_list->InsertNode(node);
else if (strcmp(_name, "node()")
== 0)
_list->InsertNode(node);
if (node->m_type == ELEMENT_NODE)
downInDocOrder(_list,
node, _name);
node = node->NextSibling();
}
} // downInDocOrder
//---------------------------------------------------------------------
// Recurse into the DOM proceeding in reverse document order
//
void CXPath::downInBackOrder(PCNodeList _list, PCNode _node, Pchar
_name) {
PCNode node = _node->LastChild();
while (node) {
if
(node->m_type == TEXT_NODE &&
strcmp(_name, "text()") == 0)
_list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(_name, "comment()") == 0)
_list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE)
{
downInBackOrder(_list,
node, _name);
if (strcmp(_name,
"*") == 0 ||
strcmp(_name, "node()") == 0 ||
strcmp(_name, node->text) == 0)
_list->InsertNode(node);
}
else if (strcmp(_name, "node()")
== 0)
_list->InsertNode(node);
node = node->PreviousSibling();
}
} // downInBackOrder
//---------------------------------------------------------------------
// ancestor
//
PCNodeList CXPath::ancestor(PCNode _contextNode, Pchar _name) {
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->ParentNode();
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, "node()") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
node = node->ParentNode();
}
return list;
} // ancestor
//---------------------------------------------------------------------
// ancestor-or-self
//
PCNodeList CXPath::ancestorOrSelf(PCNode _contextNode, Pchar _name)
{
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode;
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, "node()") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
node = node->ParentNode();
}
return list;
} // ancestor_or_self
//---------------------------------------------------------------------
// attribute
//
PCNodeList CXPath::attribute(PCNode _contextNode, Pchar _name)
{
PCNodeList list = new CNodeList();
Pchar name
= _name+1;
PCNamedNodeMap attrs = _contextNode->Attributes();
if (!attrs)
return list;
for (int i = 0; i < attrs->Length(); i++) {
PCNode attr = attrs->Item(i);
if (strcmp(name, "*")
== 0 ||
strcmp(name,
"node()") == 0 ||
strcmp(name,
attr->text) == 0)
list->InsertNode(attr);
}
return list;
} // attribute
//---------------------------------------------------------------------
// child
//
PCNodeList CXPath::child(PCNode _contextNode, Pchar _name) {
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->FirstChild();
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
node = node->NextSibling();
}
// If extend requested and no matching child node,
then add a new child
// element
if (extend && list->Length() == 0) {
PCElement el = _contextNode->OwnerDocument()->CreateElement(name);
node
= TYPECAST(el, Node);
_contextNode->AppendChild(node);
list->InsertNode(node);
}
return list;
} // child
//---------------------------------------------------------------------
// descendant
//
PCNodeList CXPath::descendant(PCNode _contextNode, Pchar _name)
{
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->FirstChild();
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
if (node->m_type == ELEMENT_NODE)
downInDocOrder(list,
node, name);
node = node->NextSibling();
}
return list;
} // descendant
//---------------------------------------------------------------------
// descendant-or-self
//
PCNodeList CXPath::descendantOrSelf(PCNode _contextNode, Pchar
_name) {
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode;
if (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
if (node->m_type == ELEMENT_NODE
||
node->m_type
== DOCUMENT_NODE)
downInDocOrder(list,
node, name);
}
return list;
} // descendantOrSelf
//---------------------------------------------------------------------
// following
//
PCNodeList CXPath::following(PCNode _contextNode, Pchar _name)
{
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->NextSibling();
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
if (node->m_type == ELEMENT_NODE)
downInDocOrder(list,
node, name);
node = node->NextSibling();
}
return list;
} // following
//---------------------------------------------------------------------
// following-sibling
//
PCNodeList CXPath::followingSibling(PCNode _contextNode, Pchar
_name) {
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->NextSibling();
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
node = node->NextSibling();
}
return list;
} // followingSibling
//---------------------------------------------------------------------
// namespace
// TBD
//
PCNodeList CXPath::nameSpace(PCNode _contextNode, Pchar _name)
{
_contextNode;
_name;
PCNodeList list = new CNodeList();
return list;
} // nameSpace
//---------------------------------------------------------------------
// paren
//
PCNodeList CXPath::parent(PCNode _contextNode, Pchar _name) {
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->ParentNode();
if (node)
if
(node->m_type == ELEMENT_NODE &&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
return list;
} // parent
//---------------------------------------------------------------------
// preceding
//
PCNodeList CXPath::preceding(PCNode _contextNode, Pchar _name)
{
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->PreviousSibling();
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE)
{
downInBackOrder(list,
node, name);
if (strcmp(name,
"*") == 0 ||
strcmp(name, "node()") == 0 ||
strcmp(name, node->text) == 0)
list->InsertNode(node);
}
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
node = node->PreviousSibling();
}
return list;
} // preceding
//---------------------------------------------------------------------
// preceding-sibling
//
PCNodeList CXPath::precedingSibling(PCNode _contextNode, Pchar
_name) {
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode->PreviousSibling();
while (node) {
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
node = node->PreviousSibling();
}
return list;
} // precedingSibling
//---------------------------------------------------------------------
// self
//
PCNodeList CXPath::self(PCNode _contextNode, Pchar _name) {
PCNodeList list = new CNodeList();
Pchar name = _name+1;
PCNode node = _contextNode;
if (node)
if
((node->m_type == TEXT_NODE &&
strcmp(name, "text()") == 0))
list->InsertNode(node);
else if (node->m_type == COMMENT_NODE
&&
strcmp(name, "comment()") == 0)
list->InsertNode(node);
else if (node->m_type == ELEMENT_NODE
&&
(strcmp(name, "*") == 0 ||
strcmp(name, node->text) == 0))
list->InsertNode(node);
else if (strcmp(name, "node()")
== 0)
list->InsertNode(node);
return list;
} // self
//=====================================================================
// Evaluator tokenizer
//=====================================================================
//---------------------------------------------------------------------
//
void CXPath::initEvalTokenizer(Pchar _postFixExp) {
iExp = 1;
exp = new CRecord(_postFixExp);
} // initEvalTokenizer
//---------------------------------------------------------------------
//
bool CXPath::getEvalToken(void) {
op = XP_EMPTY;
stoken[0] = 0;
if (iExp > exp->Number())
return false;
exp->GetField(iExp++, stoken, sizeLine);
op = stoken[0] & 0xff;
return true;
} // getEvalToken
//=====================================================================
// Parser
//=====================================================================
//---------------------------------------------------------------------
//
Pchar CXPath::Parse(Pchar _path) {
char work[sizeString];
Strcpy(work, _path, sizeString);
parse (work, work, sizeString);
Pchar p = 0;
STRINIT(p, work);
return p;
} // Parse
//---------------------------------------------------------------------
// The expression parser converts an XPath expression from infix
// notation to postfix notation.
//
bool CXPath::parse(Pchar _inFixExp, Pchar _postFixExp, ushort _size)
{
Assert(_postFixExp);
Assert(_size != 0);
// Check for something to do
if (StrEmpty(_inFixExp)) {
memset(_postFixExp, 0, _size);
return true;
}
// Prepare the input and output expression areas (they
can be the
// same area)
STRINIT(inFixExp, _inFixExp);
memset(_postFixExp, 0, _size);
delete[] postFixExp;
postFixExp = new char[sizeString];
memset(postFixExp, 0, sizeString);
// Initialize the tokenizer
initParseTokenizer(inFixExp);
// Parse the expression
try {
err = XPE_OK;
do {
getParseToken();
expr();
} while (!atEnd);
}
catch (ulong _err) {
err = _err;
char token[sizeLine];
sprintf(token, "%cERR=%ld>", XP_PARSEERROR,
_err);
outputPostfix(token);
}
// Return the postfix expression result
if (strlen(postFixExp) >= _size) {
delete[] inFixExp;
inFixExp = 0;
delete[] postFixExp;
postFixExp = 0;
return false;
}
else {
strncpy(_postFixExp, postFixExp,
_size);
delete[] inFixExp;
inFixExp = 0;
delete[] postFixExp;
postFixExp = 0;
return true;
}
} // parse
//---------------------------------------------------------------------
// [14] Expr ::= OrExpr
//
void CXPath::expr(void) {
orExpr();
} // expr
//---------------------------------------------------------------------
// [21] OrExpr ::= AndExpr | OrExpr 'or' AndExpr
//
void CXPath::orExpr(void) {
andExpr();
// Loop to process subsequent andExprs separated by
OR-operators.
while (op == XP_OR) {
getParseToken();
andExpr();
outputPostfix(XP_OR);
}
} // orExpr
//---------------------------------------------------------------------
// [22] AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
//
void CXPath::andExpr(void) {
equalityExpr();
// Loop to process subsequent equalityExprs separated
by AND-operators.
while (op == XP_AND) {
getParseToken();
equalityExpr();
outputPostfix(XP_AND);
}
} // andExpr
//---------------------------------------------------------------------
// [23] EqualityExpr ::= RelationalExpr
//
| EqualityExpr '=' RelationalExpr
//
| EqualityExpr '!=' RelationalExpr
// note: A != B = C is allowed ? Answer from James, yes with
// (RelationalExpr = RelationalExpr) = RelationalExpr
// (RelationalExpr != RelationalExpr) != RelationalExpr
// which is basically what got implemented.
//
void CXPath::equalityExpr(void) {
relationalExpr();
// Loop to process subsequent relationalExprs separated
by eq-operators
while (op == XP_EQUAL ||
op == XP_NOTEQUAL)
{
uchar holdOp = op;
getParseToken();
relationalExpr();
outputPostfix(holdOp);
}
} // equalityExpr
//---------------------------------------------------------------------
// [24] RelationalExpr ::= AdditiveExpr
//
| RelationalExpr '<' AdditiveExpr
//
| RelationalExpr '>' AdditiveExpr
//
| RelationalExpr '<=' AdditiveExpr
//
| RelationalExpr '>=' AdditiveExpr
// note: A <= B > C is allowed ? Answer from James, yes with
// (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
// which is basically what got implemented.
//
void CXPath::relationalExpr(void) {
additiveExpr();
// Loop to process subsequent additiveExprs separated
by eq-operators
while (op == XP_LESSTHAN ||
op == XP_LESSOREQUAL
||
op == XP_GREATERTHAN
||
op == XP_GREATEROREQUAL)
{
uchar holdOp = op;
getParseToken();
additiveExpr();
outputPostfix(holdOp);
}
} // relationalExpr
//---------------------------------------------------------------------
// [25] AdditiveExpr ::= MultiplicativeExpr
//
| AdditiveExpr '+' MultiplicativeExpr
//
| AdditiveExpr '-' MultiplicativeExpr
//
void CXPath::additiveExpr(void) {
multiplicativeExpr();
while (op == XP_PLUS ||
op == XP_MINUS)
{
uchar holdOp = op;
getParseToken();
multiplicativeExpr();
outputPostfix(holdOp);
}
} // additiveExpr
//---------------------------------------------------------------------
// [26] MultiplicativeExpr ::= UnaryExpr
//
| MultiplicativeExpr MultiplyOperator UnaryExpr
//
| MultiplicativeExpr 'div' UnaryExpr
//
| MultiplicativeExpr 'mod' UnaryExpr
//
void CXPath::multiplicativeExpr(void) {
unaryExpr();
while (op == XP_MUL ||
op == XP_DIV
||
op == XP_MOD)
{
uchar holdOp = op;
getParseToken();
unaryExpr();
outputPostfix(holdOp);
}
} // multiplicativeExpr
//---------------------------------------------------------------------
// [27] UnaryExpr ::= UnionExpr
//
| '-' UnaryExpr
//
void CXPath::unaryExpr(void) {
bool found = false;
bool minus = false;
while (op == XP_MINUS) {
found = true;
minus = !minus;
getParseToken();
}
unionExpr();
if (found)
if (minus)
outputPostfix(XP_UNARYMINUS);
} // unaryExpr
//---------------------------------------------------------------------
// [18] UnionExpr ::= PathExpr
//
| UnionExpr '|' PathExpr
//
void CXPath::unionExpr(void) {
pathExpr();
while (op == XP_UNION) {
getParseToken();
pathExpr();
outputPostfix(XP_UNION);
}
} // unionExpr
//---------------------------------------------------------------------
// [19] pathExpr ::= LocationPath
//
| FilterExpr
//
| FilterExpr '/' RelativeLocationPath
//
| FilterExpr '//' RelativeLocationpath
//
// A token is a primary Expr if its first character is one of the
the
// following characters:
//
// $, ", ', (, digit
//
// or if it is a functionName
//
void CXPath::pathExpr(void) {
if (!filterExpr()) {
locationPath();
return;
}
if (op == XP_PATH) {
outputPostfix(XP_PATH);
getParseToken();
relativeLocationPath(1);
}
else if (op == XP_DBLPATH) {
outputPostfix(XP_PATH);
char work[32];
sprintf(work, "%cdescendant-or-self",
XP_AXISNAME);
outputPostfix(work);
sprintf(work, "%cnode()", XP_NODETYPE);
outputPostfix(work);
getParseToken();
if (op != XP_EMPTY) {
outputPostfix(XP_PATH);
relativeLocationPath(2);
}
else
relativeLocationPath(1);
}
} // pathExpr
//---------------------------------------------------------------------
// [20] FilterExpr ::=
PrimaryExpr
//
| FilterExpr Predicate (*)TBD
//
bool CXPath::filterExpr(void) {
if (!primaryExpr())
return false;
while (op == XP_LBOX)
predicateExpr();
return true;
} // filterExpr
//---------------------------------------------------------------------
// [15] PrimaryExpr ::=
VariableReference
//
| '(' Expr ')'
//
| Literal
//
| Number
//
| FunctionCall
//
bool CXPath::primaryExpr(void) {
char token[sizeLine];
if (op == XP_VARIABLE) {
if (strlen(stoken) == 1)
throw(XPE_VARNAMEEXPECTED);
sprintf(token, "%c%s", XP_VARIABLE,
stoken);
outputPostfix(token);
getParseToken();
return true;
}
if (op == XP_LPAREN) {
getParseToken();
expr();
if (op != XP_RPAREN)
throw(XPE_RPARENEXPECTED);
getParseToken();
return true;
}
if (op == XP_QUOTEDSTR) {
sprintf(token, "%c%s", XP_QUOTEDSTR,
stoken);
outputPostfix(token);
getParseToken();
return true;
}
if (op == XP_NUMBER) {
sprintf(token, "%c%s", XP_NUMBER,
stoken);
outputPostfix(token);
getParseToken();
return true;
}
if (op == XP_FUNNAME) {
functionCall();
return true;
}
return false;
} // primaryExpr
//---------------------------------------------------------------------
// [16] FunctionCall ::= FunctionName
//
'(' ( Argument ( ',' Argument )* )? ')'
//
// emits
// argExpr1 , argExpr2 , ... , argExprN )functionName
//
void CXPath::functionCall(void) {
char token[sizeLine];
sprintf(token, "%c%s", XP_FUNNAME, stoken);
getParseToken();
if (op != XP_LPAREN)
throw(XPE_LPARENEXPECTED);
// Marks the end of the list of function parameters
for the
// evaluator
outputPostfix(XP_LPAREN);
do {
getParseToken();
if (op != XP_RPAREN &&
op != XP_COMMA)
expr();
} while (op == XP_COMMA);
if (op != XP_RPAREN)
throw(XPE_RPARENEXPECTED);
outputPostfix(token);
getParseToken();
} // functionCall
//---------------------------------------------------------------------
// [1] LocationPath ::=
RelativeLocationPath
//
| AbsoluteLocationPath
// [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
//
| AbbreviatedAbsoluteLocationPath
// [10] AbbreviatedAbsoluteLocationPath ::=
//
'//' RelativeLocationPath
//
void CXPath::locationPath(void) {
if (op == XP_PATH) {
outputPostfix(XP_ROOT);
getParseToken();
relativeLocationPath(1);
}
else if (op == XP_DBLPATH) {
outputPostfix(XP_ROOT);
char token[sizeName];
sprintf(token, "%cdescendant-or-self
%cnode()", XP_AXISNAME,
XP_NODETYPE);
outputPostfix(token);
getParseToken();
if (op != XP_EMPTY) {
outputPostfix(XP_PATH);
relativeLocationPath(2);
}
else
relativeLocationPath(1);
}
else
relativeLocationPath(0);
} // locationPath
//---------------------------------------------------------------------
// [3] RelativeLocationPath ::= Step
//
| RelativeLocationPath '/' Step
//
| AbbreviatedRelativeLocationPath
// [11] AbbreviatedRelativeLocationPath ::=
//
RelativeLocationPath '//' Step
//
void CXPath::relativeLocationPath(ushort _steps) {
if (op == XP_EMPTY) {
if (_steps > 0) {
char token[32];
sprintf(token,
"%c%d", XP_UNWIND, _steps);
outputPostfix(token);
}
return;
}
step();
while (true)
if
(op == XP_PATH) {
outputPostfix(XP_PATH);
_steps++;
getParseToken();
if (op == XP_EMPTY)
throw(XPE_UNEXPECTEDEND);
step();
}
else if (op == XP_DBLPATH) {
outputPostfix(XP_PATH);
_steps++;
char token[32];
sprintf(token,
"%cdescendant-or-self", XP_AXISNAME);
outputPostfix(token);
sprintf(token,
"%cnode()", XP_NODETYPE);
outputPostfix(token);
getParseToken();
if (op != XP_EMPTY)
{
outputPostfix(XP_PATH);
_steps++;
step();
}
}
else if (_steps > 0) {
char token[32];
sprintf(token,
"%c%d", XP_UNWIND, _steps);
outputPostfix(token);
return;
}
else
return;
} // relativeLocationPath
//---------------------------------------------------------------------
// [4] Step ::=
AxisSpecifier NodeTest Predicate*
//
| AbbreviatedStep
//
void CXPath::step(void) {
// Parse the AbbreviatedStep part
if (abbreviatedStep())
return;
// Parse the AxisName part
axisName();
// Parse the NodeTest part
nodeTest();
// Parse the Predicate part
while (op == XP_LBOX)
predicateExpr();
} // step
//---------------------------------------------------------------------
// [12] AbbreviatedStep ::=
'.'
//
| '..'
//
bool CXPath::abbreviatedStep(void) {
char token[32];
if (op == XP_DOT) {
sprintf(token, "%cself", XP_AXISNAME);
outputPostfix(token);
sprintf(token, "%cnode()", XP_NODETYPE);
outputPostfix(token);
getParseToken();
return true;
}
if (op == XP_DBLDOT) {
sprintf(token, "%cparent", XP_AXISNAME);
outputPostfix(token);
sprintf(token, "%cnode()", XP_NODETYPE);
outputPostfix(token);
getParseToken();
return true;
}
return false;
} // abbreviatedStep
//---------------------------------------------------------------------
// [5] AxisSpecifier ::=
AxisName '::'
//
| AbbreviatedAxisSpecifier
// [6] AxisName ::=
'ancestor'
//
| 'ancestor-or-self'
//
| 'attribute'
//
| 'child'
//
| 'descendant'
//
| 'descendant-or-self'
//
| 'following'
//
| 'following-sibling'
//
| 'namespace'
//
| 'parent'
//
| 'preceding'
//
| 'preceding-sibling'
//
| 'self'
//
void CXPath::axisName(void) {
char token[sizeLine];
// Parse the abbreviatedAxisSpecifier part
if (abbreviatedAxisSpecifier())
return;
// Parse the AxisName part
if (op == XP_AXISNAME) {
sprintf(token, "%c%s", XP_AXISNAME,
stoken);
outputPostfix(token);
getParseToken();
if (op != XP_DBLCOLON)
throw(XPE_DOUBLECOLONEXPECTED);
getParseToken();
}
else if (op == XP_LBOX) {
sprintf(token, "%cself", XP_AXISNAME);
outputPostfix(token);
}
else if (op != XP_EMPTY) {
sprintf(token, "%cchild", XP_AXISNAME);
outputPostfix(token);
}
} // axisName
//---------------------------------------------------------------------
// [13] AbbreviatedAxisSpecifier ::= '@'?
//
bool CXPath::abbreviatedAxisSpecifier(void) {
char token[sizeLine];
if (op == XP_ATTR) {
sprintf(token, "%cattribute", XP_AXISNAME);
outputPostfix(token);
getParseToken();
return true;
}
return false;
} // abbreviatedAxisSpecifier
//---------------------------------------------------------------------
// [7] NodeTest ::=
NameTest
//
| NodeType '(' ')'
//
| 'processing-instruction'
//
'(' Literal ')'
//
void CXPath::nodeTest(void) {
char token[sizeLine];
// Parse the NameTest part
if (nameTest())
return;
// Parse the NodeType part
if (nodeType())
return;
// Handle the QName part of the NameTest part
if (op == XP_QNAME)
{
sprintf(token, "%c%s", XP_QNAME,
stoken);
outputPostfix(token);
getParseToken();
}
else if (op == XP_LBOX) {
sprintf(token, "%cnode()", XP_NODETYPE);
outputPostfix(token);
}
else
throw(XPE_QNAMEEXPECTED);
} // nodeTest
//---------------------------------------------------------------------
// [37] NameTest ::=
'*'
//
| NCName ':' '*'
//
| QName
//
bool CXPath::nameTest(void) {
char token[sizeLine];
if (op == XP_MUL) {
isOp = false;
op = XP_ALL;
sprintf(token, "%c*", XP_ALL);
outputPostfix(token);
getParseToken();
return true;
}
// Parse the NCName ':*' NameTest - TBD
if (op == XP_ALLNAME) {
sprintf(token, "%c%s", XP_ALLNAME,
stoken);
outputPostfix(token);
// changed it to the form *NCName
getParseToken();
if (op != XP_COLON)
throw(XPE_PARSEERROR);
getParseToken();
if (op != XP_MUL)
throw(XPE_PARSEERROR);
return true;
}
return false;
} // nameTest
//---------------------------------------------------------------------
// [38] NodeType ::=
'comment'
//
| 'text'
//
| 'processing-instruction'
//
| 'node'
// (also handles the special case:
// 'processing-instruction' '(' Literal ')'
//
// emits
// literal (processing-instruction
// or
// (nodeType
//
bool CXPath::nodeType(void) {
char htoken[sizeLine];
if (op == XP_NODETYPE) {
sprintf(htoken, "%c%s()", XP_NODETYPE,
stoken);
getParseToken();
// Parse open parenthesis
if (op != XP_LPAREN)
throw(XPE_LPARENEXPECTED);
getParseToken();
// Parse close parenthesis
if (op != XP_RPAREN)
if (strcmp(htoken+1,
"processing-instruction()") == 0) {
if (op != XP_QUOTEDSTR)
throw(XPE_LITERALEXPECTED);
// Save the literal (quoted string)
char token[sizeLine];
sprintf(token, "%c%s", XP_QUOTEDSTR, stoken);
outputPostfix(token);
getParseToken();
if (op != XP_RPAREN)
throw(XPE_RPARENEXPECTED);
}
else
throw(XPE_RPARENNOTEXPECTED);
// Save the nodeType
outputPostfix(htoken);
getParseToken();
return true;
}
return false;
} // nodeType
//---------------------------------------------------------------------
// [8] Predicate ::=
'[' PredicateExpr ']'
//
void CXPath::predicateExpr(void) {
outputPostfix(XP_LBOX);
getParseToken();
expr();
if (op != XP_RBOX)
throw(XPE_RBRACKETEXPECTED);
outputPostfix(XP_RBOX);
getParseToken();
} // predicateExpr
//---------------------------------------------------------------------
// Append the string preceded by a blank to the postfix buffer.
//
void CXPath::outputPostfix(Pchar _symbol) {
ChrCat(postFixExp, spacer, sizeString);
Strcat(postFixExp, _symbol, sizeString);
} // outputPostfix
//---------------------------------------------------------------------
// Append the operator preceded by a blank to the postfix buffer.
//
void CXPath::outputPostfix(char _op) {
ChrCat(postFixExp, spacer, sizeString);
ChrCat(postFixExp, _op, sizeString);
} // outputPostfix
//=====================================================================
// Parser tokenizer
//=====================================================================
//---------------------------------------------------------------------
// Initialize the tokenizer
//
void CXPath::initParseTokenizer(Pchar _inFixExp) {
pInFixExp = _inFixExp;
delete[] stoken;
stoken = new char[sizeString];
atEnd = false;
getCh();
} // initParseTokenizer
//---------------------------------------------------------------------
// Get a token
//
void CXPath::getParseToken(void) {
// state of last token
wasOp = isOp;
lop = op;
// clear the token string
isOp = false;
op = XP_NOTKNOWN;
stoken[0] = 0;
skipSpaces();
if (atEnd) {
op = XP_EMPTY;
return;
}
if ((ch >= 'A' &&
ch <= 'Z') ||
(ch >= 'a' && ch <= 'z') ||
(ch == '_'))
getSymbol();
else if (ch == '$')
getVariable();
else if (ch >= '0' && ch <= '9')
getNumber();
else if (ch == strQuote1 ||
// "string"
ch == strQuote2)
// 'string'
getQuotedString();
else
getOp();
} // getParseToken
//---------------------------------------------------------------------
// Get a symbol
//
void CXPath::getSymbol(void) {
op = XP_QNAME;
int nrColons = 0;
ChrCat(stoken, ch, sizeString);
while (getCh() && (ch == '_' ||
ch == '-' ||
ch == '.' ||
ch == ':' ||
isalnum(ch))) {
if (ch == ':') {
if (++nrColons
> 1)
throw(XPE_TOOMANYCOLONS);
if
(chkCh() == ':') {
op = XP_AXISNAME;
break;
}
else if (chkCh()
== '*') {
op = XP_ALLNAME;
break;
}
}
ChrCat(stoken, ch, sizeString);
}
// If there is a preceding token and the preceding
token is not one
// of @, ::, (, [, , or an Operator, then a * must
be recognized as
// a MultiplyOperator and an NCName must be recognized
as an
// OperatorName. Otherwise not.
if (lop != XP_ATTR &&
lop != XP_DBLCOLON &&
lop != XP_LPAREN
&&
lop != XP_LBOX
&&
lop != XP_COMMA
&&
!wasOp)
if
(strcmp(stoken, "and") == 0) {
op = XP_AND;
return;
}
else if (strcmp(stoken, "or")
== 0) {
op = XP_OR;
return;
}
else if (strcmp(stoken, "mod") ==
0) {
op = XP_MOD;
return;
}
else if (strcmp(stoken, "div") ==
0) {
op = XP_DIV;
return;
}
skipSpaces();
// Check if the symbol is a FunctionName or NodeType
if (ch == '(')
if (strcmp(stoken, "comment")
== 0 ||
strcmp(stoken,
"node")
== 0 ||
strcmp(stoken,
"text")
== 0 ||
strcmp(stoken,
"processing-instruction") == 0)
op = XP_NODETYPE;
else
op = XP_FUNNAME;
} // getSymbol
//---------------------------------------------------------------------
// Get a variable
//
void CXPath::getVariable(void) {
op = XP_VARIABLE;
while (getCh() && (ch == '_' ||
ch == '-' ||
ch == '.' ||
isalnum(ch)))
ChrCat(stoken, ch, sizeString);
} // getVariable
//---------------------------------------------------------------------
// Get a number
//
void CXPath::getNumber(void) {
op = XP_NUMBER;
ChrCat(stoken, ch, sizeString);
while (getCh() && (isdigit(ch) ||
ch == '.'))
ChrCat(stoken, ch, sizeString);
} // getNumber
//---------------------------------------------------------------------
// Get a quoted string.
//
void CXPath::getQuotedString(void) {
op = XP_QUOTEDSTR;
char quote = ch;
while (getCh() && ch != quote) {
if (ch == ' ')
// fill in spaces
ch = XP_SPACE;
ChrCat(stoken, ch, sizeString);
}
// Check for closing quote
if (ch == 0)
throw(XPE_UNEXPECTEDEND);
getCh();
} // getQuotedString
//---------------------------------------------------------------------
// Get an operator string.
// (all are one-char or two-char operators)
// [32] Operator
OperatorName
//
| MultiplyOperator
//
| '/' | '//' | '|' | '+' | '-' | '='
//
| '!=' | '<' | '<=' | '>' | '>='
//
void CXPath::getOp(void) {
ChrCat(stoken, ch, sizeString);
switch (ch) {
case '|':
getCh();
op
= XP_UNION;
isOp = true;
break;
case '!':
getCh();
if (ch != '=')
throw(XPE_EQUALSIGNEXPECTED);
ChrCat(stoken,
ch, sizeString);
getCh();
op
= XP_NOTEQUAL;
isOp = true;
break;
case '=':
getCh();
op
= XP_EQUAL;
isOp = true;
break;
case '<':
getCh();
if (ch == '=')
{
ChrCat(stoken, ch, sizeString);
getCh();
op = XP_LESSOREQUAL;
}
else
op = XP_LESSTHAN;
isOp = true;
break;
case '>':
getCh();
if (ch == '=')
{
ChrCat(stoken, ch, sizeString);
getCh();
op = XP_GREATEROREQUAL;
}
else
op = XP_GREATERTHAN;
isOp = true;
break;
case '+':
getCh();
op
= XP_PLUS;
isOp = true;
break;
case '-':
getCh();
op
= XP_MINUS;
isOp = true;
break;
case '*':
getCh();
op
= XP_MUL;
isOp = true;
break;
case '/':
getCh();
if (ch == '/')
{
ChrCat(stoken, ch, sizeString);
getCh();
op = XP_DBLPATH;
}
else
op = XP_PATH;
isOp = true;
break;
case '(':
getCh();
op = XP_LPAREN;
break;
case ')':
getCh();
op = XP_RPAREN;
break;
case '[':
getCh();
op = XP_LBOX;
break;
case ']':
getCh();
op = XP_RBOX;
break;
case '.':
getCh();
if
(ch == '.') {
ChrCat(stoken, ch, sizeString);
getCh();
op = XP_DBLDOT;
}
else if (isdigit(ch))
getNumber();
else
op = XP_DOT;
break;
case '@':
getCh();
op = XP_ATTR;
break;
case ',':
getCh();
op = XP_COMMA;
break;
case ':':
getCh();
if (ch == ':')
{
ChrCat(stoken, ch, sizeString);
getCh();
op = XP_DBLCOLON;
}
else
op = XP_COLON;
break;
default:
throw(XPE_UNKNOWNOPERATOR);
}
} // getOp
//---------------------------------------------------------------------
// Get the next character
//
bool CXPath::getCh(void) {
ch = 0;
if (atEnd)
return false;
if (*pInFixExp == 0) {
atEnd = true;
return false;
}
ch = *pInFixExp++;
// Convert standard five XML entities to their character
values
if (ch == '&')
ch = getEntity(pInFixExp);
return true;
} // getCh
//---------------------------------------------------------------------
// Check the next non-blank character
//
char CXPath::chkCh(void) {
if (atEnd)
return 0;
if (*pInFixExp == 0)
return 0;
Pchar p = pInFixExp;
while (*p == spacer)
p++;
char ch = *p;
if (ch == '&')
ch = getEntity(p);
return ch;
} // chkCh
//---------------------------------------------------------------------
// Skip white space
//
void CXPath::skipSpaces(void) {
while (ch <= spacer && getCh());
} // skipSpaces
//---------------------------------------------------------------------
// This method only handles the following entities:
//
// entities of the form &#nn; and the following named entities.
// < less-than
// > greater-than
// & ampersand
// ' apostrophe
// " quote
//
char CXPath::getEntity(RPchar _p) {
char work[sizeName];
char name[sizeName];
name[0] = 0;
Pchar q = _p;
while (*q && *q != ';') {
ChrCat(name, *q, sizeName);
q++;
}
// Is the entity complete?
if (*q == 0)
throw(XPE_BADENTITY);
char ch = 0;
// Convert number form
if (name[0] == '#')
{
// TBD - This code handles the form
&#nn; not &#nn;#nn;
strcpy(name, name+1);
ushort nr = StrToShort(name);
ch
= nr;
}
// Check for named entity
else if (strcmp(name, "lt") == 0)
ch = '<';
else if (strcmp(name, "gt") == 0)
ch = '>';
else if (strcmp(name, "amp") == 0)
ch = '&';
else if (strcmp(name, "apos") == 0)
ch = '\'';
else if (strcmp(name, "quot") == 0)
ch = '"';
// I don't recognize the name
else
throw(XPE_UNKNOWNENTITY);
_p = q+1;
return ch;
} // getEntity
//=====================================================================
// CXPathItem Implementation
//=====================================================================
//---------------------------------------------------------------------
//
CXPathItem::CXPathItem(void):
CItem (),
order (down),
position(0),
size (0),
type (XP_NOTYPE),
bValue (false),
dValue (0.0),
sValue (0),
nValue (0) {
} // CXPathItem
//---------------------------------------------------------------------
//
CXPathItem::CXPathItem(bool _value):
CItem (),
order (down),
position(0),
size (0),
type (XP_BOOLEAN),
bValue (_value),
dValue (0.0),
sValue (0),
nValue (0) {
} // CXPathItem
//---------------------------------------------------------------------
//
CXPathItem::CXPathItem(double _value):
CItem (),
order (down),
position(0),
size (0),
type (XP_NUMBER),
bValue (false),
dValue (_value),
sValue (0),
nValue (0) {
} // CXPathItem
//---------------------------------------------------------------------
//
CXPathItem::CXPathItem(Pchar _value):
CItem (),
order (down),
position(0),
size (0),
type (XP_STRING),
bValue (false),
dValue (0.0),
sValue (0),
nValue (0) {
STRINIT(sValue, _value);
} // CXPathItem
//---------------------------------------------------------------------
//
CXPathItem::CXPathItem(RPCNodeList _value):
CItem (),
order (down),
position(0),
size (_value->Length()),
type (XP_NODESET),
bValue (false),
dValue (0.0),
sValue (0),
nValue (_value) {
if (size) {
node = nValue->Item(0);
position = 1;
}
} // CXPathItem
//---------------------------------------------------------------------
//
CXPathItem::CXPathItem(RPCNode _value):
CItem (),
node (_value),
order (down),
position(1),
size (1),
type (XP_NODESET),
bValue (false),
dValue (0.0),
sValue (0) {
nValue = new CNodeList();
nValue->InsertNode(_value);
} // CXPathItem
//---------------------------------------------------------------------
//
CXPathItem::CXPathItem(RPCXPathItem _value):
CItem (),
node (_value->node),
order (down),
position(_value->position),
size (_value->size),
type (_value->type),
bValue (_value->bValue),
dValue (_value->dValue),
sValue (0),
nValue (0) {
STRINIT(sValue, _value->sValue);
if (_value->nValue)
nValue = new CNodeList(_value->nValue);
} // CXPathItem
//---------------------------------------------------------------------
//
CXPathItem::~CXPathItem() {
delete[] sValue;
sValue = 0;
} // ~CXPathItem
//---------------------------------------------------------------------
//
RTTI_CPP(XPathItem, Item)
//---------------------------------------------------------------------
//
void CXPathItem::clear(void) {
if (type != XP_BOOLEAN)
bValue = false;
if (type != XP_NUMBER)
dValue = 0.0;
if (type != XP_STRING) {
delete[] sValue;
sValue = 0;
}
if (type != XP_NODESET)
nValue = 0;
} // clear
//---------------------------------------------------------------------
//
void CXPathItem::Set(bool _value) {
type = XP_BOOLEAN;
bValue = _value;
} // Set
//---------------------------------------------------------------------
//
void CXPathItem::Set(double _value) {
type = XP_NUMBER;
dValue = _value;
} // Set
//---------------------------------------------------------------------
//
void CXPathItem::Set(Pchar _value) {
type = XP_STRING;
STRINIT(sValue, _value);
} // Set
//---------------------------------------------------------------------
//
void CXPathItem::Set(RPCNodeList _value) {
type = XP_NODESET;
nValue = _value;
} // Set
//---------------------------------------------------------------------
//
ushort CXPathItem::Type(void) {
return type;
} // Type
//---------------------------------------------------------------------
//
bool CXPathItem::Boolean(void) {
Assert(type == XP_BOOLEAN);
return bValue;
} // Boolean
//---------------------------------------------------------------------
// Caller must delete the memory when done
//
Pdouble CXPathItem::Number(void) {
Assert(type == XP_NUMBER);
Pdouble p = new double;
*p = dValue;
return p;
} // Number
//---------------------------------------------------------------------
// Caller must delete the memory when done
//
Pchar CXPathItem::String(void) {
Assert(type == XP_STRING);
Pchar p = 0;
STRINIT(p, sValue);
return p;
} // String
//---------------------------------------------------------------------
//
PCNodeList CXPathItem::NodeSet(void) {
Assert(type == XP_NODESET);
return nValue;
} // NodeSet
//=====================================================================
// CXPathStack Implementation
//=====================================================================
//---------------------------------------------------------------------
//
CXPathStack::CXPathStack(void):
CList() {
} // CXPathStack
//---------------------------------------------------------------------
//
CXPathStack::~CXPathStack() {
} // ~CXPathStack
//---------------------------------------------------------------------
//
RTTI_CPP(XPathStack, List)
//---------------------------------------------------------------------
//
void CXPathStack::Init(void) {
Flush();
} // Init
//---------------------------------------------------------------------
//
void CXPathStack::Dup(void) {
if (!GotoHead())
throw(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
PCXPathItem newit = new CXPathItem(item);
PushX(newit);
} // Dup
//---------------------------------------------------------------------
//
ushort CXPathStack::TypeAtTOS(void) {
if (!GotoHead())
throw(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
return item->type;
} // TypeAtTOS
//---------------------------------------------------------------------
//
bool CXPathStack::BoolAtTOS(void) {
if (!GotoHead())
throw(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
return item->bValue;
} // BoolAtTOS
//---------------------------------------------------------------------
//
double CXPathStack::DblAtTOS(void) {
if (!GotoHead())
throw(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
return item->dValue;
} // DblAtTOS
//---------------------------------------------------------------------
//
Pchar CXPathStack::StrAtTOS(void) {
if (!GotoHead())
throw(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
return item->sValue;
} // StrAtTOS
//---------------------------------------------------------------------
//
PCNodeList CXPathStack::NodesAtTOS(void) {
if (!GotoHead())
throw(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
return item->nValue;
} // NodesAtTOS
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::ItemAtTOS(void) {
if (!GotoHead())
throw(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
return item;
} // ItemAtTOS
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushV(void) {
PCXPathItem item = new CXPathItem();
PCItem it
= TYPECAST(item, Item);
Insert(it, atTop);
return item;
} // PushV
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushL(void) {
PCXPathItem item = new CXPathItem();
item->type = XP_LPAREN;
PCItem it
= TYPECAST(item, Item);
Insert(it, atTop);
return item;
} // PushL
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushX(RPCXPathItem _value) {
PCItem item = TYPECAST(_value, Item);
Insert(item, atTop);
return _value;
} // PushX
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushB(bool _value) {
PCXPathItem item = new CXPathItem(_value);
PCItem it
= TYPECAST(item, Item);
Insert(it, atTop);
return item;
} // PushB
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushD(double _value) {
PCXPathItem item = new CXPathItem(_value);
PCItem it
= TYPECAST(item, Item);
Insert(it, atTop);
return item;
} // PushD
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushS(Pchar _value) {
PCXPathItem item = new CXPathItem(_value);
PCItem it
= TYPECAST(item, Item);
Insert(it, atTop);
return item;
} // PushS
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushNL(RPCNodeList _value) {
PCXPathItem item = new CXPathItem(_value);
PCItem it
= TYPECAST(item, Item);
Insert(it, atTop);
return item;
} // PushNL
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::PushN(RPCNode _value) {
PCXPathItem item = new CXPathItem(_value);
PCItem it
= TYPECAST(item, Item);
Insert(it, atTop);
return item;
} // PushN
//---------------------------------------------------------------------
//
void CXPathStack::SetTOS(bool _value) {
if (!GotoHead())
Assert(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
item->type = XP_BOOLEAN;
item->bValue = _value;
} // SetTOS
//---------------------------------------------------------------------
//
void CXPathStack::SetTOS(double _value) {
if (!GotoHead())
Assert(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
item->type = XP_NUMBER;
item->dValue = _value;
} // SetTOS
//---------------------------------------------------------------------
//
void CXPathStack::SetTOS(Pchar _value) {
if (!GotoHead())
Assert(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
item->type = XP_STRING;
STRINIT(item->sValue, _value);
} // SetTOS
//---------------------------------------------------------------------
//
void CXPathStack::SetTOS(RPCNodeList _value) {
if (!GotoHead())
Assert(XPE_UNDERRUN);
PCItem it
= Item();
PCXPathItem item = TYPECAST(it, XPathItem);
item->type = XP_NODESET;
item->nValue = _value;
} // SetTOS
//---------------------------------------------------------------------
//
PCXPathItem CXPathStack::Pop(void) {
if (!GotoHead())
Assert(XPE_UNDERRUN);
PCItem item = Remove(atTop, false);
return TYPECAST(item, XPathItem);
} // Pop