Did the boring cleanup job now that stuff works okay again:
- xpath.[ch] xpointer.c: restaured the Binary and API compatibility
cleaned up the parser internals, refactored XPath code, added
new compilation based APIs and cleanly separated public and
private APIs.
Daniel
diff --git a/xpath.c b/xpath.c
index 53f6138..134565b 100644
--- a/xpath.c
+++ b/xpath.c
@@ -522,7 +522,16 @@
}
#endif
-void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
+/**
+ * xmlXPathDebugDumpObject:
+ * @output: the FILE * to dump the output
+ * @cur: the object to inspect
+ * @depth: indentation level
+ *
+ * Dump the content of the object for debugging purposes
+ */
+void
+xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
int i;
char shift[100];
@@ -2298,19 +2307,6 @@
ret->cur = ret->base = str;
ret->context = ctxt;
- /* Allocate the value stack
- ret->valueTab = (xmlXPathObjectPtr *)
- xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
- if (ret->valueTab == NULL) {
- xmlFree(ret);
- xmlGenericError(xmlGenericErrorContext,
- "xmlXPathNewParserContext: out of memory\n");
- return(NULL);
- }
- ret->valueNr = 0;
- ret->valueMax = 10;
- ret->value = NULL; */
-
ret->comp = xmlXPathNewCompExpr();
if (ret->comp == NULL) {
xmlFree(ret->valueTab);
@@ -5336,14 +5332,14 @@
* a couple of forward declarations since we use a recursive call based
* implementation.
*/
-void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
-void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
-void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
+static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
+static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt);
+static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
#ifdef VMS
-void xmlXPathEvalRelLocationPath(xmlXPathParserContextPtr ctxt);
-#define xmlXPathEvalRelativeLocationPath xmlXPathEvalRelLocationPath
+static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
+#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
#else
-void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
+static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
#endif
/**
@@ -5454,7 +5450,7 @@
* | '.' Digits
* [31] Digits ::= [0-9]+
*
- * Parse and evaluate a Number in the string
+ * Compile a Number in the string
* In complement of the Number expression, this function also handles
* negative values : '-' Number.
*
@@ -5499,18 +5495,18 @@
}
/**
- * xmlXPathEvalNumber:
+ * xmlXPathCompNumber:
* @ctxt: the XPath Parser context
*
* [30] Number ::= Digits ('.' Digits?)?
* | '.' Digits
* [31] Digits ::= [0-9]+
*
- * Parse and evaluate a Number, then push it on the stack
+ * Compile a Number, then push it on the stack
*
*/
-void
-xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
double ret = 0.0;
double mult = 1;
int ok = 0;
@@ -5540,7 +5536,7 @@
}
/**
- * xmlXPathEvalLiteral:
+ * xmlXPathCompLiteral:
* @ctxt: the XPath Parser context
*
* Parse a Literal and push it on the stack.
@@ -5548,10 +5544,10 @@
* [29] Literal ::= '"' [^"]* '"'
* | "'" [^']* "'"
*
- * TODO: xmlXPathEvalLiteral memory allocation could be improved.
+ * TODO: xmlXPathCompLiteral memory allocation could be improved.
*/
-void
-xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
const xmlChar *q;
xmlChar *ret = NULL;
@@ -5587,7 +5583,7 @@
}
/**
- * xmlXPathEvalVariableReference:
+ * xmlXPathCompVariableReference:
* @ctxt: the XPath Parser context
*
* Parse a VariableReference, evaluate it and push it on the stack.
@@ -5603,8 +5599,8 @@
*
* [36] VariableReference ::= '$' QName
*/
-void
-xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
xmlChar *name;
xmlChar *prefix;
@@ -5653,17 +5649,17 @@
}
/**
- * xmlXPathEvalFunctionCall:
+ * xmlXPathCompFunctionCall:
* @ctxt: the XPath Parser context
*
* [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
* [17] Argument ::= Expr
*
- * Parse and evaluate a function call, the evaluation of all arguments are
+ * Compile a function call, the evaluation of all arguments are
* pushed on the stack
*/
-void
-xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
xmlChar *name;
xmlChar *prefix;
int nbargs = 0;
@@ -5692,7 +5688,7 @@
while (CUR != ')') {
int op1 = ctxt->comp->last;
ctxt->comp->last = -1;
- xmlXPathEvalExpr(ctxt);
+ xmlXPathCompileExpr(ctxt);
PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
nbargs++;
if (CUR == ')') break;
@@ -5709,7 +5705,7 @@
}
/**
- * xmlXPathEvalPrimaryExpr:
+ * xmlXPathCompPrimaryExpr:
* @ctxt: the XPath Parser context
*
* [15] PrimaryExpr ::= VariableReference
@@ -5718,39 +5714,39 @@
* | Number
* | FunctionCall
*
- * Parse and evaluate a primary expression, then push the result on the stack
+ * Compile a primary expression.
*/
-void
-xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
- if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
+ if (CUR == '$') xmlXPathCompVariableReference(ctxt);
else if (CUR == '(') {
NEXT;
SKIP_BLANKS;
- xmlXPathEvalExpr(ctxt);
+ xmlXPathCompileExpr(ctxt);
if (CUR != ')') {
XP_ERROR(XPATH_EXPR_ERROR);
}
NEXT;
SKIP_BLANKS;
} else if (IS_DIGIT(CUR)) {
- xmlXPathEvalNumber(ctxt);
+ xmlXPathCompNumber(ctxt);
} else if ((CUR == '\'') || (CUR == '"')) {
- xmlXPathEvalLiteral(ctxt);
+ xmlXPathCompLiteral(ctxt);
} else {
- xmlXPathEvalFunctionCall(ctxt);
+ xmlXPathCompFunctionCall(ctxt);
}
SKIP_BLANKS;
}
/**
- * xmlXPathEvalFilterExpr:
+ * xmlXPathCompFilterExpr:
* @ctxt: the XPath Parser context
*
* [20] FilterExpr ::= PrimaryExpr
* | FilterExpr Predicate
*
- * Parse and evaluate a filter expression, then push the result on the stack
+ * Compile a filter expression.
* Square brackets are used to filter expressions in the same way that
* they are used in location paths. It is an error if the expression to
* be filtered does not evaluate to a node-set. The context node list
@@ -5758,14 +5754,14 @@
* to be filtered listed in document order.
*/
-void
-xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalPrimaryExpr(ctxt);
+static void
+xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompPrimaryExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while (CUR == '[') {
- xmlXPathEvalPredicate(ctxt);
+ xmlXPathCompPredicate(ctxt);
SKIP_BLANKS;
}
@@ -5823,7 +5819,7 @@
}
/**
- * xmlXPathEvalPathExpr:
+ * xmlXPathCompPathExpr:
* @ctxt: the XPath Parser context
*
* [19] PathExpr ::= LocationPath
@@ -5831,7 +5827,7 @@
* | FilterExpr '/' RelativeLocationPath
* | FilterExpr '//' RelativeLocationPath
*
- * Parse and evaluate a path expression, then push the result on the stack
+ * Compile a path expression.
* The / operator and // operators combine an arbitrary expression
* and a relative location path. It is an error if the expression
* does not evaluate to a node-set.
@@ -5840,8 +5836,8 @@
* /descendant-or-self::node()/.
*/
-void
-xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
int lc = 1; /* Should we branch to LocationPath ? */
xmlChar *name = NULL; /* we may have to preparse a name to find out */
@@ -5961,9 +5957,9 @@
} else {
PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
}
- xmlXPathEvalLocationPath(ctxt);
+ xmlXPathCompLocationPath(ctxt);
} else {
- xmlXPathEvalFilterExpr(ctxt);
+ xmlXPathCompFilterExpr(ctxt);
CHECK_ERROR;
if ((CUR == '/') && (NXT(1) == '/')) {
SKIP(2);
@@ -5973,27 +5969,27 @@
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
- xmlXPathEvalRelativeLocationPath(ctxt);
+ xmlXPathCompRelativeLocationPath(ctxt);
} else if (CUR == '/') {
- xmlXPathEvalRelativeLocationPath(ctxt);
+ xmlXPathCompRelativeLocationPath(ctxt);
}
}
SKIP_BLANKS;
}
/**
- * xmlXPathEvalUnionExpr:
+ * xmlXPathCompUnionExpr:
* @ctxt: the XPath Parser context
*
* [18] UnionExpr ::= PathExpr
* | UnionExpr '|' PathExpr
*
- * Parse and evaluate an union expression, then push the result on the stack
+ * Compile an union expression.
*/
-void
-xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalPathExpr(ctxt);
+static void
+xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompPathExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while (CUR == '|') {
@@ -6002,7 +5998,7 @@
NEXT;
SKIP_BLANKS;
- xmlXPathEvalPathExpr(ctxt);
+ xmlXPathCompPathExpr(ctxt);
PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
@@ -6011,17 +6007,17 @@
}
/**
- * xmlXPathEvalUnaryExpr:
+ * xmlXPathCompUnaryExpr:
* @ctxt: the XPath Parser context
*
* [27] UnaryExpr ::= UnionExpr
* | '-' UnaryExpr
*
- * Parse and evaluate an unary expression, then push the result on the stack
+ * Compile an unary expression.
*/
-void
-xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
int minus = 0;
int found = 0;
@@ -6033,7 +6029,7 @@
SKIP_BLANKS;
}
- xmlXPathEvalUnionExpr(ctxt);
+ xmlXPathCompUnionExpr(ctxt);
CHECK_ERROR;
if (found) {
if (minus)
@@ -6044,7 +6040,7 @@
}
/**
- * xmlXPathEvalMultiplicativeExpr:
+ * xmlXPathCompMultiplicativeExpr:
* @ctxt: the XPath Parser context
*
* [26] MultiplicativeExpr ::= UnaryExpr
@@ -6053,12 +6049,12 @@
* | MultiplicativeExpr 'mod' UnaryExpr
* [34] MultiplyOperator ::= '*'
*
- * Parse and evaluate an Additive expression, then push the result on the stack
+ * Compile an Additive expression.
*/
-void
-xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalUnaryExpr(ctxt);
+static void
+xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompUnaryExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '*') ||
@@ -6078,7 +6074,7 @@
SKIP(3);
}
SKIP_BLANKS;
- xmlXPathEvalUnaryExpr(ctxt);
+ xmlXPathCompUnaryExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
SKIP_BLANKS;
@@ -6086,20 +6082,20 @@
}
/**
- * xmlXPathEvalAdditiveExpr:
+ * xmlXPathCompAdditiveExpr:
* @ctxt: the XPath Parser context
*
* [25] AdditiveExpr ::= MultiplicativeExpr
* | AdditiveExpr '+' MultiplicativeExpr
* | AdditiveExpr '-' MultiplicativeExpr
*
- * Parse and evaluate an Additive expression, then push the result on the stack
+ * Compile an Additive expression.
*/
-void
-xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalMultiplicativeExpr(ctxt);
+ xmlXPathCompMultiplicativeExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '+') || (CUR == '-')) {
@@ -6110,7 +6106,7 @@
else plus = 0;
NEXT;
SKIP_BLANKS;
- xmlXPathEvalMultiplicativeExpr(ctxt);
+ xmlXPathCompMultiplicativeExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
SKIP_BLANKS;
@@ -6118,7 +6114,7 @@
}
/**
- * xmlXPathEvalRelationalExpr:
+ * xmlXPathCompRelationalExpr:
* @ctxt: the XPath Parser context
*
* [24] RelationalExpr ::= AdditiveExpr
@@ -6131,13 +6127,13 @@
* (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
* which is basically what got implemented.
*
- * Parse and evaluate a Relational expression, then push the result
+ * Compile a Relational expression, then push the result
* on the stack
*/
-void
-xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalAdditiveExpr(ctxt);
+static void
+xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompAdditiveExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '<') ||
@@ -6154,7 +6150,7 @@
NEXT;
if (!strict) NEXT;
SKIP_BLANKS;
- xmlXPathEvalAdditiveExpr(ctxt);
+ xmlXPathCompAdditiveExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
SKIP_BLANKS;
@@ -6162,7 +6158,7 @@
}
/**
- * xmlXPathEvalEqualityExpr:
+ * xmlXPathCompEqualityExpr:
* @ctxt: the XPath Parser context
*
* [23] EqualityExpr ::= RelationalExpr
@@ -6174,12 +6170,12 @@
* (RelationalExpr != RelationalExpr) != RelationalExpr
* which is basically what got implemented.
*
- * Parse and evaluate an Equality expression, then push the result on the stack
+ * Compile an Equality expression.
*
*/
-void
-xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalRelationalExpr(ctxt);
+static void
+xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompRelationalExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
@@ -6191,7 +6187,7 @@
NEXT;
if (!eq) NEXT;
SKIP_BLANKS;
- xmlXPathEvalRelationalExpr(ctxt);
+ xmlXPathCompRelationalExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
SKIP_BLANKS;
@@ -6199,25 +6195,25 @@
}
/**
- * xmlXPathEvalAndExpr:
+ * xmlXPathCompAndExpr:
* @ctxt: the XPath Parser context
*
* [22] AndExpr ::= EqualityExpr
* | AndExpr 'and' EqualityExpr
*
- * Parse and evaluate an AND expression, then push the result on the stack
+ * Compile an AND expression.
*
*/
-void
-xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalEqualityExpr(ctxt);
+static void
+xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompEqualityExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
int op1 = ctxt->comp->last;
SKIP(3);
SKIP_BLANKS;
- xmlXPathEvalEqualityExpr(ctxt);
+ xmlXPathCompEqualityExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
SKIP_BLANKS;
@@ -6225,26 +6221,25 @@
}
/**
- * xmlXPathEvalExpr:
+ * xmlXPathCompExpr:
* @ctxt: the XPath Parser context
*
* [14] Expr ::= OrExpr
* [21] OrExpr ::= AndExpr
* | OrExpr 'or' AndExpr
*
- * Parse and evaluate an expression, then push the result on the stack
- *
+ * Parse and compile an expression
*/
-void
-xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
- xmlXPathEvalAndExpr(ctxt);
+static void
+xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompAndExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == 'o') && (NXT(1) == 'r')) {
int op1 = ctxt->comp->last;
SKIP(2);
SKIP_BLANKS;
- xmlXPathEvalAndExpr(ctxt);
+ xmlXPathCompAndExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
op1 = ctxt->comp->nbStep;
@@ -6257,181 +6252,16 @@
}
/**
- * xmlXPathEvaluatePredicateResult:
- * @ctxt: the XPath Parser context
- * @res: the Predicate Expression evaluation result
- *
- * Evaluate a predicate result for the current node.
- * A PredicateExpr is evaluated by evaluating the Expr and converting
- * the result to a boolean. If the result is a number, the result will
- * be converted to true if the number is equal to the position of the
- * context node in the context node list (as returned by the position
- * function) and will be converted to false otherwise; if the result
- * is not a number, then the result will be converted as if by a call
- * to the boolean function.
- *
- * Return 1 if predicate is true, 0 otherwise
- */
-int
-xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
- xmlXPathObjectPtr res) {
- if (res == NULL) return(0);
- switch (res->type) {
- case XPATH_BOOLEAN:
- return(res->boolval);
- case XPATH_NUMBER:
- return(res->floatval == ctxt->context->proximityPosition);
- case XPATH_NODESET:
- case XPATH_XSLT_TREE:
- return(res->nodesetval->nodeNr != 0);
- case XPATH_STRING:
- return((res->stringval != NULL) &&
- (xmlStrlen(res->stringval) != 0));
- default:
- STRANGE
- }
- return(0);
-}
-
-/**
- * xmlXPathRunPredicate:
+ * xmlXPathCompPredicate:
* @ctxt: the XPath Parser context
*
* [8] Predicate ::= '[' PredicateExpr ']'
* [9] PredicateExpr ::= Expr
*
- * ---------------------
- * For each node in the node-set to be filtered, the PredicateExpr is
- * evaluated with that node as the context node, with the number of nodes
- * in the node-set as the context size, and with the proximity position
- * of the node in the node-set with respect to the axis as the context
- * position; if PredicateExpr evaluates to true for that node, the node
- * is included in the new node-set; otherwise, it is not included.
- * ---------------------
- *
- * Parse and evaluate a predicate for all the elements of the
- * current node list. Then refine the list by removing all
- * nodes where the predicate is false.
+ * Compile a predicate expression
*/
-void
-xmlXPathRunPredicate(xmlXPathParserContextPtr ctxt) {
- const xmlChar *cur;
- xmlXPathObjectPtr res;
- xmlXPathObjectPtr obj, tmp;
- xmlNodeSetPtr newset = NULL;
- xmlNodeSetPtr oldset;
- xmlNodePtr oldnode;
- int i;
-
- /* TODO ... */
-
- SKIP_BLANKS;
- if (CUR != '[') {
- XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
- }
- NEXT;
- SKIP_BLANKS;
-
- /*
- * Extract the old set, and then evaluate the result of the
- * expression for all the element in the set. use it to grow
- * up a new set.
- */
- CHECK_TYPE(XPATH_NODESET);
- obj = valuePop(ctxt);
- oldset = obj->nodesetval;
- oldnode = ctxt->context->node;
- ctxt->context->node = NULL;
-
- if ((oldset == NULL) || (oldset->nodeNr == 0)) {
- ctxt->context->contextSize = 0;
- ctxt->context->proximityPosition = 0;
- xmlXPathEvalExpr(ctxt);
- res = valuePop(ctxt);
- if (res != NULL)
- xmlXPathFreeObject(res);
- valuePush(ctxt, obj);
- CHECK_ERROR;
- } else {
- /*
- * Save the expression pointer since we will have to evaluate
- * it multiple times. Initialize the new set.
- */
- cur = ctxt->cur;
- newset = xmlXPathNodeSetCreate(NULL);
-
- for (i = 0; i < oldset->nodeNr; i++) {
- ctxt->cur = cur;
-
- /*
- * Run the evaluation with a node list made of a single item
- * in the nodeset.
- */
- ctxt->context->node = oldset->nodeTab[i];
- tmp = xmlXPathNewNodeSet(ctxt->context->node);
- valuePush(ctxt, tmp);
- ctxt->context->contextSize = oldset->nodeNr;
- ctxt->context->proximityPosition = i + 1;
-
- xmlXPathEvalExpr(ctxt);
- CHECK_ERROR;
-
- /*
- * The result of the evaluation need to be tested to
- * decided whether the filter succeeded or not
- */
- res = valuePop(ctxt);
- if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
- xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
- }
-
- /*
- * Cleanup
- */
- if (res != NULL)
- xmlXPathFreeObject(res);
- if (ctxt->value == tmp) {
- res = valuePop(ctxt);
- xmlXPathFreeObject(res);
- }
-
- ctxt->context->node = NULL;
- }
-
- /*
- * The result is used as the new evaluation set.
- */
- xmlXPathFreeObject(obj);
- ctxt->context->node = NULL;
- ctxt->context->contextSize = -1;
- ctxt->context->proximityPosition = -1;
- valuePush(ctxt, xmlXPathWrapNodeSet(newset));
- }
- if (CUR != ']') {
- XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
- }
-
- PUSH_UNARY_EXPR(XPATH_OP_PREDICATE, ctxt->comp->last, 0, 0);
-
- NEXT;
- SKIP_BLANKS;
-#ifdef DEBUG_STEP
- xmlGenericError(xmlGenericErrorContext, "After predicate : ");
- xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
- ctxt->value->nodesetval);
-#endif
- ctxt->context->node = oldnode;
-}
-
-/**
- * xmlXPathEvalPredicate:
- * @ctxt: the XPath Parser context
- *
- * [8] Predicate ::= '[' PredicateExpr ']'
- * [9] PredicateExpr ::= Expr
- */
-void
-xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt) {
int op1 = ctxt->comp->last;
SKIP_BLANKS;
@@ -6442,7 +6272,7 @@
SKIP_BLANKS;
ctxt->comp->last = -1;
- xmlXPathEvalExpr(ctxt);
+ xmlXPathCompileExpr(ctxt);
CHECK_ERROR;
if (CUR != ']') {
@@ -6456,7 +6286,7 @@
}
/**
- * xmlXPathEvalNodeTest:
+ * xmlXPathCompNodeTest:
* @ctxt: the XPath Parser context
* @test: pointer to a xmlXPathTestVal
* @type: pointer to a xmlXPathTypeVal
@@ -6477,8 +6307,9 @@
* Returns the name found and update @test, @type and @prefix appropriately
*/
xmlChar *
-xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
- xmlXPathTypeVal *type, const xmlChar **prefix, xmlChar *name) {
+xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
+ xmlXPathTypeVal *type, const xmlChar **prefix,
+ xmlChar *name) {
int blanks;
if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
@@ -6538,7 +6369,7 @@
if (name != NULL)
xmlFree(name);
- xmlXPathEvalLiteral(ctxt);
+ xmlXPathCompLiteral(ctxt);
CHECK_ERROR 0;
xmlXPathStringFunction(ctxt, 1);
CHECK_ERROR0;
@@ -6655,14 +6486,15 @@
}
/**
- * xmlXPathEvalAxisSpecifier:
+ * xmlXPathCompAxisSpecifier:
* @ctxt: the XPath Parser context
*
+ * Parse an axis value
*
* Returns the axis found
*/
xmlXPathAxisVal
-xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
+xmlXPathCompAxisSpecifier(xmlXPathParserContextPtr ctxt) {
xmlXPathAxisVal ret = AXIS_CHILD;
int blank = 0;
xmlChar *name;
@@ -6689,7 +6521,7 @@
}
/**
- * xmlXPathEvalStep:
+ * xmlXPathCompStep:
* @ctxt: the XPath Parser context
*
* [4] Step ::= AxisSpecifier NodeTest Predicate*
@@ -6708,7 +6540,7 @@
* | AbbreviatedStep
* | 'range-to' '(' Expr ')' Predicate*
*
- * Evaluate one step in a Location Path
+ * Compile one step in a Location Path
* A location step of . is short for self::node(). This is
* particularly useful in conjunction with //. For example, the
* location path .//para is short for
@@ -6720,8 +6552,8 @@
* and so will select the title children of the parent of the context
* node.
*/
-void
-xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
if ((CUR == '.') && (NXT(1) == '.')) {
SKIP(2);
@@ -6754,7 +6586,7 @@
NEXT;
SKIP_BLANKS;
- xmlXPathEvalExpr(ctxt);
+ xmlXPathCompileExpr(ctxt);
PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op1, ctxt->comp->last, 0, 0);
CHECK_ERROR;
@@ -6793,7 +6625,7 @@
CHECK_ERROR;
- name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
+ name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
if (test == 0)
return;
@@ -6813,7 +6645,7 @@
eval_predicates:
SKIP_BLANKS;
while (CUR == '[') {
- xmlXPathEvalPredicate(ctxt);
+ xmlXPathCompPredicate(ctxt);
}
}
#ifdef DEBUG_STEP
@@ -6824,7 +6656,7 @@
}
/**
- * xmlXPathEvalRelativeLocationPath:
+ * xmlXPathCompRelativeLocationPath:
* @ctxt: the XPath Parser context
*
* [3] RelativeLocationPath ::= Step
@@ -6832,12 +6664,13 @@
* | AbbreviatedRelativeLocationPath
* [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
*
+ * Compile a relative location path.
*/
-void
+static void
#ifdef VMS
-xmlXPathEvalRelLocationPath
+xmlXPathCompRelLocationPath
#else
-xmlXPathEvalRelativeLocationPath
+xmlXPathCompRelativeLocationPath
#endif
(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
@@ -6850,7 +6683,7 @@
NEXT;
SKIP_BLANKS;
}
- xmlXPathEvalStep(ctxt);
+ xmlXPathCompStep(ctxt);
SKIP_BLANKS;
while (CUR == '/') {
if ((CUR == '/') && (NXT(1) == '/')) {
@@ -6858,18 +6691,18 @@
SKIP_BLANKS;
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
- xmlXPathEvalStep(ctxt);
+ xmlXPathCompStep(ctxt);
} else if (CUR == '/') {
NEXT;
SKIP_BLANKS;
- xmlXPathEvalStep(ctxt);
+ xmlXPathCompStep(ctxt);
}
SKIP_BLANKS;
}
}
/**
- * xmlXPathEvalLocationPath:
+ * xmlXPathCompLocationPath:
* @ctxt: the XPath Parser context
*
* [1] LocationPath ::= RelativeLocationPath
@@ -6879,6 +6712,8 @@
* [10] AbbreviatedAbsoluteLocationPath ::=
* '//' RelativeLocationPath
*
+ * Compile a location path
+ *
* // is short for /descendant-or-self::node()/. For example,
* //para is short for /descendant-or-self::node()/child::para and
* so will select any para element in the document (even a para element
@@ -6887,11 +6722,11 @@
* short for div/descendant-or-self::node()/child::para and so will
* select all para descendants of div children.
*/
-void
-xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
+static void
+xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
if (CUR != '/') {
- xmlXPathEvalRelativeLocationPath(ctxt);
+ xmlXPathCompRelativeLocationPath(ctxt);
} else {
while (CUR == '/') {
if ((CUR == '/') && (NXT(1) == '/')) {
@@ -6899,12 +6734,12 @@
SKIP_BLANKS;
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
- xmlXPathEvalRelativeLocationPath(ctxt);
+ xmlXPathCompRelativeLocationPath(ctxt);
} else if (CUR == '/') {
NEXT;
SKIP_BLANKS;
if (CUR != 0)
- xmlXPathEvalRelativeLocationPath(ctxt);
+ xmlXPathCompRelativeLocationPath(ctxt);
}
}
}
@@ -7378,6 +7213,74 @@
xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
}
+/************************************************************************
+ * *
+ * Public interfaces *
+ * *
+ ************************************************************************/
+
+/**
+ * xmlXPathEvaluatePredicateResult:
+ * @ctxt: the XPath Parser context
+ * @res: the Predicate Expression evaluation result
+ *
+ * Evaluate a predicate result for the current node.
+ * A PredicateExpr is evaluated by evaluating the Expr and converting
+ * the result to a boolean. If the result is a number, the result will
+ * be converted to true if the number is equal to the position of the
+ * context node in the context node list (as returned by the position
+ * function) and will be converted to false otherwise; if the result
+ * is not a number, then the result will be converted as if by a call
+ * to the boolean function.
+ *
+ * Return 1 if predicate is true, 0 otherwise
+ */
+int
+xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
+ xmlXPathObjectPtr res) {
+ if (res == NULL) return(0);
+ switch (res->type) {
+ case XPATH_BOOLEAN:
+ return(res->boolval);
+ case XPATH_NUMBER:
+ return(res->floatval == ctxt->context->proximityPosition);
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ return(res->nodesetval->nodeNr != 0);
+ case XPATH_STRING:
+ return((res->stringval != NULL) &&
+ (xmlStrlen(res->stringval) != 0));
+ default:
+ STRANGE
+ }
+ return(0);
+}
+
+/**
+ * xmlXPathCompile:
+ * @str: the XPath expression
+ *
+ * Compile an XPath expression
+ *
+ * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
+ * the caller has to free the object.
+ */
+xmlXPathCompExprPtr
+xmlXPathCompile(const xmlChar *str) {
+ xmlXPathParserContextPtr ctxt;
+ xmlXPathCompExprPtr comp;
+
+ xmlXPathInit();
+
+ ctxt = xmlXPathNewParserContext(str, NULL);
+ xmlXPathCompileExpr(ctxt);
+
+ comp = ctxt->comp;
+ ctxt->comp = NULL;
+ xmlXPathFreeParserContext(ctxt);
+ return(comp);
+}
+
/**
* xmlXPathCompiledEval:
* @comp: the compiled XPath expression
@@ -7434,15 +7337,23 @@
xmlXPathDebugDumpCompExpr(stdout, ctxt->comp, 0);
+ ctxt->comp = NULL;
xmlXPathFreeParserContext(ctxt);
return(res);
}
-/************************************************************************
- * *
- * Main interfaces *
- * *
- ************************************************************************/
+/**
+ * xmlXPathEvalExpr:
+ * @ctxt: the XPath Parser context
+ *
+ * Parse and evaluate an XPath expression in the given context,
+ * then push the result on the context stack
+ */
+void
+xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
+ xmlXPathCompileExpr(ctxt);
+ xmlXPathRunEval(ctxt);
+}
/**
* xmlXPathEval:
@@ -7466,8 +7377,6 @@
ctxt = xmlXPathNewParserContext(str, ctx);
xmlXPathEvalExpr(ctxt);
- /* xmlXPathDebugDumpCompExpr(stdout, ctxt->comp, 0); */
- xmlXPathRunEval(ctxt);
if (ctxt->value == NULL) {
xmlGenericError(xmlGenericErrorContext,
@@ -7524,7 +7433,6 @@
pctxt = xmlXPathNewParserContext(str, ctxt);
xmlXPathEvalExpr(pctxt);
- xmlXPathRunEval(pctxt);
if (*pctxt->cur != 0) {
xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);