blob: c9d5ed68ee497c806a1c46574d8f38fbfaf9a754 [file] [log] [blame]
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001/*
2 * xpath.c: XML Path Language implementation
3 * XPath is a language for addressing parts of an XML document,
Daniel Veillard55b91f22000-10-05 16:30:11 +00004 * designed to be used by both XSLT and XPointer
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00006 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
Daniel Veillard1566d3a1999-07-15 14:24:29 +00008 * Public reference:
Daniel Veillard55b91f22000-10-05 16:30:11 +00009 * http://www.w3.org/TR/xpath
Daniel Veillard1566d3a1999-07-15 14:24:29 +000010 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#else
19#include "config.h"
20#endif
21
Daniel Veillardb71379b2000-10-09 12:30:39 +000022#include <libxml/xmlversion.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000023#ifdef LIBXML_XPATH_ENABLED
24
Daniel Veillard7f7d1111999-09-22 09:46:25 +000025#include <stdio.h>
26#include <string.h>
27
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000031#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000032#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000033#endif
34#ifdef HAVE_MATH_H
35#include <float.h>
36#endif
37#ifdef HAVE_IEEEFP_H
38#include <ieeefp.h>
39#endif
40#ifdef HAVE_NAN_H
41#include <nan.h>
42#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000043#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000044#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000045#endif
46
Daniel Veillard361d8452000-04-03 19:48:13 +000047#include <libxml/xmlmemory.h>
48#include <libxml/tree.h>
49#include <libxml/valid.h>
50#include <libxml/xpath.h>
Daniel Veillard29a11cc2000-10-25 13:32:39 +000051#include <libxml/xpathInternals.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000052#include <libxml/parserInternals.h>
Daniel Veillard52afe802000-10-22 16:56:02 +000053#include <libxml/hash.h>
Daniel Veillardac260302000-10-04 13:33:43 +000054#ifdef LIBXML_XPTR_ENABLED
55#include <libxml/xpointer.h>
56#endif
Daniel Veillardc2df4cd2000-10-12 23:15:24 +000057#ifdef LIBXML_DEBUG_ENABLED
58#include <libxml/debugXML.h>
59#endif
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000060#include <libxml/xmlerror.h>
Daniel Veillard1566d3a1999-07-15 14:24:29 +000061
Daniel Veillarddbfd6411999-12-28 16:35:14 +000062/* #define DEBUG */
63/* #define DEBUG_STEP */
64/* #define DEBUG_EXPR */
65
Daniel Veillardc2df4cd2000-10-12 23:15:24 +000066void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
67double xmlXPathStringEvalNumber(const xmlChar *str);
68
Daniel Veillard1566d3a1999-07-15 14:24:29 +000069/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000070 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000071 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000072 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000073double xmlXPathNAN = 0;
74double xmlXPathPINF = 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +000075double xmlXPathNINF = -1;
Daniel Veillarde2d034d1999-07-27 19:52:06 +000076
Daniel Veillardb05deb71999-08-10 19:04:08 +000077#ifndef isinf
78#ifndef HAVE_ISINF
79
80#if HAVE_FPCLASS
81
82int isinf(double d) {
83 fpclass_t type = fpclass(d);
84 switch (type) {
85 case FP_NINF:
86 return(-1);
87 case FP_PINF:
88 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000089 }
90 return(0);
91}
92
93#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
94
95#if HAVE_FP_CLASS_H
96#include <fp_class.h>
97#endif
98
99int isinf(double d) {
100#if HAVE_FP_CLASS
101 int fpclass = fp_class(d);
102#else
103 int fpclass = fp_class_d(d);
104#endif
105 if (fpclass == FP_POS_INF)
106 return(1);
107 if (fpclass == FP_NEG_INF)
108 return(-1);
109 return(0);
110}
111
112#elif defined(HAVE_CLASS)
113
114int isinf(double d) {
115 int fpclass = class(d);
116 if (fpclass == FP_PLUS_INF)
117 return(1);
118 if (fpclass == FP_MINUS_INF)
119 return(-1);
120 return(0);
121}
122#elif defined(finite) || defined(HAVE_FINITE)
123int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000124#elif defined(HUGE_VAL)
Daniel Veillardfc708e22000-04-08 13:17:27 +0000125int isinf(double x)
Daniel Veillard991e63d1999-08-15 23:32:28 +0000126{
127 if (x == HUGE_VAL)
128 return(1);
129 if (x == -HUGE_VAL)
130 return(-1);
131 return(0);
132}
133#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000134
135#endif /* ! HAVE_ISINF */
136#endif /* ! defined(isinf) */
137
138#ifndef isnan
139#ifndef HAVE_ISNAN
140
141#ifdef HAVE_ISNAND
142#define isnan(f) isnand(f)
143#endif /* HAVE_iSNAND */
144
145#endif /* ! HAVE_iSNAN */
146#endif /* ! defined(isnan) */
147
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000148/**
149 * xmlXPathInit:
150 *
151 * Initialize the XPath environment
152 */
153void
154xmlXPathInit(void) {
155 static int initialized = 0;
156
157 if (initialized) return;
158
159 xmlXPathNAN = 0;
160 xmlXPathNAN /= 0;
161
162 xmlXPathPINF = 1;
163 xmlXPathPINF /= 0;
164
Daniel Veillardf6bf9212000-10-26 14:07:44 +0000165 xmlXPathNINF = -1;
166 xmlXPathNINF /= 0;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000167
168 initialized = 1;
169}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000170
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000171/************************************************************************
172 * *
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000173 * Debugging related functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000174 * *
175 ************************************************************************/
176
Daniel Veillard7e99c632000-10-06 12:59:53 +0000177#define TODO \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000178 xmlGenericError(xmlGenericErrorContext, \
179 "Unimplemented block at %s:%d\n", \
Daniel Veillard7e99c632000-10-06 12:59:53 +0000180 __FILE__, __LINE__);
181
182#define STRANGE \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000183 xmlGenericError(xmlGenericErrorContext, \
184 "Internal error at %s:%d\n", \
Daniel Veillard7e99c632000-10-06 12:59:53 +0000185 __FILE__, __LINE__);
186
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000187#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000188void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
189 int i;
190 char shift[100];
191
192 for (i = 0;((i < depth) && (i < 25));i++)
193 shift[2 * i] = shift[2 * i + 1] = ' ';
194 shift[2 * i] = shift[2 * i + 1] = 0;
195 if (cur == NULL) {
196 fprintf(output, shift);
197 fprintf(output, "Node is NULL !\n");
198 return;
199
200 }
201
202 if ((cur->type == XML_DOCUMENT_NODE) ||
203 (cur->type == XML_HTML_DOCUMENT_NODE)) {
204 fprintf(output, shift);
205 fprintf(output, " /\n");
206 } else if (cur->type == XML_ATTRIBUTE_NODE)
207 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
208 else
209 xmlDebugDumpOneNode(output, cur, depth);
210}
211
212void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
213 int i;
214 char shift[100];
215
216 for (i = 0;((i < depth) && (i < 25));i++)
217 shift[2 * i] = shift[2 * i + 1] = ' ';
218 shift[2 * i] = shift[2 * i + 1] = 0;
219
220 if (cur == NULL) {
221 fprintf(output, shift);
222 fprintf(output, "NodeSet is NULL !\n");
223 return;
224
225 }
226
227 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
228 for (i = 0;i < cur->nodeNr;i++) {
229 fprintf(output, shift);
230 fprintf(output, "%d", i + 1);
231 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
232 }
233}
234
235#if defined(LIBXML_XPTR_ENABLED)
236void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
237void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
238 int i;
239 char shift[100];
240
241 for (i = 0;((i < depth) && (i < 25));i++)
242 shift[2 * i] = shift[2 * i + 1] = ' ';
243 shift[2 * i] = shift[2 * i + 1] = 0;
244
245 if (cur == NULL) {
246 fprintf(output, shift);
247 fprintf(output, "LocationSet is NULL !\n");
248 return;
249
250 }
251
252 for (i = 0;i < cur->locNr;i++) {
253 fprintf(output, shift);
254 fprintf(output, "%d : ", i + 1);
255 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
256 }
257}
258#endif
259
260void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
261 int i;
262 char shift[100];
263
264 for (i = 0;((i < depth) && (i < 25));i++)
265 shift[2 * i] = shift[2 * i + 1] = ' ';
266 shift[2 * i] = shift[2 * i + 1] = 0;
267
268 fprintf(output, shift);
269
270 if (cur == NULL) {
271 fprintf(output, "Object is empty (NULL)\n");
272 return;
273 }
274 switch(cur->type) {
275 case XPATH_UNDEFINED:
276 fprintf(output, "Object is uninitialized\n");
277 break;
278 case XPATH_NODESET:
279 fprintf(output, "Object is a Node Set :\n");
280 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
281 break;
282 case XPATH_BOOLEAN:
283 fprintf(output, "Object is a Boolean : ");
284 if (cur->boolval) fprintf(output, "true\n");
285 else fprintf(output, "false\n");
286 break;
287 case XPATH_NUMBER:
288 fprintf(output, "Object is a number : %0g\n", cur->floatval);
289 break;
290 case XPATH_STRING:
291 fprintf(output, "Object is a string : ");
292 xmlDebugDumpString(output, cur->stringval);
293 fprintf(output, "\n");
294 break;
295 case XPATH_POINT:
296 fprintf(output, "Object is a point : index %d in node", cur->index);
297 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
298 fprintf(output, "\n");
299 break;
300 case XPATH_RANGE:
301 if ((cur->user2 == NULL) ||
302 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
303 fprintf(output, "Object is a collapsed range :\n");
304 fprintf(output, shift);
305 if (cur->index >= 0)
306 fprintf(output, "index %d in ", cur->index);
307 fprintf(output, "node\n");
308 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
309 depth + 1);
310 } else {
311 fprintf(output, "Object is a range :\n");
312 fprintf(output, shift);
313 fprintf(output, "From ");
314 if (cur->index >= 0)
315 fprintf(output, "index %d in ", cur->index);
316 fprintf(output, "node\n");
317 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
318 depth + 1);
319 fprintf(output, shift);
320 fprintf(output, "To ");
321 if (cur->index2 >= 0)
322 fprintf(output, "index %d in ", cur->index2);
323 fprintf(output, "node\n");
324 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
325 depth + 1);
326 fprintf(output, "\n");
327 }
328 break;
329 case XPATH_LOCATIONSET:
330#if defined(LIBXML_XPTR_ENABLED)
331 fprintf(output, "Object is a Location Set:\n");
332 xmlXPathDebugDumpLocationSet(output,
333 (xmlLocationSetPtr) cur->user, depth);
334#endif
335 break;
336 case XPATH_USERS:
337 fprintf(output, "Object is user defined\n");
338 break;
339 }
340}
341#endif
342
343/************************************************************************
344 * *
345 * Parser stacks related functions and macros *
346 * *
347 ************************************************************************/
348
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000349/*
350 * Generic function for accessing stacks in the Parser Context
351 */
352
353#define PUSH_AND_POP(type, name) \
354extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
355 if (ctxt->name##Nr >= ctxt->name##Max) { \
356 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000357 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000358 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
359 if (ctxt->name##Tab == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000360 xmlGenericError(xmlGenericErrorContext, \
361 "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000362 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000363 } \
364 } \
365 ctxt->name##Tab[ctxt->name##Nr] = value; \
366 ctxt->name = value; \
367 return(ctxt->name##Nr++); \
368} \
369extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
370 type ret; \
371 if (ctxt->name##Nr <= 0) return(0); \
372 ctxt->name##Nr--; \
373 if (ctxt->name##Nr > 0) \
374 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
375 else \
376 ctxt->name = NULL; \
377 ret = ctxt->name##Tab[ctxt->name##Nr]; \
378 ctxt->name##Tab[ctxt->name##Nr] = 0; \
379 return(ret); \
380} \
381
382PUSH_AND_POP(xmlXPathObjectPtr, value)
383
384/*
385 * Macros for accessing the content. Those should be used only by the parser,
386 * and not exported.
387 *
388 * Dirty macros, i.e. one need to make assumption on the context to use them
389 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000390 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000391 * CUR returns the current xmlChar value, i.e. a 8 bit value
392 * in ISO-Latin or UTF-8.
393 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000394 * only to compare to ASCII values otherwise it would break when
395 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000396 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000397 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000398 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000399 * strings within the parser.
400 * CURRENT Returns the current char value, with the full decoding of
401 * UTF-8 if we are using this mode. It returns an int.
402 * NEXT Skip to the next character, this does the proper decoding
403 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000404 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000405 */
406
407#define CUR (*ctxt->cur)
408#define SKIP(val) ctxt->cur += (val)
409#define NXT(val) ctxt->cur[(val)]
410#define CUR_PTR ctxt->cur
411
412#define SKIP_BLANKS \
413 while (IS_BLANK(*(ctxt->cur))) NEXT
414
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000415#define CURRENT (*ctxt->cur)
416#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000417
418/************************************************************************
419 * *
420 * Error handling routines *
421 * *
422 ************************************************************************/
423
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000424
425const char *xmlXPathErrorMessages[] = {
426 "Ok",
427 "Number encoding",
428 "Unfinished litteral",
429 "Start of litteral",
430 "Expected $ for variable reference",
431 "Undefined variable",
432 "Invalid predicate",
433 "Invalid expression",
434 "Missing closing curly brace",
435 "Unregistered function",
436 "Invalid operand",
437 "Invalid type",
438 "Invalid number of arguments",
Daniel Veillardf09e7e32000-10-01 15:53:30 +0000439 "Invalid context size",
440 "Invalid context position",
Daniel Veillardb71379b2000-10-09 12:30:39 +0000441 "Memory allocation error",
442 "Syntax error",
443 "Resource error",
444 "Sub resource error"
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000445};
446
447/**
448 * xmlXPathError:
449 * @ctxt: the XPath Parser context
450 * @file: the file name
451 * @line: the line number
452 * @no: the error number
453 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000454 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000455 *
456 * Returns the newly created object.
457 */
458void
459xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
460 int line, int no) {
461 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000462 const xmlChar *cur;
463 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000464
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000465 xmlGenericError(xmlGenericErrorContext,
466 "Error %s:%d: %s\n", file, line,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000467 xmlXPathErrorMessages[no]);
468
469 cur = ctxt->cur;
470 base = ctxt->base;
471 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
472 cur--;
473 }
474 n = 0;
475 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
476 cur--;
477 if ((*cur == '\n') || (*cur == '\r')) cur++;
478 base = cur;
479 n = 0;
480 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000481 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000482 n++;
483 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000484 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000485 cur = ctxt->cur;
486 while ((*cur == '\n') || (*cur == '\r'))
487 cur--;
488 n = 0;
489 while ((cur != base) && (n++ < 80)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000490 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000491 base++;
492 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000493 xmlGenericError(xmlGenericErrorContext,"^\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000494}
495
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000496
497/************************************************************************
498 * *
499 * Routines to handle NodeSets *
500 * *
501 ************************************************************************/
502
503#define XML_NODESET_DEFAULT 10
504/**
505 * xmlXPathNodeSetCreate:
506 * @val: an initial xmlNodePtr, or NULL
507 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000508 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000509 *
510 * Returns the newly created object.
511 */
512xmlNodeSetPtr
513xmlXPathNodeSetCreate(xmlNodePtr val) {
514 xmlNodeSetPtr ret;
515
Daniel Veillard6454aec1999-09-02 22:04:43 +0000516 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000517 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000518 xmlGenericError(xmlGenericErrorContext,
519 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000520 return(NULL);
521 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000522 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000523 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000524 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000525 sizeof(xmlNodePtr));
526 if (ret->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000527 xmlGenericError(xmlGenericErrorContext,
528 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000529 return(NULL);
530 }
531 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000532 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000533 ret->nodeMax = XML_NODESET_DEFAULT;
534 ret->nodeTab[ret->nodeNr++] = val;
535 }
536 return(ret);
537}
538
539/**
540 * xmlXPathNodeSetAdd:
541 * @cur: the initial node set
542 * @val: a new xmlNodePtr
543 *
544 * add a new xmlNodePtr ot an existing NodeSet
545 */
546void
547xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
548 int i;
549
550 if (val == NULL) return;
551
552 /*
553 * check against doublons
554 */
555 for (i = 0;i < cur->nodeNr;i++)
556 if (cur->nodeTab[i] == val) return;
557
558 /*
559 * grow the nodeTab if needed
560 */
561 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000562 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000563 sizeof(xmlNodePtr));
564 if (cur->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000565 xmlGenericError(xmlGenericErrorContext,
566 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000567 return;
568 }
569 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000570 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000571 cur->nodeMax = XML_NODESET_DEFAULT;
572 } else if (cur->nodeNr == cur->nodeMax) {
573 xmlNodePtr *temp;
574
575 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000576 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000577 sizeof(xmlNodePtr));
578 if (temp == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000579 xmlGenericError(xmlGenericErrorContext,
580 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000581 return;
582 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000583 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000584 }
585 cur->nodeTab[cur->nodeNr++] = val;
586}
587
588/**
589 * xmlXPathNodeSetMerge:
Daniel Veillard2d38f042000-10-11 10:54:10 +0000590 * @val1: the first NodeSet or NULL
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000591 * @val2: the second NodeSet
592 *
593 * Merges two nodesets, all nodes from @val2 are added to @val1
Daniel Veillard2d38f042000-10-11 10:54:10 +0000594 * if @val1 is NULL, a new set is created and copied from @val2
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000595 *
596 * Returns val1 once extended or NULL in case of error.
597 */
598xmlNodeSetPtr
599xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
600 int i;
601
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000602 if (val2 == NULL) return(val1);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000603 if (val1 == NULL) {
604 val1 = xmlXPathNodeSetCreate(NULL);
605 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000606
607 /*
608 * !!!!! this can be optimized a lot, knowing that both
609 * val1 and val2 already have unicity of their values.
610 */
611
612 for (i = 0;i < val2->nodeNr;i++)
613 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
614
615 return(val1);
616}
617
618/**
619 * xmlXPathNodeSetDel:
620 * @cur: the initial node set
621 * @val: an xmlNodePtr
622 *
623 * Removes an xmlNodePtr from an existing NodeSet
624 */
625void
626xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
627 int i;
628
629 if (cur == NULL) return;
630 if (val == NULL) return;
631
632 /*
633 * check against doublons
634 */
635 for (i = 0;i < cur->nodeNr;i++)
636 if (cur->nodeTab[i] == val) break;
637
638 if (i >= cur->nodeNr) {
639#ifdef DEBUG
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000640 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000641 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
642 val->name);
643#endif
644 return;
645 }
646 cur->nodeNr--;
647 for (;i < cur->nodeNr;i++)
648 cur->nodeTab[i] = cur->nodeTab[i + 1];
649 cur->nodeTab[cur->nodeNr] = NULL;
650}
651
652/**
653 * xmlXPathNodeSetRemove:
654 * @cur: the initial node set
655 * @val: the index to remove
656 *
657 * Removes an entry from an existing NodeSet list.
658 */
659void
660xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
661 if (cur == NULL) return;
662 if (val >= cur->nodeNr) return;
663 cur->nodeNr--;
664 for (;val < cur->nodeNr;val++)
665 cur->nodeTab[val] = cur->nodeTab[val + 1];
666 cur->nodeTab[cur->nodeNr] = NULL;
667}
668
669/**
670 * xmlXPathFreeNodeSet:
671 * @obj: the xmlNodeSetPtr to free
672 *
673 * Free the NodeSet compound (not the actual nodes !).
674 */
675void
676xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
677 if (obj == NULL) return;
678 if (obj->nodeTab != NULL) {
679#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000680 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000681#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000682 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000683 }
684#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000685 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000686#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000687 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000688}
689
Daniel Veillardb96e6431999-08-29 21:02:19 +0000690#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000691/**
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000692 * xmlGenericErrorContextNodeSet:
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000693 * @output: a FILE * for the output
694 * @obj: the xmlNodeSetPtr to free
695 *
696 * Quick display of a NodeSet
697 */
698void
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000699xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000700 int i;
701
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000702 if (output == NULL) output = xmlGenericErrorContext;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000703 if (obj == NULL) {
704 fprintf(output, "NodeSet == NULL !\n");
705 return;
706 }
707 if (obj->nodeNr == 0) {
708 fprintf(output, "NodeSet is empty\n");
709 return;
710 }
711 if (obj->nodeTab == NULL) {
712 fprintf(output, " nodeTab == NULL !\n");
713 return;
714 }
715 for (i = 0; i < obj->nodeNr; i++) {
716 if (obj->nodeTab[i] == NULL) {
717 fprintf(output, " NULL !\n");
718 return;
719 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000720 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
721 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000722 fprintf(output, " /");
723 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000724 fprintf(output, " noname!");
725 else fprintf(output, " %s", obj->nodeTab[i]->name);
726 }
727 fprintf(output, "\n");
728}
729#endif
730
Daniel Veillard7e99c632000-10-06 12:59:53 +0000731/**
732 * xmlXPathNewNodeSet:
733 * @val: the NodePtr value
734 *
735 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
736 * it with the single Node @val
737 *
738 * Returns the newly created object.
739 */
740xmlXPathObjectPtr
741xmlXPathNewNodeSet(xmlNodePtr val) {
742 xmlXPathObjectPtr ret;
743
744 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
745 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000746 xmlGenericError(xmlGenericErrorContext,
747 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000748 return(NULL);
749 }
750 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
751 ret->type = XPATH_NODESET;
752 ret->nodesetval = xmlXPathNodeSetCreate(val);
753 return(ret);
754}
755
756/**
757 * xmlXPathNewNodeSetList:
758 * @val: an existing NodeSet
759 *
760 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
761 * it with the Nodeset @val
762 *
763 * Returns the newly created object.
764 */
765xmlXPathObjectPtr
766xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
767 xmlXPathObjectPtr ret;
768 int i;
769
770 if (val == NULL)
771 ret = NULL;
772 else if (val->nodeTab == NULL)
773 ret = xmlXPathNewNodeSet(NULL);
774 else
775 {
776 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
777 for (i = 1; i < val->nodeNr; ++i)
778 xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
779 }
780
781 return(ret);
782}
783
784/**
785 * xmlXPathWrapNodeSet:
786 * @val: the NodePtr value
787 *
788 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
789 *
790 * Returns the newly created object.
791 */
792xmlXPathObjectPtr
793xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
794 xmlXPathObjectPtr ret;
795
796 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
797 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000798 xmlGenericError(xmlGenericErrorContext,
799 "xmlXPathWrapNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000800 return(NULL);
801 }
802 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
803 ret->type = XPATH_NODESET;
804 ret->nodesetval = val;
805 return(ret);
806}
807
808/**
809 * xmlXPathFreeNodeSetList:
810 * @obj: an existing NodeSetList object
811 *
812 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
813 * the list contrary to xmlXPathFreeObject().
814 */
815void
816xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
817 if (obj == NULL) return;
818#ifdef DEBUG
819 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
820#endif
821 xmlFree(obj);
822}
823
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000824/************************************************************************
825 * *
Daniel Veillard2d38f042000-10-11 10:54:10 +0000826 * Routines to handle extra functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000827 * *
828 ************************************************************************/
829
830/**
Daniel Veillard2d38f042000-10-11 10:54:10 +0000831 * xmlXPathRegisterFunc:
832 * @ctxt: the XPath context
833 * @name: the function name
834 * @f: the function implementation or NULL
835 *
836 * Register a new function. If @f is NULL it unregisters the function
837 *
838 * Returns 0 in case of success, -1 in case of error
839 */
840int
841xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
842 xmlXPathFunction f) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000843 if (ctxt == NULL)
844 return(-1);
845 if (name == NULL)
846 return(-1);
847
Daniel Veillard52afe802000-10-22 16:56:02 +0000848 if (ctxt->funcHash == NULL)
849 ctxt->funcHash = xmlHashCreate(0);
850 if (ctxt->funcHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +0000851 return(-1);
Daniel Veillard52afe802000-10-22 16:56:02 +0000852 return(xmlHashAddEntry(ctxt->funcHash, name, (void *) f));
Daniel Veillard2d38f042000-10-11 10:54:10 +0000853}
854
855/**
856 * xmlXPathFunctionLookup:
857 * @ctxt: the XPath context
858 * @name: the function name
859 *
860 * Search in the Function array of the context for the given
861 * function.
862 *
863 * Returns the xmlXPathFunction or NULL if not found
864 */
865xmlXPathFunction
866xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000867 if (ctxt == NULL)
868 return(NULL);
Daniel Veillard52afe802000-10-22 16:56:02 +0000869 if (ctxt->funcHash == NULL)
870 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000871 if (name == NULL)
872 return(NULL);
873
Daniel Veillard52afe802000-10-22 16:56:02 +0000874 return((xmlXPathFunction) xmlHashLookup(ctxt->funcHash, name));
Daniel Veillard2d38f042000-10-11 10:54:10 +0000875}
876
877/**
878 * xmlXPathRegisteredFuncsCleanup:
879 * @ctxt: the XPath context
880 *
881 * Cleanup the XPath context data associated to registered functions
882 */
883void
884xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000885 if (ctxt == NULL)
886 return;
887
Daniel Veillard52afe802000-10-22 16:56:02 +0000888 xmlHashFree(ctxt->funcHash, NULL);
889 ctxt->funcHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +0000890}
891
892/************************************************************************
893 * *
894 * Routines to handle Variable *
895 * *
896 ************************************************************************/
897
898/**
899 * xmlXPathRegisterVariable:
900 * @ctxt: the XPath context
901 * @name: the variable name
902 * @value: the variable value or NULL
903 *
904 * Register a new variable value. If @value is NULL it unregisters
905 * the variable
906 *
907 * Returns 0 in case of success, -1 in case of error
908 */
909int
910xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
911 xmlXPathObjectPtr value) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000912 if (ctxt == NULL)
913 return(-1);
914 if (name == NULL)
915 return(-1);
916
Daniel Veillard126f2792000-10-24 17:10:12 +0000917 if (ctxt->varHash == NULL)
918 ctxt->varHash = xmlHashCreate(0);
919 if (ctxt->varHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +0000920 return(-1);
Daniel Veillard126f2792000-10-24 17:10:12 +0000921 return(xmlHashUpdateEntry(ctxt->varHash, name, (void *) value,
922 (xmlHashDeallocator)xmlXPathFreeObject));
Daniel Veillard2d38f042000-10-11 10:54:10 +0000923}
924
925/**
926 * xmlXPathVariableLookup:
927 * @ctxt: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000928 * @name: the variable name
929 *
930 * Search in the Variable array of the context for the given
931 * variable value.
932 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000933 * Returns the value or NULL if not found
934 */
935xmlXPathObjectPtr
Daniel Veillard2d38f042000-10-11 10:54:10 +0000936xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000937 if (ctxt == NULL)
938 return(NULL);
Daniel Veillard126f2792000-10-24 17:10:12 +0000939 if (ctxt->varHash == NULL)
940 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000941 if (name == NULL)
942 return(NULL);
943
Daniel Veillard126f2792000-10-24 17:10:12 +0000944 return((xmlXPathObjectPtr) xmlHashLookup(ctxt->varHash, name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000945}
946
Daniel Veillard2d38f042000-10-11 10:54:10 +0000947/**
948 * xmlXPathRegisteredVariablesCleanup:
949 * @ctxt: the XPath context
950 *
951 * Cleanup the XPath context data associated to registered variables
952 */
953void
954xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +0000955 if (ctxt == NULL)
956 return;
957
Daniel Veillard126f2792000-10-24 17:10:12 +0000958 xmlHashFree(ctxt->varHash, NULL);
959 ctxt->varHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +0000960}
961
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000962/************************************************************************
963 * *
964 * Routines to handle Values *
965 * *
966 ************************************************************************/
967
968/* Allocations are terrible, one need to optimize all this !!! */
969
970/**
971 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000972 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000973 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000974 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000975 *
976 * Returns the newly created object.
977 */
978xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000979xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000980 xmlXPathObjectPtr ret;
981
Daniel Veillard6454aec1999-09-02 22:04:43 +0000982 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000983 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000984 xmlGenericError(xmlGenericErrorContext,
985 "xmlXPathNewFloat: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000986 return(NULL);
987 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000988 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000989 ret->type = XPATH_NUMBER;
990 ret->floatval = val;
991 return(ret);
992}
993
994/**
995 * xmlXPathNewBoolean:
996 * @val: the boolean value
997 *
998 * Create a new xmlXPathObjectPtr of type boolean and of value @val
999 *
1000 * Returns the newly created object.
1001 */
1002xmlXPathObjectPtr
1003xmlXPathNewBoolean(int val) {
1004 xmlXPathObjectPtr ret;
1005
Daniel Veillard6454aec1999-09-02 22:04:43 +00001006 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001007 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001008 xmlGenericError(xmlGenericErrorContext,
1009 "xmlXPathNewBoolean: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001010 return(NULL);
1011 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001012 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001013 ret->type = XPATH_BOOLEAN;
1014 ret->boolval = (val != 0);
1015 return(ret);
1016}
1017
1018/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001019 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001020 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001021 *
1022 * Create a new xmlXPathObjectPtr of type string and of value @val
1023 *
1024 * Returns the newly created object.
1025 */
1026xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001027xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001028 xmlXPathObjectPtr ret;
1029
Daniel Veillard6454aec1999-09-02 22:04:43 +00001030 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001031 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001032 xmlGenericError(xmlGenericErrorContext,
1033 "xmlXPathNewString: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001034 return(NULL);
1035 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001036 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001037 ret->type = XPATH_STRING;
1038 ret->stringval = xmlStrdup(val);
1039 return(ret);
1040}
1041
1042/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001043 * xmlXPathNewCString:
1044 * @val: the char * value
1045 *
1046 * Create a new xmlXPathObjectPtr of type string and of value @val
1047 *
1048 * Returns the newly created object.
1049 */
1050xmlXPathObjectPtr
1051xmlXPathNewCString(const char *val) {
1052 xmlXPathObjectPtr ret;
1053
Daniel Veillard6454aec1999-09-02 22:04:43 +00001054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001055 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001056 xmlGenericError(xmlGenericErrorContext,
1057 "xmlXPathNewCString: out of memory\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001058 return(NULL);
1059 }
1060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1061 ret->type = XPATH_STRING;
1062 ret->stringval = xmlStrdup(BAD_CAST val);
1063 return(ret);
1064}
1065
1066/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001067 * xmlXPathObjectCopy:
1068 * @val: the original object
1069 *
1070 * allocate a new copy of a given object
1071 *
1072 * Returns the newly created object.
1073 */
1074xmlXPathObjectPtr
1075xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1076 xmlXPathObjectPtr ret;
1077
1078 if (val == NULL)
1079 return(NULL);
1080
1081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1082 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001083 xmlGenericError(xmlGenericErrorContext,
1084 "xmlXPathObjectCopy: out of memory\n");
Daniel Veillard2d38f042000-10-11 10:54:10 +00001085 return(NULL);
1086 }
1087 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1088 switch (val->type) {
1089 case XPATH_BOOLEAN:
1090 case XPATH_NUMBER:
1091 case XPATH_STRING:
1092 case XPATH_POINT:
1093 case XPATH_RANGE:
1094 break;
1095 case XPATH_NODESET:
1096 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1097 break;
1098 case XPATH_LOCATIONSET:
1099#ifdef LIBXML_XPTR_ENABLED
1100 {
1101 xmlLocationSetPtr loc = val->user;
1102 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1103 break;
1104 }
1105#endif
1106 case XPATH_UNDEFINED:
1107 case XPATH_USERS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001108 xmlGenericError(xmlGenericErrorContext,
1109 "xmlXPathObjectCopy: unsupported type %d\n",
Daniel Veillard2d38f042000-10-11 10:54:10 +00001110 val->type);
1111 }
1112 return(ret);
1113}
1114
1115/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001116 * xmlXPathFreeObject:
1117 * @obj: the object to free
1118 *
1119 * Free up an xmlXPathObjectPtr object.
1120 */
1121void
1122xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1123 if (obj == NULL) return;
Daniel Veillardac260302000-10-04 13:33:43 +00001124 if (obj->type == XPATH_NODESET) {
1125 if (obj->nodesetval != NULL)
1126 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001127#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard7e99c632000-10-06 12:59:53 +00001128 } else if (obj->type == XPATH_LOCATIONSET) {
1129 if (obj->user != NULL)
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00001130 xmlXPtrFreeLocationSet(obj->user);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001131#endif
Daniel Veillardac260302000-10-04 13:33:43 +00001132 } else if (obj->type == XPATH_STRING) {
1133 if (obj->stringval != NULL)
1134 xmlFree(obj->stringval);
1135 }
1136
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001137#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001138 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001139#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001140 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001141}
1142
1143/************************************************************************
1144 * *
1145 * Routines to handle XPath contexts *
1146 * *
1147 ************************************************************************/
1148
1149/**
1150 * xmlXPathNewContext:
1151 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001152 *
1153 * Create a new xmlXPathContext
1154 *
1155 * Returns the xmlXPathContext just allocated.
1156 */
1157xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001158xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001159 xmlXPathContextPtr ret;
1160
Daniel Veillard6454aec1999-09-02 22:04:43 +00001161 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001162 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001163 xmlGenericError(xmlGenericErrorContext,
1164 "xmlXPathNewContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001165 return(NULL);
1166 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001167 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001168 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001169 ret->node = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001170
Daniel Veillard126f2792000-10-24 17:10:12 +00001171 ret->varHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001172
1173 ret->nb_types = 0;
1174 ret->max_types = 0;
1175 ret->types = NULL;
1176
Daniel Veillard52afe802000-10-22 16:56:02 +00001177 ret->funcHash = xmlHashCreate(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001178
1179 ret->nb_axis = 0;
1180 ret->max_axis = 0;
1181 ret->axis = NULL;
1182
Daniel Veillardb96e6431999-08-29 21:02:19 +00001183 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001184 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +00001185 ret->nsNr = 0;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001186
1187 ret->contextSize = -1;
1188 ret->proximityPosition = -1;
Daniel Veillard52afe802000-10-22 16:56:02 +00001189
1190 xmlXPathRegisterAllFunctions(ret);
1191
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001192 return(ret);
1193}
1194
1195/**
1196 * xmlXPathFreeContext:
1197 * @ctxt: the context to free
1198 *
1199 * Free up an xmlXPathContext
1200 */
1201void
1202xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001203 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001204 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001205
Daniel Veillard2d38f042000-10-11 10:54:10 +00001206 xmlXPathRegisteredFuncsCleanup(ctxt);
1207 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001208#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001209 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001210#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001211 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001212}
1213
1214/************************************************************************
1215 * *
1216 * Routines to handle XPath parser contexts *
1217 * *
1218 ************************************************************************/
1219
Daniel Veillard740abf52000-10-02 23:04:54 +00001220#define CHECK_CTXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001221 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001222 xmlGenericError(xmlGenericErrorContext, \
1223 "%s:%d Internal error: ctxt == NULL\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001224 __FILE__, __LINE__); \
1225 } \
1226
1227
Daniel Veillard740abf52000-10-02 23:04:54 +00001228#define CHECK_CONTEXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001229 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001230 xmlGenericError(xmlGenericErrorContext, \
1231 "%s:%d Internal error: no context\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001232 __FILE__, __LINE__); \
1233 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001234 else if (ctxt->doc == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001235 xmlGenericError(xmlGenericErrorContext, \
1236 "%s:%d Internal error: no document\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001237 __FILE__, __LINE__); \
1238 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001239 else if (ctxt->doc->children == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001240 xmlGenericError(xmlGenericErrorContext, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001241 "%s:%d Internal error: document without root\n", \
1242 __FILE__, __LINE__); \
1243 } \
1244
1245
1246/**
1247 * xmlXPathNewParserContext:
1248 * @str: the XPath expression
1249 * @ctxt: the XPath context
1250 *
1251 * Create a new xmlXPathParserContext
1252 *
1253 * Returns the xmlXPathParserContext just allocated.
1254 */
1255xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001256xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001257 xmlXPathParserContextPtr ret;
1258
Daniel Veillard6454aec1999-09-02 22:04:43 +00001259 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001260 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001261 xmlGenericError(xmlGenericErrorContext,
1262 "xmlXPathNewParserContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001263 return(NULL);
1264 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001265 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001266 ret->cur = ret->base = str;
1267 ret->context = ctxt;
1268
1269 /* Allocate the value stack */
1270 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001271 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001272 ret->valueNr = 0;
1273 ret->valueMax = 10;
1274 ret->value = NULL;
1275 return(ret);
1276}
1277
1278/**
1279 * xmlXPathFreeParserContext:
1280 * @ctxt: the context to free
1281 *
1282 * Free up an xmlXPathParserContext
1283 */
1284void
1285xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1286 if (ctxt->valueTab != NULL) {
1287#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001288 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001289#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001290 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001291 }
1292#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001293 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001294#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001295 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001296}
1297
1298/************************************************************************
1299 * *
1300 * The implicit core function library *
1301 * *
1302 ************************************************************************/
1303
1304/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001305 * Auto-pop and cast to a number
1306 */
1307void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1308
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001309
1310#define POP_FLOAT \
1311 arg = valuePop(ctxt); \
1312 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001313 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001314 } \
1315 if (arg->type != XPATH_NUMBER) { \
1316 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001317 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001318 arg = valuePop(ctxt); \
1319 }
1320
1321/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001322 * xmlXPathEqualNodeSetString
1323 * @arg: the nodeset object argument
1324 * @str: the string to compare to.
1325 *
1326 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1327 * If one object to be compared is a node-set and the other is a string,
1328 * then the comparison will be true if and only if there is a node in
1329 * the node-set such that the result of performing the comparison on the
1330 * string-value of the node and the other string is true.
1331 *
1332 * Returns 0 or 1 depending on the results of the test.
1333 */
1334int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001335xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001336 int i;
1337 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001338 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001339
1340 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
1341 return(0);
1342 ns = arg->nodesetval;
1343 for (i = 0;i < ns->nodeNr;i++) {
1344 str2 = xmlNodeGetContent(ns->nodeTab[i]);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001345 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001346 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001347 return(1);
1348 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001349 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001350 }
1351 return(0);
1352}
1353
1354/**
1355 * xmlXPathEqualNodeSetFloat
1356 * @arg: the nodeset object argument
1357 * @f: the float to compare to
1358 *
1359 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1360 * If one object to be compared is a node-set and the other is a number,
1361 * then the comparison will be true if and only if there is a node in
1362 * the node-set such that the result of performing the comparison on the
1363 * number to be compared and on the result of converting the string-value
1364 * of that node to a number using the number function is true.
1365 *
1366 * Returns 0 or 1 depending on the results of the test.
1367 */
1368int
1369xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001370 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001371
1372 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1373 return(0);
1374
1375 if (isnan(f))
1376 sprintf(buf, "NaN");
1377 else if (isinf(f) > 0)
1378 sprintf(buf, "+Infinity");
1379 else if (isinf(f) < 0)
1380 sprintf(buf, "-Infinity");
1381 else
1382 sprintf(buf, "%0g", f);
1383
Daniel Veillardb96e6431999-08-29 21:02:19 +00001384 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001385}
1386
1387
1388/**
1389 * xmlXPathEqualNodeSets
1390 * @arg1: first nodeset object argument
1391 * @arg2: second nodeset object argument
1392 *
1393 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1394 * If both objects to be compared are node-sets, then the comparison
1395 * will be true if and only if there is a node in the first node-set and
1396 * a node in the second node-set such that the result of performing the
1397 * comparison on the string-values of the two nodes is true.
1398 *
1399 * (needless to say, this is a costly operation)
1400 *
1401 * Returns 0 or 1 depending on the results of the test.
1402 */
1403int
1404xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1405 int i;
1406 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001407 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001408
1409 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1410 return(0);
1411 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1412 return(0);
1413
1414 ns = arg1->nodesetval;
1415 for (i = 0;i < ns->nodeNr;i++) {
1416 str = xmlNodeGetContent(ns->nodeTab[i]);
1417 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001418 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001419 return(1);
1420 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001421 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001422 }
1423 return(0);
1424}
1425
1426/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001427 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001428 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001429 *
1430 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1431 *
1432 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001433 */
1434int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001435xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1436 xmlXPathObjectPtr arg1, arg2;
1437 int ret = 0;
1438
1439 arg1 = valuePop(ctxt);
1440 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001441 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001442
1443 arg2 = valuePop(ctxt);
1444 if (arg2 == NULL) {
1445 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001446 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001447 }
1448
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001449 if (arg1 == arg2) {
1450#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001451 xmlGenericError(xmlGenericErrorContext,
1452 "Equal: by pointer\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001453#endif
1454 return(1);
1455 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001456
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001457 switch (arg1->type) {
1458 case XPATH_UNDEFINED:
1459#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001460 xmlGenericError(xmlGenericErrorContext,
1461 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001462#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001463 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001464 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001465 switch (arg2->type) {
1466 case XPATH_UNDEFINED:
1467#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001468 xmlGenericError(xmlGenericErrorContext,
1469 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001470#endif
1471 break;
1472 case XPATH_NODESET:
1473 ret = xmlXPathEqualNodeSets(arg1, arg2);
1474 break;
1475 case XPATH_BOOLEAN:
1476 if ((arg1->nodesetval == NULL) ||
1477 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1478 else
1479 ret = 1;
1480 ret = (ret == arg2->boolval);
1481 break;
1482 case XPATH_NUMBER:
1483 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1484 break;
1485 case XPATH_STRING:
1486 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1487 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001488 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001489 case XPATH_POINT:
1490 case XPATH_RANGE:
1491 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001492 TODO
1493 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001494 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001495 break;
1496 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001497 switch (arg2->type) {
1498 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001499#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001500 xmlGenericError(xmlGenericErrorContext,
1501 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001502#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001503 break;
1504 case XPATH_NODESET:
1505 if ((arg2->nodesetval == NULL) ||
1506 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1507 else
1508 ret = 1;
1509 break;
1510 case XPATH_BOOLEAN:
1511#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001512 xmlGenericError(xmlGenericErrorContext,
1513 "Equal: %d boolean %d \n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00001514 arg1->boolval, arg2->boolval);
1515#endif
1516 ret = (arg1->boolval == arg2->boolval);
1517 break;
1518 case XPATH_NUMBER:
1519 if (arg2->floatval) ret = 1;
1520 else ret = 0;
1521 ret = (arg1->boolval == ret);
1522 break;
1523 case XPATH_STRING:
1524 if ((arg2->stringval == NULL) ||
1525 (arg2->stringval[0] == 0)) ret = 0;
1526 else
1527 ret = 1;
1528 ret = (arg1->boolval == ret);
1529 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001530 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001531 case XPATH_POINT:
1532 case XPATH_RANGE:
1533 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001534 TODO
1535 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001536 }
1537 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001538 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001539 switch (arg2->type) {
1540 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001541#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001542 xmlGenericError(xmlGenericErrorContext,
1543 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001544#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001545 break;
1546 case XPATH_NODESET:
1547 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1548 break;
1549 case XPATH_BOOLEAN:
1550 if (arg1->floatval) ret = 1;
1551 else ret = 0;
1552 ret = (arg2->boolval == ret);
1553 break;
1554 case XPATH_STRING:
1555 valuePush(ctxt, arg2);
1556 xmlXPathNumberFunction(ctxt, 1);
1557 arg2 = valuePop(ctxt);
1558 /* no break on purpose */
1559 case XPATH_NUMBER:
1560 ret = (arg1->floatval == arg2->floatval);
1561 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001562 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001563 case XPATH_POINT:
1564 case XPATH_RANGE:
1565 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001566 TODO
1567 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001568 }
1569 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001570 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001571 switch (arg2->type) {
1572 case XPATH_UNDEFINED:
1573#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001574 xmlGenericError(xmlGenericErrorContext,
1575 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00001576#endif
1577 break;
1578 case XPATH_NODESET:
1579 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1580 break;
1581 case XPATH_BOOLEAN:
1582 if ((arg1->stringval == NULL) ||
1583 (arg1->stringval[0] == 0)) ret = 0;
1584 else
1585 ret = 1;
1586 ret = (arg2->boolval == ret);
1587 break;
1588 case XPATH_STRING:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001589 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001590 break;
1591 case XPATH_NUMBER:
1592 valuePush(ctxt, arg1);
1593 xmlXPathNumberFunction(ctxt, 1);
1594 arg1 = valuePop(ctxt);
1595 ret = (arg1->floatval == arg2->floatval);
1596 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001597 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001598 case XPATH_POINT:
1599 case XPATH_RANGE:
1600 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001601 TODO
1602 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001603 }
1604 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00001605 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00001606 case XPATH_POINT:
1607 case XPATH_RANGE:
1608 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00001609 TODO
1610 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001611 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001612 xmlXPathFreeObject(arg1);
1613 xmlXPathFreeObject(arg2);
1614 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001615}
1616
1617/**
1618 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001619 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001620 * @inf: less than (1) or greater than (2)
1621 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001622 *
1623 * Implement the compare operation on XPath objects:
1624 * @arg1 < @arg2 (1, 1, ...
1625 * @arg1 <= @arg2 (1, 0, ...
1626 * @arg1 > @arg2 (0, 1, ...
1627 * @arg1 >= @arg2 (0, 0, ...
1628 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001629 * When neither object to be compared is a node-set and the operator is
1630 * <=, <, >=, >, then the objects are compared by converted both objects
1631 * to numbers and comparing the numbers according to IEEE 754. The <
1632 * comparison will be true if and only if the first number is less than the
1633 * second number. The <= comparison will be true if and only if the first
1634 * number is less than or equal to the second number. The > comparison
1635 * will be true if and only if the first number is greater than the second
1636 * number. The >= comparison will be true if and only if the first number
1637 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001638 */
1639int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001640xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1641 int ret = 0;
1642 xmlXPathObjectPtr arg1, arg2;
1643
1644 arg2 = valuePop(ctxt);
1645 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1646 if (arg2 != NULL)
1647 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001648 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001649 }
1650
1651 arg1 = valuePop(ctxt);
1652 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1653 if (arg1 != NULL)
1654 xmlXPathFreeObject(arg1);
1655 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001656 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001657 }
1658
1659 if (arg1->type != XPATH_NUMBER) {
1660 valuePush(ctxt, arg1);
1661 xmlXPathNumberFunction(ctxt, 1);
1662 arg1 = valuePop(ctxt);
1663 }
1664 if (arg1->type != XPATH_NUMBER) {
1665 xmlXPathFreeObject(arg1);
1666 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001667 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001668 }
1669 if (arg2->type != XPATH_NUMBER) {
1670 valuePush(ctxt, arg2);
1671 xmlXPathNumberFunction(ctxt, 1);
1672 arg2 = valuePop(ctxt);
1673 }
1674 if (arg2->type != XPATH_NUMBER) {
1675 xmlXPathFreeObject(arg1);
1676 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001677 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001678 }
1679 /*
1680 * Add tests for infinity and nan
1681 * => feedback on 3.4 for Inf and NaN
1682 */
1683 if (inf && strict)
1684 ret = (arg1->floatval < arg2->floatval);
1685 else if (inf && !strict)
1686 ret = (arg1->floatval <= arg2->floatval);
1687 else if (!inf && strict)
1688 ret = (arg1->floatval > arg2->floatval);
1689 else if (!inf && !strict)
1690 ret = (arg1->floatval >= arg2->floatval);
1691 xmlXPathFreeObject(arg1);
1692 xmlXPathFreeObject(arg2);
1693 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001694}
1695
1696/**
1697 * xmlXPathValueFlipSign:
1698 * @ctxt: the XPath Parser context
1699 *
1700 * Implement the unary - operation on an XPath object
1701 * The numeric operators convert their operands to numbers as if
1702 * by calling the number function.
1703 */
1704void
1705xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1706 xmlXPathObjectPtr arg;
1707
1708 POP_FLOAT
1709 arg->floatval = -arg->floatval;
1710 valuePush(ctxt, arg);
1711}
1712
1713/**
1714 * xmlXPathAddValues:
1715 * @ctxt: the XPath Parser context
1716 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001717 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001718 * The numeric operators convert their operands to numbers as if
1719 * by calling the number function.
1720 */
1721void
1722xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1723 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001724 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001725
1726 POP_FLOAT
1727 val = arg->floatval;
1728 xmlXPathFreeObject(arg);
1729
1730 POP_FLOAT
1731 arg->floatval += val;
1732 valuePush(ctxt, arg);
1733}
1734
1735/**
1736 * xmlXPathSubValues:
1737 * @ctxt: the XPath Parser context
1738 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001739 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001740 * The numeric operators convert their operands to numbers as if
1741 * by calling the number function.
1742 */
1743void
1744xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1745 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001746 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001747
1748 POP_FLOAT
1749 val = arg->floatval;
1750 xmlXPathFreeObject(arg);
1751
1752 POP_FLOAT
1753 arg->floatval -= val;
1754 valuePush(ctxt, arg);
1755}
1756
1757/**
1758 * xmlXPathMultValues:
1759 * @ctxt: the XPath Parser context
1760 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001761 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001762 * The numeric operators convert their operands to numbers as if
1763 * by calling the number function.
1764 */
1765void
1766xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1767 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001768 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001769
1770 POP_FLOAT
1771 val = arg->floatval;
1772 xmlXPathFreeObject(arg);
1773
1774 POP_FLOAT
1775 arg->floatval *= val;
1776 valuePush(ctxt, arg);
1777}
1778
1779/**
1780 * xmlXPathDivValues:
1781 * @ctxt: the XPath Parser context
1782 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001783 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001784 * The numeric operators convert their operands to numbers as if
1785 * by calling the number function.
1786 */
1787void
1788xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1789 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001790 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001791
1792 POP_FLOAT
1793 val = arg->floatval;
1794 xmlXPathFreeObject(arg);
1795
1796 POP_FLOAT
1797 arg->floatval /= val;
1798 valuePush(ctxt, arg);
1799}
1800
1801/**
1802 * xmlXPathModValues:
1803 * @ctxt: the XPath Parser context
1804 *
1805 * Implement the div operation on XPath objects: @arg1 / @arg2
1806 * The numeric operators convert their operands to numbers as if
1807 * by calling the number function.
1808 */
1809void
1810xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1811 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001812 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001813
1814 POP_FLOAT
1815 val = arg->floatval;
1816 xmlXPathFreeObject(arg);
1817
1818 POP_FLOAT
1819 arg->floatval /= val;
1820 valuePush(ctxt, arg);
1821}
1822
1823/************************************************************************
1824 * *
1825 * The traversal functions *
1826 * *
1827 ************************************************************************/
1828
Daniel Veillard740abf52000-10-02 23:04:54 +00001829typedef enum {
1830 AXIS_ANCESTOR = 1,
1831 AXIS_ANCESTOR_OR_SELF,
1832 AXIS_ATTRIBUTE,
1833 AXIS_CHILD,
1834 AXIS_DESCENDANT,
1835 AXIS_DESCENDANT_OR_SELF,
1836 AXIS_FOLLOWING,
1837 AXIS_FOLLOWING_SIBLING,
1838 AXIS_NAMESPACE,
1839 AXIS_PARENT,
1840 AXIS_PRECEDING,
1841 AXIS_PRECEDING_SIBLING,
1842 AXIS_SELF
1843} xmlXPathAxisVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001844
1845/*
1846 * A traversal function enumerates nodes along an axis.
1847 * Initially it must be called with NULL, and it indicates
1848 * termination on the axis by returning NULL.
1849 */
1850typedef xmlNodePtr (*xmlXPathTraversalFunction)
1851 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1852
1853/**
1854 * mlXPathNextSelf:
1855 * @ctxt: the XPath Parser context
1856 * @cur: the current node in the traversal
1857 *
1858 * Traversal function for the "self" direction
1859 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001860 *
1861 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001862 */
1863xmlNodePtr
1864xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1865 if (cur == NULL)
1866 return(ctxt->context->node);
1867 return(NULL);
1868}
1869
1870/**
1871 * mlXPathNextChild:
1872 * @ctxt: the XPath Parser context
1873 * @cur: the current node in the traversal
1874 *
1875 * Traversal function for the "child" direction
1876 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001877 *
1878 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001879 */
1880xmlNodePtr
1881xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001882 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001883 if (ctxt->context->node == NULL) return(NULL);
1884 switch (ctxt->context->node->type) {
1885 case XML_ELEMENT_NODE:
1886 case XML_TEXT_NODE:
1887 case XML_CDATA_SECTION_NODE:
1888 case XML_ENTITY_REF_NODE:
1889 case XML_ENTITY_NODE:
1890 case XML_PI_NODE:
1891 case XML_COMMENT_NODE:
1892 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001893 case XML_DTD_NODE:
1894 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001895 case XML_DOCUMENT_NODE:
1896 case XML_DOCUMENT_TYPE_NODE:
1897 case XML_DOCUMENT_FRAG_NODE:
1898 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00001899#ifdef LIBXML_SGML_ENABLED
1900 case XML_SGML_DOCUMENT_NODE:
1901#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00001902 return(((xmlDocPtr) ctxt->context->node)->children);
1903 case XML_ELEMENT_DECL:
1904 case XML_ATTRIBUTE_DECL:
1905 case XML_ENTITY_DECL:
1906 case XML_ATTRIBUTE_NODE:
1907 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001908 }
1909 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001910 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001911 if ((cur->type == XML_DOCUMENT_NODE) ||
1912 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001913 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001914 return(cur->next);
1915}
1916
1917/**
1918 * mlXPathNextDescendant:
1919 * @ctxt: the XPath Parser context
1920 * @cur: the current node in the traversal
1921 *
1922 * Traversal function for the "descendant" direction
1923 * the descendant axis contains the descendants of the context node in document
1924 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001925 *
1926 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001927 */
1928xmlNodePtr
1929xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001930 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001931 if (ctxt->context->node == NULL)
1932 return(NULL);
1933 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1934 return(NULL);
1935
Daniel Veillardb05deb71999-08-10 19:04:08 +00001936 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00001937 return(ctxt->context->doc->children);
1938 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001939 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001940
Daniel Veillardbe803962000-06-28 23:40:59 +00001941 if (cur->children != NULL)
1942 {
1943 if (cur->children->type != XML_ENTITY_DECL)
1944 return(cur->children);
1945 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001946 if (cur->next != NULL) return(cur->next);
1947
1948 do {
1949 cur = cur->parent;
1950 if (cur == NULL) return(NULL);
1951 if (cur == ctxt->context->node) return(NULL);
1952 if (cur->next != NULL) {
1953 cur = cur->next;
1954 return(cur);
1955 }
1956 } while (cur != NULL);
1957 return(cur);
1958}
1959
1960/**
1961 * mlXPathNextDescendantOrSelf:
1962 * @ctxt: the XPath Parser context
1963 * @cur: the current node in the traversal
1964 *
1965 * Traversal function for the "descendant-or-self" direction
1966 * the descendant-or-self axis contains the context node and the descendants
1967 * of the context node in document order; thus the context node is the first
1968 * node on the axis, and the first child of the context node is the second node
1969 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001970 *
1971 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001972 */
1973xmlNodePtr
1974xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001975 if (cur == NULL) {
1976 if (ctxt->context->node == NULL)
1977 return(NULL);
1978 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1979 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001980 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001981 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001982
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001983 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001984}
1985
1986/**
1987 * xmlXPathNextParent:
1988 * @ctxt: the XPath Parser context
1989 * @cur: the current node in the traversal
1990 *
1991 * Traversal function for the "parent" direction
1992 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001993 *
1994 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001995 */
1996xmlNodePtr
1997xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1998 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001999 * the parent of an attribute or namespace node is the element
2000 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002001 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002002 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002003 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002004 if (ctxt->context->node == NULL) return(NULL);
2005 switch (ctxt->context->node->type) {
2006 case XML_ELEMENT_NODE:
2007 case XML_TEXT_NODE:
2008 case XML_CDATA_SECTION_NODE:
2009 case XML_ENTITY_REF_NODE:
2010 case XML_ENTITY_NODE:
2011 case XML_PI_NODE:
2012 case XML_COMMENT_NODE:
2013 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002014 case XML_DTD_NODE:
2015 case XML_ELEMENT_DECL:
2016 case XML_ATTRIBUTE_DECL:
2017 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002018 if (ctxt->context->node->parent == NULL)
2019 return((xmlNodePtr) ctxt->context->doc);
2020 return(ctxt->context->node->parent);
2021 case XML_ATTRIBUTE_NODE: {
2022 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2023
Daniel Veillardcf461992000-03-14 18:30:20 +00002024 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002025 }
2026 case XML_DOCUMENT_NODE:
2027 case XML_DOCUMENT_TYPE_NODE:
2028 case XML_DOCUMENT_FRAG_NODE:
2029 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002030#ifdef LIBXML_SGML_ENABLED
2031 case XML_SGML_DOCUMENT_NODE:
2032#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002033 return(NULL);
2034 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002035 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002036 return(NULL);
2037}
2038
2039/**
2040 * xmlXPathNextAncestor:
2041 * @ctxt: the XPath Parser context
2042 * @cur: the current node in the traversal
2043 *
2044 * Traversal function for the "ancestor" direction
2045 * the ancestor axis contains the ancestors of the context node; the ancestors
2046 * of the context node consist of the parent of context node and the parent's
2047 * parent and so on; the nodes are ordered in reverse document order; thus the
2048 * parent is the first node on the axis, and the parent's parent is the second
2049 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002050 *
2051 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002052 */
2053xmlNodePtr
2054xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2055 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002056 * the parent of an attribute or namespace node is the element
2057 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002058 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002059 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002060 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002061 if (ctxt->context->node == NULL) return(NULL);
2062 switch (ctxt->context->node->type) {
2063 case XML_ELEMENT_NODE:
2064 case XML_TEXT_NODE:
2065 case XML_CDATA_SECTION_NODE:
2066 case XML_ENTITY_REF_NODE:
2067 case XML_ENTITY_NODE:
2068 case XML_PI_NODE:
2069 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002070 case XML_DTD_NODE:
2071 case XML_ELEMENT_DECL:
2072 case XML_ATTRIBUTE_DECL:
2073 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002074 case XML_NOTATION_NODE:
2075 if (ctxt->context->node->parent == NULL)
2076 return((xmlNodePtr) ctxt->context->doc);
2077 return(ctxt->context->node->parent);
2078 case XML_ATTRIBUTE_NODE: {
2079 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2080
Daniel Veillardcf461992000-03-14 18:30:20 +00002081 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002082 }
2083 case XML_DOCUMENT_NODE:
2084 case XML_DOCUMENT_TYPE_NODE:
2085 case XML_DOCUMENT_FRAG_NODE:
2086 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002087#ifdef LIBXML_SGML_ENABLED
2088 case XML_SGML_DOCUMENT_NODE:
2089#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002090 return(NULL);
2091 }
2092 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002093 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002094 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002095 return((xmlNodePtr) ctxt->context->doc);
2096 if (cur == (xmlNodePtr) ctxt->context->doc)
2097 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002098 switch (cur->type) {
2099 case XML_ELEMENT_NODE:
2100 case XML_TEXT_NODE:
2101 case XML_CDATA_SECTION_NODE:
2102 case XML_ENTITY_REF_NODE:
2103 case XML_ENTITY_NODE:
2104 case XML_PI_NODE:
2105 case XML_COMMENT_NODE:
2106 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002107 case XML_DTD_NODE:
2108 case XML_ELEMENT_DECL:
2109 case XML_ATTRIBUTE_DECL:
2110 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002111 return(cur->parent);
2112 case XML_ATTRIBUTE_NODE: {
2113 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2114
Daniel Veillardcf461992000-03-14 18:30:20 +00002115 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002116 }
2117 case XML_DOCUMENT_NODE:
2118 case XML_DOCUMENT_TYPE_NODE:
2119 case XML_DOCUMENT_FRAG_NODE:
2120 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002121#ifdef LIBXML_SGML_ENABLED
2122 case XML_SGML_DOCUMENT_NODE:
2123#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002124 return(NULL);
2125 }
2126 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002127}
2128
2129/**
2130 * xmlXPathNextAncestorOrSelf:
2131 * @ctxt: the XPath Parser context
2132 * @cur: the current node in the traversal
2133 *
2134 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00002135 * he ancestor-or-self axis contains the context node and ancestors of
2136 * the context node in reverse document order; thus the context node is
2137 * the first node on the axis, and the context node's parent the second;
2138 * parent here is defined the same as with the parent axis.
2139 *
2140 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002141 */
2142xmlNodePtr
2143xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002144 if (cur == NULL)
2145 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002146 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002147}
2148
2149/**
2150 * xmlXPathNextFollowingSibling:
2151 * @ctxt: the XPath Parser context
2152 * @cur: the current node in the traversal
2153 *
2154 * Traversal function for the "following-sibling" direction
2155 * The following-sibling axis contains the following siblings of the context
2156 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002157 *
2158 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002159 */
2160xmlNodePtr
2161xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002162 if (cur == (xmlNodePtr) ctxt->context->doc)
2163 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002164 if (cur == NULL)
2165 return(ctxt->context->node->next);
2166 return(cur->next);
2167}
2168
2169/**
2170 * xmlXPathNextPrecedingSibling:
2171 * @ctxt: the XPath Parser context
2172 * @cur: the current node in the traversal
2173 *
2174 * Traversal function for the "preceding-sibling" direction
2175 * The preceding-sibling axis contains the preceding siblings of the context
2176 * node in reverse document order; the first preceding sibling is first on the
2177 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002178 *
2179 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002180 */
2181xmlNodePtr
2182xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002183 if (cur == (xmlNodePtr) ctxt->context->doc)
2184 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002185 if (cur == NULL)
2186 return(ctxt->context->node->prev);
2187 return(cur->prev);
2188}
2189
2190/**
2191 * xmlXPathNextFollowing:
2192 * @ctxt: the XPath Parser context
2193 * @cur: the current node in the traversal
2194 *
2195 * Traversal function for the "following" direction
2196 * The following axis contains all nodes in the same document as the context
2197 * node that are after the context node in document order, excluding any
2198 * descendants and excluding attribute nodes and namespace nodes; the nodes
2199 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00002200 *
2201 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002202 */
2203xmlNodePtr
2204xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002205 if (cur != NULL && cur->children != NULL)
2206 return cur->children ;
Daniel Veillardac260302000-10-04 13:33:43 +00002207 if (cur == NULL) cur = ctxt->context->node;
2208 if (cur == NULL) return(NULL) ; /* ERROR */
2209 if (cur->next != NULL) return(cur->next) ;
Daniel Veillard740abf52000-10-02 23:04:54 +00002210 do {
2211 cur = cur->parent;
2212 if (cur == NULL) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002213 if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */
2214 if (cur->next != NULL) return(cur->next);
Daniel Veillard740abf52000-10-02 23:04:54 +00002215 } while (cur != NULL);
2216 return(cur);
2217}
2218
2219/*
Daniel Veillardac260302000-10-04 13:33:43 +00002220 * xmlXPathIsAncestor:
2221 * @ancestor: the ancestor node
2222 * @node: the current node
2223 *
2224 * Check that @ancestor is a @node's ancestor
2225 *
Daniel Veillard740abf52000-10-02 23:04:54 +00002226 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2227 */
2228static int
Daniel Veillardac260302000-10-04 13:33:43 +00002229xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002230 xmlNodePtr tmp ;
2231 if (ancestor == NULL || node == NULL) return 0 ;
2232 for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) {
2233 if (tmp->parent == ancestor)
2234 return 1 ;
2235 }
2236 return 0 ;
2237}
2238
2239/**
2240 * xmlXPathNextPreceding:
2241 * @ctxt: the XPath Parser context
2242 * @cur: the current node in the traversal
2243 *
2244 * Traversal function for the "preceding" direction
2245 * the preceding axis contains all nodes in the same document as the context
2246 * node that are before the context node in document order, excluding any
2247 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2248 * ordered in reverse document order
2249 *
2250 * Returns the next element following that axis
2251 */
2252xmlNodePtr
2253xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2254 if (cur == NULL)
2255 cur = ctxt->context->node ;
2256 do {
2257 if (cur->prev != NULL) {
2258 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2259 ;
2260 return(cur) ;
2261 }
2262
2263 cur = cur->parent;
2264 if (cur == NULL) return(NULL);
2265 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002266 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillard740abf52000-10-02 23:04:54 +00002267 return(cur);
2268}
2269
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002270/**
2271 * xmlXPathNextNamespace:
2272 * @ctxt: the XPath Parser context
2273 * @cur: the current attribute in the traversal
2274 *
2275 * Traversal function for the "namespace" direction
2276 * the namespace axis contains the namespace nodes of the context node;
2277 * the order of nodes on this axis is implementation-defined; the axis will
2278 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00002279 *
2280 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002281 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00002282xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002283xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002284 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2285 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002286 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002287 ctxt->context->namespaces =
2288 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2289 if (ctxt->context->namespaces == NULL) return(NULL);
2290 ctxt->context->nsNr = 0;
2291 }
2292 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002293}
2294
2295/**
2296 * xmlXPathNextAttribute:
2297 * @ctxt: the XPath Parser context
2298 * @cur: the current attribute in the traversal
2299 *
2300 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00002301 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00002302 *
2303 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002304 */
2305xmlAttrPtr
2306xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00002307 if (cur == NULL) {
2308 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2309 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002310 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002311 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002312 return(cur->next);
2313}
2314
2315/************************************************************************
2316 * *
2317 * NodeTest Functions *
2318 * *
2319 ************************************************************************/
2320
Daniel Veillard740abf52000-10-02 23:04:54 +00002321typedef enum {
2322 NODE_TEST_NONE = 0,
2323 NODE_TEST_TYPE = 1,
2324 NODE_TEST_PI = 2,
2325 NODE_TEST_ALL = 3,
2326 NODE_TEST_NS = 4,
2327 NODE_TEST_NAME = 5
2328} xmlXPathTestVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002329
Daniel Veillard740abf52000-10-02 23:04:54 +00002330typedef enum {
Daniel Veillard55b91f22000-10-05 16:30:11 +00002331 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
2332 NODE_TYPE_TEXT = XML_TEXT_NODE,
2333 NODE_TYPE_PI = XML_PI_NODE,
2334 NODE_TYPE_NODE = XML_ELEMENT_NODE
Daniel Veillard740abf52000-10-02 23:04:54 +00002335} xmlXPathTypeVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002336
2337#define IS_FUNCTION 200
2338
2339/**
2340 * xmlXPathNodeCollectAndTest:
2341 * @ctxt: the XPath Parser context
Daniel Veillard740abf52000-10-02 23:04:54 +00002342 * @axis: the XPath axis
2343 * @test: the XPath test
2344 * @type: the XPath type
2345 * @prefix: the namesapce prefix if any
2346 * @name: the name used in the search if any
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002347 *
2348 * This is the function implementing a step: based on the current list
2349 * of nodes, it builds up a new list, looking at all nodes under that
2350 * axis and selecting them.
2351 *
2352 * Returns the new NodeSet resulting from the search.
2353 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002354void
2355xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2356 xmlXPathTestVal test, xmlXPathTypeVal type,
2357 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002358#ifdef DEBUG_STEP
2359 int n = 0, t = 0;
2360#endif
2361 int i;
2362 xmlNodeSetPtr ret;
2363 xmlXPathTraversalFunction next = NULL;
2364 xmlNodePtr cur = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00002365 xmlXPathObjectPtr obj;
2366 xmlNodeSetPtr nodelist;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002367
Daniel Veillard740abf52000-10-02 23:04:54 +00002368 CHECK_TYPE(XPATH_NODESET);
2369 obj = valuePop(ctxt);
2370
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002371#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002372 xmlGenericError(xmlGenericErrorContext,
2373 "new step : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002374#endif
2375 switch (axis) {
2376 case AXIS_ANCESTOR:
2377#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002378 xmlGenericError(xmlGenericErrorContext,
2379 "axis 'ancestors' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002380#endif
2381 next = xmlXPathNextAncestor; break;
2382 case AXIS_ANCESTOR_OR_SELF:
2383#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002384 xmlGenericError(xmlGenericErrorContext,
2385 "axis 'ancestors-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002386#endif
2387 next = xmlXPathNextAncestorOrSelf; break;
2388 case AXIS_ATTRIBUTE:
2389#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002390 xmlGenericError(xmlGenericErrorContext,
2391 "axis 'attributes' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002392#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002393 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002394 break;
2395 case AXIS_CHILD:
2396#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002397 xmlGenericError(xmlGenericErrorContext,
2398 "axis 'child' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002399#endif
2400 next = xmlXPathNextChild; break;
2401 case AXIS_DESCENDANT:
2402#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002403 xmlGenericError(xmlGenericErrorContext,
2404 "axis 'descendant' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002405#endif
2406 next = xmlXPathNextDescendant; break;
2407 case AXIS_DESCENDANT_OR_SELF:
2408#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002409 xmlGenericError(xmlGenericErrorContext,
2410 "axis 'descendant-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002411#endif
2412 next = xmlXPathNextDescendantOrSelf; break;
2413 case AXIS_FOLLOWING:
2414#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002415 xmlGenericError(xmlGenericErrorContext,
2416 "axis 'following' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002417#endif
2418 next = xmlXPathNextFollowing; break;
2419 case AXIS_FOLLOWING_SIBLING:
2420#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002421 xmlGenericError(xmlGenericErrorContext,
2422 "axis 'following-siblings' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002423#endif
2424 next = xmlXPathNextFollowingSibling; break;
2425 case AXIS_NAMESPACE:
2426#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002427 xmlGenericError(xmlGenericErrorContext,
2428 "axis 'namespace' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002429#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002430 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002431 break;
2432 case AXIS_PARENT:
2433#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002434 xmlGenericError(xmlGenericErrorContext,
2435 "axis 'parent' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002436#endif
2437 next = xmlXPathNextParent; break;
2438 case AXIS_PRECEDING:
2439#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002440 xmlGenericError(xmlGenericErrorContext,
2441 "axis 'preceding' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002442#endif
2443 next = xmlXPathNextPreceding; break;
2444 case AXIS_PRECEDING_SIBLING:
2445#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002446 xmlGenericError(xmlGenericErrorContext,
2447 "axis 'preceding-sibling' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002448#endif
2449 next = xmlXPathNextPrecedingSibling; break;
2450 case AXIS_SELF:
2451#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002452 xmlGenericError(xmlGenericErrorContext,
2453 "axis 'self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002454#endif
2455 next = xmlXPathNextSelf; break;
2456 }
Daniel Veillard740abf52000-10-02 23:04:54 +00002457 if (next == NULL)
2458 return;
2459
2460 nodelist = obj->nodesetval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002461 ret = xmlXPathNodeSetCreate(NULL);
2462#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002463 xmlGenericError(xmlGenericErrorContext,
2464 " context contains %d nodes\n",
Daniel Veillard740abf52000-10-02 23:04:54 +00002465 nodelist->nodeNr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002466 switch (test) {
2467 case NODE_TEST_NONE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002468 xmlGenericError(xmlGenericErrorContext,
2469 " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002470 break;
2471 case NODE_TEST_TYPE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002472 xmlGenericError(xmlGenericErrorContext,
2473 " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002474 break;
2475 case NODE_TEST_PI:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002476 xmlGenericError(xmlGenericErrorContext,
2477 " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002478 break;
2479 case NODE_TEST_ALL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002480 xmlGenericError(xmlGenericErrorContext,
2481 " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002482 break;
2483 case NODE_TEST_NS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002484 xmlGenericError(xmlGenericErrorContext,
2485 " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002486 prefix);
2487 break;
2488 case NODE_TEST_NAME:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002489 xmlGenericError(xmlGenericErrorContext,
2490 " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002491 if (prefix != NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002492 xmlGenericError(xmlGenericErrorContext,
2493 " with namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002494 prefix);
2495 break;
2496 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002497 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002498#endif
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00002499 /*
2500 * 2.3 Node Tests
2501 * - For the attribute axis, the principal node type is attribute.
2502 * - For the namespace axis, the principal node type is namespace.
2503 * - For other axes, the principal node type is element.
2504 *
2505 * A node test * is true for any node of the
2506 * principal node type. For example, child::* willi
2507 * select all element children of the context node
2508 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002509 for (i = 0;i < nodelist->nodeNr; i++) {
2510 ctxt->context->node = nodelist->nodeTab[i];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002511
2512 cur = NULL;
2513 do {
2514 cur = next(ctxt, cur);
2515 if (cur == NULL) break;
2516#ifdef DEBUG_STEP
2517 t++;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002518 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002519#endif
2520 switch (test) {
2521 case NODE_TEST_NONE:
2522 STRANGE
Daniel Veillard740abf52000-10-02 23:04:54 +00002523 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002524 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002525 if ((cur->type == type) ||
2526 ((type == XML_ELEMENT_NODE) &&
2527 ((cur->type == XML_DOCUMENT_NODE) ||
2528 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002529#ifdef DEBUG_STEP
2530 n++;
2531#endif
2532 xmlXPathNodeSetAdd(ret, cur);
2533 }
2534 break;
2535 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002536 if (cur->type == XML_PI_NODE) {
2537 if ((name != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002538 (!xmlStrEqual(name, cur->name)))
Daniel Veillardb96e6431999-08-29 21:02:19 +00002539 break;
2540#ifdef DEBUG_STEP
2541 n++;
2542#endif
2543 xmlXPathNodeSetAdd(ret, cur);
2544 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002545 break;
2546 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002547 if ((cur->type == XML_ELEMENT_NODE) ||
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00002548 (cur->type == XML_DOCUMENT_NODE) ||
2549 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002550#ifdef DEBUG_STEP
2551 n++;
2552#endif
2553 xmlXPathNodeSetAdd(ret, cur);
2554 }
2555 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002556 case NODE_TEST_NS: {
2557 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002558 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002559 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002560 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002561 switch (cur->type) {
2562 case XML_ELEMENT_NODE:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002563 if (xmlStrEqual(name, cur->name) &&
Daniel Veillardb05deb71999-08-10 19:04:08 +00002564 (((prefix == NULL) ||
2565 ((cur->ns != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002566 (xmlStrEqual(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002567#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002568 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002569#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002570 xmlXPathNodeSetAdd(ret, cur);
2571 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002572 break;
2573 case XML_ATTRIBUTE_NODE: {
2574 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002575 if (xmlStrEqual(name, attr->name)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002576#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00002577 n++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002578#endif
2579 xmlXPathNodeSetAdd(ret, cur);
2580 }
2581 break;
2582 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002583 default:
2584 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002585 }
2586 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002587 }
2588 } while (cur != NULL);
2589 }
2590#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002591 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002592 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2593#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00002594 xmlXPathFreeObject(obj);
2595 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002596}
2597
2598
2599/************************************************************************
2600 * *
2601 * Implicit tree core function library *
2602 * *
2603 ************************************************************************/
2604
2605/**
2606 * xmlXPathRoot:
2607 * @ctxt: the XPath Parser context
2608 *
2609 * Initialize the context to the root of the document
2610 */
2611void
2612xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00002613 if (ctxt->value != NULL) {
2614 xmlXPathObjectPtr obj;
Daniel Veillard740abf52000-10-02 23:04:54 +00002615
Daniel Veillard55b91f22000-10-05 16:30:11 +00002616 CHECK_TYPE(XPATH_NODESET);
2617 obj = valuePop(ctxt);
2618 xmlXPathFreeObject(obj);
2619 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002620 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Daniel Veillard740abf52000-10-02 23:04:54 +00002621 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002622}
2623
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002624/************************************************************************
2625 * *
2626 * The explicit core function library *
2627 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2628 * *
2629 ************************************************************************/
2630
2631
2632/**
2633 * xmlXPathLastFunction:
2634 * @ctxt: the XPath Parser context
2635 *
2636 * Implement the last() XPath function
2637 * The last function returns the number of nodes in the context node list.
2638 */
2639void
2640xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2641 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002642 if (ctxt->context->contextSize > 0) {
2643 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
2644#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002645 xmlGenericError(xmlGenericErrorContext,
2646 "last() : %d\n", ctxt->context->contextSize);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002647#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002648 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002649 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002650 }
2651}
2652
2653/**
2654 * xmlXPathPositionFunction:
2655 * @ctxt: the XPath Parser context
2656 *
2657 * Implement the position() XPath function
2658 * The position function returns the position of the context node in the
2659 * context node list. The first position is 1, and so the last positionr
2660 * will be equal to last().
2661 */
2662void
2663xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002664 CHECK_ARITY(0);
Daniel Veillardff9c3302000-10-13 16:38:25 +00002665 if (ctxt->context->proximityPosition >= 0) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002666 valuePush(ctxt,
Daniel Veillardff9c3302000-10-13 16:38:25 +00002667 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002668#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002669 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
Daniel Veillardf09e7e32000-10-01 15:53:30 +00002670 ctxt->context->proximityPosition);
2671#endif
2672 } else {
2673 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002674 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002675}
2676
2677/**
2678 * xmlXPathCountFunction:
2679 * @ctxt: the XPath Parser context
2680 *
2681 * Implement the count() XPath function
2682 */
2683void
2684xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2685 xmlXPathObjectPtr cur;
2686
2687 CHECK_ARITY(1);
2688 CHECK_TYPE(XPATH_NODESET);
2689 cur = valuePop(ctxt);
2690
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002691 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002692 xmlXPathFreeObject(cur);
2693}
2694
2695/**
2696 * xmlXPathIdFunction:
2697 * @ctxt: the XPath Parser context
2698 *
2699 * Implement the id() XPath function
2700 * The id function selects elements by their unique ID
2701 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2702 * then the result is the union of the result of applying id to the
2703 * string value of each of the nodes in the argument node-set. When the
2704 * argument to id is of any other type, the argument is converted to a
2705 * string as if by a call to the string function; the string is split
2706 * into a whitespace-separated list of tokens (whitespace is any sequence
2707 * of characters matching the production S); the result is a node-set
2708 * containing the elements in the same document as the context node that
2709 * have a unique ID equal to any of the tokens in the list.
2710 */
2711void
2712xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002713 const xmlChar *tokens;
2714 const xmlChar *cur;
2715 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002716 xmlAttrPtr attr;
2717 xmlNodePtr elem = NULL;
2718 xmlXPathObjectPtr ret, obj;
2719
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002720 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002721 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002722 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002723 if (obj->type == XPATH_NODESET) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002724 xmlXPathObjectPtr newobj;
2725 int i;
2726
2727 ret = xmlXPathNewNodeSet(NULL);
2728
2729 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
2730 valuePush(ctxt,
2731 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
2732 xmlXPathStringFunction(ctxt, 1);
2733 xmlXPathIdFunction(ctxt, 1);
2734 newobj = valuePop(ctxt);
2735 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
2736 newobj->nodesetval);
2737 xmlXPathFreeObject(newobj);
2738 }
2739
2740 xmlXPathFreeObject(obj);
2741 valuePush(ctxt, ret);
2742 return;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002743 }
2744 if (obj->type != XPATH_STRING) {
2745 valuePush(ctxt, obj);
2746 xmlXPathStringFunction(ctxt, 1);
2747 obj = valuePop(ctxt);
2748 if (obj->type != XPATH_STRING) {
2749 xmlXPathFreeObject(obj);
2750 return;
2751 }
2752 }
2753 tokens = obj->stringval;
2754
2755 ret = xmlXPathNewNodeSet(NULL);
2756 valuePush(ctxt, ret);
2757 if (tokens == NULL) {
2758 xmlXPathFreeObject(obj);
2759 return;
2760 }
2761
2762 cur = tokens;
2763
2764 while (IS_BLANK(*cur)) cur++;
2765 while (*cur != 0) {
2766 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2767 (*cur == '.') || (*cur == '-') ||
2768 (*cur == '_') || (*cur == ':') ||
2769 (IS_COMBINING(*cur)) ||
2770 (IS_EXTENDER(*cur)))
2771 cur++;
2772
2773 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2774
2775 ID = xmlStrndup(tokens, cur - tokens);
2776 attr = xmlGetID(ctxt->context->doc, ID);
2777 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002778 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002779 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2780 }
2781 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002782 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002783
2784 while (IS_BLANK(*cur)) cur++;
2785 tokens = cur;
2786 }
2787 xmlXPathFreeObject(obj);
2788 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002789}
2790
2791/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002792 * xmlXPathLocalNameFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002793 * @ctxt: the XPath Parser context
2794 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002795 * Implement the local-name() XPath function
2796 * The local-name function returns a string containing the local part
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002797 * of the name of the node in the argument node-set that is first in
2798 * document order. If the node-set is empty or the first node has no
2799 * name, an empty string is returned. If the argument is omitted it
2800 * defaults to the context node.
2801 */
2802void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002803xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002804 xmlXPathObjectPtr cur;
2805
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002806 if (nargs == 0) {
2807 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2808 nargs = 1;
2809 }
2810
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002811 CHECK_ARITY(1);
2812 CHECK_TYPE(XPATH_NODESET);
2813 cur = valuePop(ctxt);
2814
2815 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002816 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002817 } else {
2818 int i = 0; /* Should be first in document order !!!!! */
2819 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2820 }
2821 xmlXPathFreeObject(cur);
2822}
2823
2824/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002825 * xmlXPathNamespaceURIFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002826 * @ctxt: the XPath Parser context
2827 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002828 * Implement the namespace-uri() XPath function
2829 * The namespace-uri function returns a string containing the
2830 * namespace URI of the expanded name of the node in the argument
2831 * node-set that is first in document order. If the node-set is empty,
2832 * the first node has no name, or the expanded name has no namespace
2833 * URI, an empty string is returned. If the argument is omitted it
2834 * defaults to the context node.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002835 */
2836void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002837xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002838 xmlXPathObjectPtr cur;
2839
Daniel Veillardb96e6431999-08-29 21:02:19 +00002840 if (nargs == 0) {
2841 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2842 nargs = 1;
2843 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002844 CHECK_ARITY(1);
2845 CHECK_TYPE(XPATH_NODESET);
2846 cur = valuePop(ctxt);
2847
2848 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002849 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002850 } else {
2851 int i = 0; /* Should be first in document order !!!!! */
2852
2853 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002854 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002855 else
2856 valuePush(ctxt, xmlXPathNewString(
2857 cur->nodesetval->nodeTab[i]->ns->href));
2858 }
2859 xmlXPathFreeObject(cur);
2860}
2861
2862/**
2863 * xmlXPathNameFunction:
2864 * @ctxt: the XPath Parser context
2865 *
2866 * Implement the name() XPath function
2867 * The name function returns a string containing a QName representing
2868 * the name of the node in the argument node-set that is first in documenti
2869 * order. The QName must represent the name with respect to the namespace
2870 * declarations in effect on the node whose name is being represented.
2871 * Typically, this will be the form in which the name occurred in the XML
2872 * source. This need not be the case if there are namespace declarations
2873 * in effect on the node that associate multiple prefixes with the same
2874 * namespace. However, an implementation may include information about
2875 * the original prefix in its representation of nodes; in this case, an
2876 * implementation can ensure that the returned string is always the same
2877 * as the QName used in the XML source. If the argument it omitted it
2878 * defaults to the context node.
2879 * Libxml keep the original prefix so the "real qualified name" used is
2880 * returned.
2881 */
2882void
2883xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2884 xmlXPathObjectPtr cur;
2885
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002886 if (nargs == 0) {
2887 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2888 nargs = 1;
2889 }
2890
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002891 CHECK_ARITY(1);
2892 CHECK_TYPE(XPATH_NODESET);
2893 cur = valuePop(ctxt);
2894
2895 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002896 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002897 } else {
2898 int i = 0; /* Should be first in document order !!!!! */
2899
2900 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2901 valuePush(ctxt, xmlXPathNewString(
2902 cur->nodesetval->nodeTab[i]->name));
2903
2904 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002905 char name[2000];
Daniel Veillard39c7d712000-09-10 16:14:55 +00002906#ifdef HAVE_SNPRINTF
2907 snprintf(name, sizeof(name), "%s:%s",
2908 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2909 (char *) cur->nodesetval->nodeTab[i]->name);
2910#else
Daniel Veillardb96e6431999-08-29 21:02:19 +00002911 sprintf(name, "%s:%s",
2912 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2913 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00002914#endif
2915 name[sizeof(name) - 1] = 0;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002916 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002917 }
2918 }
2919 xmlXPathFreeObject(cur);
2920}
2921
2922/**
2923 * xmlXPathStringFunction:
2924 * @ctxt: the XPath Parser context
2925 *
2926 * Implement the string() XPath function
2927 * he string function converts an object to a string as follows:
2928 * - A node-set is converted to a string by returning the value of
2929 * the node in the node-set that is first in document order.
2930 * If the node-set is empty, an empty string is returned.
2931 * - A number is converted to a string as follows
2932 * + NaN is converted to the string NaN
2933 * + positive zero is converted to the string 0
2934 * + negative zero is converted to the string 0
2935 * + positive infinity is converted to the string Infinity
2936 * + negative infinity is converted to the string -Infinity
2937 * + if the number is an integer, the number is represented in
2938 * decimal form as a Number with no decimal point and no leading
2939 * zeros, preceded by a minus sign (-) if the number is negative
2940 * + otherwise, the number is represented in decimal form as a
2941 * Number including a decimal point with at least one digit
2942 * before the decimal point and at least one digit after the
2943 * decimal point, preceded by a minus sign (-) if the number
2944 * is negative; there must be no leading zeros before the decimal
2945 * point apart possibly from the one required digit immediatelyi
2946 * before the decimal point; beyond the one required digit
2947 * after the decimal point there must be as many, but only as
2948 * many, more digits as are needed to uniquely distinguish the
2949 * number from all other IEEE 754 numeric values.
2950 * - The boolean false value is converted to the string false.
2951 * The boolean true value is converted to the string true.
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002952 *
2953 * If the argument is omitted, it defaults to a node-set with the
2954 * context node as its only member.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002955 */
2956void
2957xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2958 xmlXPathObjectPtr cur;
2959
Daniel Veillardf6bf9212000-10-26 14:07:44 +00002960 if (nargs == 0) {
2961 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2962 nargs = 1;
2963 }
2964
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002965 CHECK_ARITY(1);
2966 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002967 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002968 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002969 case XPATH_UNDEFINED:
2970#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002971 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00002972#endif
2973 valuePush(ctxt, xmlXPathNewCString(""));
2974 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002975 case XPATH_NODESET:
2976 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002977 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002978 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002979 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002980 int i = 0; /* Should be first in document order !!!!! */
2981 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2982 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002983 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002984 }
2985 xmlXPathFreeObject(cur);
2986 return;
2987 case XPATH_STRING:
2988 valuePush(ctxt, cur);
2989 return;
2990 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002991 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2992 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002993 xmlXPathFreeObject(cur);
2994 return;
2995 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002996 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002997
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002998 if (isnan(cur->floatval))
2999 sprintf(buf, "NaN");
3000 else if (isinf(cur->floatval) > 0)
3001 sprintf(buf, "+Infinity");
3002 else if (isinf(cur->floatval) < 0)
3003 sprintf(buf, "-Infinity");
3004 else
3005 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003006 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003007 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003008 return;
3009 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003010 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003011 case XPATH_POINT:
3012 case XPATH_RANGE:
3013 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003014 TODO
3015 valuePush(ctxt, xmlXPathNewCString(""));
3016 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003017 }
3018 STRANGE
3019}
3020
3021/**
3022 * xmlXPathStringLengthFunction:
3023 * @ctxt: the XPath Parser context
3024 *
3025 * Implement the string-length() XPath function
3026 * The string-length returns the number of characters in the string
3027 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3028 * the context node converted to a string, in other words the value
3029 * of the context node.
3030 */
3031void
3032xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3033 xmlXPathObjectPtr cur;
3034
3035 if (nargs == 0) {
3036 if (ctxt->context->node == NULL) {
3037 valuePush(ctxt, xmlXPathNewFloat(0));
3038 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003039 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003040
3041 content = xmlNodeGetContent(ctxt->context->node);
3042 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003043 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003044 }
3045 return;
3046 }
3047 CHECK_ARITY(1);
3048 CHECK_TYPE(XPATH_STRING);
3049 cur = valuePop(ctxt);
3050 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3051 xmlXPathFreeObject(cur);
3052}
3053
3054/**
3055 * xmlXPathConcatFunction:
3056 * @ctxt: the XPath Parser context
3057 *
3058 * Implement the concat() XPath function
3059 * The concat function returns the concatenation of its arguments.
3060 */
3061void
3062xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003063 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003064 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003065
3066 if (nargs < 2) {
3067 CHECK_ARITY(2);
3068 }
3069
3070 cur = valuePop(ctxt);
3071 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3072 xmlXPathFreeObject(cur);
3073 return;
3074 }
3075 nargs--;
3076
3077 while (nargs > 0) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003078 newobj = valuePop(ctxt);
3079 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3080 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003081 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003082 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003083 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003084 tmp = xmlStrcat(newobj->stringval, cur->stringval);
3085 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003086 cur->stringval = tmp;
3087
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003088 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003089 nargs--;
3090 }
3091 valuePush(ctxt, cur);
3092}
3093
3094/**
3095 * xmlXPathContainsFunction:
3096 * @ctxt: the XPath Parser context
3097 *
3098 * Implement the contains() XPath function
3099 * The contains function returns true if the first argument string
3100 * contains the second argument string, and otherwise returns false.
3101 */
3102void
3103xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3104 xmlXPathObjectPtr hay, needle;
3105
3106 CHECK_ARITY(2);
3107 CHECK_TYPE(XPATH_STRING);
3108 needle = valuePop(ctxt);
3109 hay = valuePop(ctxt);
3110 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3111 xmlXPathFreeObject(hay);
3112 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003113 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003114 }
3115 if (xmlStrstr(hay->stringval, needle->stringval))
3116 valuePush(ctxt, xmlXPathNewBoolean(1));
3117 else
3118 valuePush(ctxt, xmlXPathNewBoolean(0));
3119 xmlXPathFreeObject(hay);
3120 xmlXPathFreeObject(needle);
3121}
3122
3123/**
3124 * xmlXPathStartsWithFunction:
3125 * @ctxt: the XPath Parser context
3126 *
3127 * Implement the starts-with() XPath function
3128 * The starts-with function returns true if the first argument string
3129 * starts with the second argument string, and otherwise returns false.
3130 */
3131void
3132xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3133 xmlXPathObjectPtr hay, needle;
3134 int n;
3135
3136 CHECK_ARITY(2);
3137 CHECK_TYPE(XPATH_STRING);
3138 needle = valuePop(ctxt);
3139 hay = valuePop(ctxt);
3140 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3141 xmlXPathFreeObject(hay);
3142 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003143 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003144 }
3145 n = xmlStrlen(needle->stringval);
3146 if (xmlStrncmp(hay->stringval, needle->stringval, n))
3147 valuePush(ctxt, xmlXPathNewBoolean(0));
3148 else
3149 valuePush(ctxt, xmlXPathNewBoolean(1));
3150 xmlXPathFreeObject(hay);
3151 xmlXPathFreeObject(needle);
3152}
3153
3154/**
3155 * xmlXPathSubstringFunction:
3156 * @ctxt: the XPath Parser context
3157 *
3158 * Implement the substring() XPath function
3159 * The substring function returns the substring of the first argument
3160 * starting at the position specified in the second argument with
3161 * length specified in the third argument. For example,
3162 * substring("12345",2,3) returns "234". If the third argument is not
3163 * specified, it returns the substring starting at the position specified
3164 * in the second argument and continuing to the end of the string. For
3165 * example, substring("12345",2) returns "2345". More precisely, each
3166 * character in the string (see [3.6 Strings]) is considered to have a
3167 * numeric position: the position of the first character is 1, the position
3168 * of the second character is 2 and so on. The returned substring contains
3169 * those characters for which the position of the character is greater than
3170 * or equal to the second argument and, if the third argument is specified,
3171 * less than the sum of the second and third arguments; the comparisons
3172 * and addition used for the above follow the standard IEEE 754 rules. Thus:
3173 * - substring("12345", 1.5, 2.6) returns "234"
3174 * - substring("12345", 0, 3) returns "12"
3175 * - substring("12345", 0 div 0, 3) returns ""
3176 * - substring("12345", 1, 0 div 0) returns ""
3177 * - substring("12345", -42, 1 div 0) returns "12345"
3178 * - substring("12345", -1 div 0, 1 div 0) returns ""
3179 */
3180void
3181xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3182 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003183 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003184 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003185 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003186
3187 /*
3188 * Conformance needs to be checked !!!!!
3189 */
3190 if (nargs < 2) {
3191 CHECK_ARITY(2);
3192 }
3193 if (nargs > 3) {
3194 CHECK_ARITY(3);
3195 }
3196 if (nargs == 3) {
3197 CHECK_TYPE(XPATH_NUMBER);
3198 len = valuePop(ctxt);
3199 le = len->floatval;
3200 xmlXPathFreeObject(len);
3201 } else {
3202 le = 2000000000;
3203 }
3204 CHECK_TYPE(XPATH_NUMBER);
3205 start = valuePop(ctxt);
3206 in = start->floatval;
3207 xmlXPathFreeObject(start);
3208 CHECK_TYPE(XPATH_STRING);
3209 str = valuePop(ctxt);
3210 le += in;
3211
3212 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003213 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003214 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003215
3216 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003217 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003218 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003219
3220 /* back to a zero based len */
3221 i--;
3222 l--;
3223
3224 /* check against the string len */
3225 if (l > 1024) {
3226 l = xmlStrlen(str->stringval);
3227 }
3228 if (i < 0) {
3229 i = 0;
3230 }
3231
3232 /* number of chars to copy */
3233 l -= i;
3234
3235 ret = xmlStrsub(str->stringval, i, l);
3236 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00003237 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003238 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003239 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003240 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003241 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003242 xmlXPathFreeObject(str);
3243}
3244
3245/**
3246 * xmlXPathSubstringBeforeFunction:
3247 * @ctxt: the XPath Parser context
3248 *
3249 * Implement the substring-before() XPath function
3250 * The substring-before function returns the substring of the first
3251 * argument string that precedes the first occurrence of the second
3252 * argument string in the first argument string, or the empty string
3253 * if the first argument string does not contain the second argument
3254 * string. For example, substring-before("1999/04/01","/") returns 1999.
3255 */
3256void
3257xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003258 xmlXPathObjectPtr str;
3259 xmlXPathObjectPtr find;
3260 xmlBufferPtr target;
3261 const xmlChar *point;
3262 int offset;
3263
3264 CHECK_ARITY(2);
3265 find = valuePop(ctxt);
3266 str = valuePop(ctxt);
3267
3268 target = xmlBufferCreate();
3269 if (target) {
3270 point = xmlStrstr(str->stringval, find->stringval);
3271 if (point) {
3272 offset = (int)(point - str->stringval);
3273 xmlBufferAdd(target, str->stringval, offset);
3274 }
3275 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3276 xmlBufferFree(target);
3277 }
3278
3279 xmlXPathFreeObject(str);
3280 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003281}
3282
3283/**
3284 * xmlXPathSubstringAfterFunction:
3285 * @ctxt: the XPath Parser context
3286 *
3287 * Implement the substring-after() XPath function
3288 * The substring-after function returns the substring of the first
3289 * argument string that follows the first occurrence of the second
3290 * argument string in the first argument string, or the empty stringi
3291 * if the first argument string does not contain the second argument
3292 * string. For example, substring-after("1999/04/01","/") returns 04/01,
3293 * and substring-after("1999/04/01","19") returns 99/04/01.
3294 */
3295void
3296xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003297 xmlXPathObjectPtr str;
3298 xmlXPathObjectPtr find;
3299 xmlBufferPtr target;
3300 const xmlChar *point;
3301 int offset;
3302
3303 CHECK_ARITY(2);
3304 find = valuePop(ctxt);
3305 str = valuePop(ctxt);
3306
3307 target = xmlBufferCreate();
3308 if (target) {
3309 point = xmlStrstr(str->stringval, find->stringval);
3310 if (point) {
3311 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
3312 xmlBufferAdd(target, &str->stringval[offset],
3313 xmlStrlen(str->stringval) - offset);
3314 }
3315 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3316 xmlBufferFree(target);
3317 }
3318
3319 xmlXPathFreeObject(str);
3320 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003321}
3322
3323/**
3324 * xmlXPathNormalizeFunction:
3325 * @ctxt: the XPath Parser context
3326 *
3327 * Implement the normalize() XPath function
3328 * The normalize function returns the argument string with white
3329 * space normalized by stripping leading and trailing whitespace
3330 * and replacing sequences of whitespace characters by a single
3331 * space. Whitespace characters are the same allowed by the S production
3332 * in XML. If the argument is omitted, it defaults to the context
3333 * node converted to a string, in other words the value of the context node.
3334 */
3335void
3336xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003337 xmlXPathObjectPtr obj = NULL;
3338 xmlChar *source = NULL;
3339 xmlBufferPtr target;
3340 xmlChar blank;
3341
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003342 if (nargs == 0) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003343 /* Use current context node */
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003344 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3345 xmlXPathStringFunction(ctxt, 1);
3346 nargs = 1;
Daniel Veillard46057e12000-09-24 18:49:59 +00003347 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003348
3349 CHECK_ARITY(1);
3350 CHECK_TYPE(XPATH_STRING);
3351 obj = valuePop(ctxt);
3352 source = obj->stringval;
3353
Daniel Veillard46057e12000-09-24 18:49:59 +00003354 target = xmlBufferCreate();
3355 if (target && source) {
3356
3357 /* Skip leading whitespaces */
3358 while (IS_BLANK(*source))
3359 source++;
3360
3361 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
3362 blank = 0;
3363 while (*source) {
3364 if (IS_BLANK(*source)) {
3365 blank = *source;
3366 } else {
3367 if (blank) {
3368 xmlBufferAdd(target, &blank, 1);
3369 blank = 0;
3370 }
3371 xmlBufferAdd(target, source, 1);
3372 }
3373 source++;
3374 }
3375
3376 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3377 xmlBufferFree(target);
3378 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003379 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003380}
3381
3382/**
3383 * xmlXPathTranslateFunction:
3384 * @ctxt: the XPath Parser context
3385 *
3386 * Implement the translate() XPath function
3387 * The translate function returns the first argument string with
3388 * occurrences of characters in the second argument string replaced
3389 * by the character at the corresponding position in the third argument
3390 * string. For example, translate("bar","abc","ABC") returns the string
3391 * BAr. If there is a character in the second argument string with no
3392 * character at a corresponding position in the third argument string
3393 * (because the second argument string is longer than the third argument
3394 * string), then occurrences of that character in the first argument
3395 * string are removed. For example, translate("--aaa--","abc-","ABC")
3396 * returns "AAA". If a character occurs more than once in second
3397 * argument string, then the first occurrence determines the replacement
3398 * character. If the third argument string is longer than the second
3399 * argument string, then excess characters are ignored.
3400 */
3401void
3402xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003403 xmlXPathObjectPtr str;
3404 xmlXPathObjectPtr from;
3405 xmlXPathObjectPtr to;
3406 xmlBufferPtr target;
3407 int i, offset, max;
3408 xmlChar ch;
3409 const xmlChar *point;
3410
3411 CHECK_ARITY(3);
3412
3413 to = valuePop(ctxt);
3414 from = valuePop(ctxt);
3415 str = valuePop(ctxt);
3416
3417 target = xmlBufferCreate();
3418 if (target) {
3419 max = xmlStrlen(to->stringval);
3420 for (i = 0; (ch = str->stringval[i]); i++) {
3421 point = xmlStrchr(from->stringval, ch);
3422 if (point) {
3423 /* Warning: This may not work with UTF-8 */
3424 offset = (int)(point - from->stringval);
3425 if (offset < max)
3426 xmlBufferAdd(target, &to->stringval[offset], 1);
3427 } else
3428 xmlBufferAdd(target, &ch, 1);
3429 }
3430 }
3431 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3432 xmlBufferFree(target);
3433 xmlXPathFreeObject(str);
3434 xmlXPathFreeObject(from);
3435 xmlXPathFreeObject(to);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003436}
3437
3438/**
3439 * xmlXPathBooleanFunction:
3440 * @ctxt: the XPath Parser context
3441 *
3442 * Implement the boolean() XPath function
3443 * he boolean function converts its argument to a boolean as follows:
3444 * - a number is true if and only if it is neither positive or
3445 * negative zero nor NaN
3446 * - a node-set is true if and only if it is non-empty
3447 * - a string is true if and only if its length is non-zero
3448 */
3449void
3450xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3451 xmlXPathObjectPtr cur;
3452 int res = 0;
3453
3454 CHECK_ARITY(1);
3455 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003456 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003457 switch (cur->type) {
3458 case XPATH_NODESET:
3459 if ((cur->nodesetval == NULL) ||
3460 (cur->nodesetval->nodeNr == 0)) res = 0;
3461 else
3462 res = 1;
3463 break;
3464 case XPATH_STRING:
3465 if ((cur->stringval == NULL) ||
3466 (cur->stringval[0] == 0)) res = 0;
3467 else
3468 res = 1;
3469 break;
3470 case XPATH_BOOLEAN:
3471 valuePush(ctxt, cur);
3472 return;
3473 case XPATH_NUMBER:
3474 if (cur->floatval) res = 1;
3475 break;
3476 default:
3477 STRANGE
3478 }
3479 xmlXPathFreeObject(cur);
3480 valuePush(ctxt, xmlXPathNewBoolean(res));
3481}
3482
3483/**
3484 * xmlXPathNotFunction:
3485 * @ctxt: the XPath Parser context
3486 *
3487 * Implement the not() XPath function
3488 * The not function returns true if its argument is false,
3489 * and false otherwise.
3490 */
3491void
3492xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3493 CHECK_ARITY(1);
3494 CHECK_TYPE(XPATH_BOOLEAN);
3495 ctxt->value->boolval = ! ctxt->value->boolval;
3496}
3497
3498/**
3499 * xmlXPathTrueFunction:
3500 * @ctxt: the XPath Parser context
3501 *
3502 * Implement the true() XPath function
3503 */
3504void
3505xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3506 CHECK_ARITY(0);
3507 valuePush(ctxt, xmlXPathNewBoolean(1));
3508}
3509
3510/**
3511 * xmlXPathFalseFunction:
3512 * @ctxt: the XPath Parser context
3513 *
3514 * Implement the false() XPath function
3515 */
3516void
3517xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3518 CHECK_ARITY(0);
3519 valuePush(ctxt, xmlXPathNewBoolean(0));
3520}
3521
3522/**
3523 * xmlXPathLangFunction:
3524 * @ctxt: the XPath Parser context
3525 *
3526 * Implement the lang() XPath function
3527 * The lang function returns true or false depending on whether the
3528 * language of the context node as specified by xml:lang attributes
3529 * is the same as or is a sublanguage of the language specified by
3530 * the argument string. The language of the context node is determined
3531 * by the value of the xml:lang attribute on the context node, or, if
3532 * the context node has no xml:lang attribute, by the value of the
3533 * xml:lang attribute on the nearest ancestor of the context node that
3534 * has an xml:lang attribute. If there is no such attribute, then lang
3535 * returns false. If there is such an attribute, then lang returns
3536 * true if the attribute value is equal to the argument ignoring case,
3537 * or if there is some suffix starting with - such that the attribute
3538 * value is equal to the argument ignoring that suffix of the attribute
3539 * value and ignoring case.
3540 */
3541void
3542xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003543 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003544 const xmlChar *theLang;
3545 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003546 int ret = 0;
3547 int i;
3548
3549 CHECK_ARITY(1);
3550 CHECK_TYPE(XPATH_STRING);
3551 val = valuePop(ctxt);
3552 lang = val->stringval;
3553 theLang = xmlNodeGetLang(ctxt->context->node);
3554 if ((theLang != NULL) && (lang != NULL)) {
3555 for (i = 0;lang[i] != 0;i++)
3556 if (toupper(lang[i]) != toupper(theLang[i]))
3557 goto not_equal;
3558 ret = 1;
3559 }
3560not_equal:
3561 xmlXPathFreeObject(val);
3562 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003563}
3564
3565/**
3566 * xmlXPathNumberFunction:
3567 * @ctxt: the XPath Parser context
3568 *
3569 * Implement the number() XPath function
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003570 *
3571 * BUG: since we directly call xmlXPathStringEvalNumber(),
3572 * number("-1") isn't evaluated in -1.0 but in NaN.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003573 */
3574void
3575xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3576 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003577 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003578
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003579 if (nargs == 0) {
3580 if (ctxt->context->node == NULL) {
3581 valuePush(ctxt, xmlXPathNewFloat(0.0));
3582 } else {
3583 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
3584
3585 res = xmlXPathStringEvalNumber(content);
3586 valuePush(ctxt, xmlXPathNewFloat(res));
3587 xmlFree(content);
3588 }
3589 return;
3590 }
3591
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003592 CHECK_ARITY(1);
3593 cur = valuePop(ctxt);
3594 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003595 case XPATH_UNDEFINED:
3596#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003597 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00003598#endif
3599 valuePush(ctxt, xmlXPathNewFloat(0.0));
3600 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003601 case XPATH_NODESET:
3602 valuePush(ctxt, cur);
3603 xmlXPathStringFunction(ctxt, 1);
3604 cur = valuePop(ctxt);
3605 case XPATH_STRING:
3606 res = xmlXPathStringEvalNumber(cur->stringval);
3607 valuePush(ctxt, xmlXPathNewFloat(res));
3608 xmlXPathFreeObject(cur);
3609 return;
3610 case XPATH_BOOLEAN:
3611 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
3612 else valuePush(ctxt, xmlXPathNewFloat(0.0));
3613 xmlXPathFreeObject(cur);
3614 return;
3615 case XPATH_NUMBER:
3616 valuePush(ctxt, cur);
3617 return;
Daniel Veillard740abf52000-10-02 23:04:54 +00003618 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003619 case XPATH_POINT:
3620 case XPATH_RANGE:
3621 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003622 TODO
3623 valuePush(ctxt, xmlXPathNewFloat(0.0));
3624 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003625 }
3626 STRANGE
3627}
3628
3629/**
3630 * xmlXPathSumFunction:
3631 * @ctxt: the XPath Parser context
3632 *
3633 * Implement the sum() XPath function
3634 * The sum function returns the sum of the values of the nodes in
3635 * the argument node-set.
3636 */
3637void
3638xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003639 xmlXPathObjectPtr cur;
3640 int i;
3641
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003642 CHECK_ARITY(1);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003643 CHECK_TYPE(XPATH_NODESET);
3644 cur = valuePop(ctxt);
3645
3646 if (cur->nodesetval->nodeNr == 0) {
3647 valuePush(ctxt, xmlXPathNewFloat(0.0));
3648 } else {
3649 valuePush(ctxt,
3650 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
3651 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
3652 valuePush(ctxt,
3653 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3654 xmlXPathAddValues(ctxt);
3655 }
3656 }
3657 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003658}
3659
3660/**
3661 * xmlXPathFloorFunction:
3662 * @ctxt: the XPath Parser context
3663 *
3664 * Implement the floor() XPath function
3665 * The floor function returns the largest (closest to positive infinity)
3666 * number that is not greater than the argument and that is an integer.
3667 */
3668void
3669xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3670 CHECK_ARITY(1);
3671 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003672#if 0
3673 ctxt->value->floatval = floor(ctxt->value->floatval);
3674#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003675 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003676 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003677#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003678}
3679
3680/**
3681 * xmlXPathCeilingFunction:
3682 * @ctxt: the XPath Parser context
3683 *
3684 * Implement the ceiling() XPath function
3685 * The ceiling function returns the smallest (closest to negative infinity)
3686 * number that is not less than the argument and that is an integer.
3687 */
3688void
3689xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003690 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003691
3692 CHECK_ARITY(1);
3693 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003694
3695#if 0
3696 ctxt->value->floatval = ceil(ctxt->value->floatval);
3697#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003698 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003699 if (f != ctxt->value->floatval)
3700 ctxt->value->floatval = f + 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003701#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003702}
3703
3704/**
3705 * xmlXPathRoundFunction:
3706 * @ctxt: the XPath Parser context
3707 *
3708 * Implement the round() XPath function
3709 * The round function returns the number that is closest to the
3710 * argument and that is an integer. If there are two such numbers,
3711 * then the one that is even is returned.
3712 */
3713void
3714xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003715 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003716
3717 CHECK_ARITY(1);
3718 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003719
3720 if ((ctxt->value->floatval == xmlXPathNAN) ||
3721 (ctxt->value->floatval == xmlXPathPINF) ||
3722 (ctxt->value->floatval == xmlXPathNINF) ||
3723 (ctxt->value->floatval == 0.0))
3724 return;
3725
3726#if 0
3727 f = floor(ctxt->value->floatval);
3728#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003729 f = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003730#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003731 if (ctxt->value->floatval < f + 0.5)
3732 ctxt->value->floatval = f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003733 else
3734 ctxt->value->floatval = f + 1;
3735}
3736
3737/************************************************************************
3738 * *
3739 * The Parser *
3740 * *
3741 ************************************************************************/
3742
3743/*
3744 * a couple of forward declarations since we use a recursive call based
3745 * implementation.
3746 */
3747void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3748void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3749void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3750void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3751
3752/**
3753 * xmlXPathParseNCName:
3754 * @ctxt: the XPath Parser context
3755 *
3756 * parse an XML namespace non qualified name.
3757 *
3758 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3759 *
3760 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3761 * CombiningChar | Extender
3762 *
3763 * Returns the namespace name or NULL
3764 */
3765
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003766xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003767xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003768 const xmlChar *q;
3769 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003770
3771 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3772 q = NEXT;
3773
3774 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3775 (CUR == '.') || (CUR == '-') ||
3776 (CUR == '_') ||
3777 (IS_COMBINING(CUR)) ||
3778 (IS_EXTENDER(CUR)))
3779 NEXT;
3780
3781 ret = xmlStrndup(q, CUR_PTR - q);
3782
3783 return(ret);
3784}
3785
3786/**
3787 * xmlXPathParseQName:
3788 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003789 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003790 *
3791 * parse an XML qualified name
3792 *
3793 * [NS 5] QName ::= (Prefix ':')? LocalPart
3794 *
3795 * [NS 6] Prefix ::= NCName
3796 *
3797 * [NS 7] LocalPart ::= NCName
3798 *
3799 * Returns the function returns the local part, and prefix is updated
3800 * to get the Prefix if any.
3801 */
3802
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003803xmlChar *
3804xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3805 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003806
3807 *prefix = NULL;
3808 ret = xmlXPathParseNCName(ctxt);
3809 if (CUR == ':') {
3810 *prefix = ret;
3811 NEXT;
3812 ret = xmlXPathParseNCName(ctxt);
3813 }
3814 return(ret);
3815}
3816
3817/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00003818 * xmlXPathParseName:
3819 * @ctxt: the XPointer Parser context
3820 *
3821 * parse an XML name
3822 *
3823 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3824 * CombiningChar | Extender
3825 *
3826 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3827 *
3828 * Returns the namespace name or NULL
3829 */
3830
3831xmlChar *
3832xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
3833 const xmlChar *q;
3834 xmlChar *ret = NULL;
3835
3836 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3837 q = NEXT;
3838
3839 /* TODO Make this UTF8 compliant !!! */
3840 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3841 (CUR == '.') || (CUR == '-') ||
3842 (CUR == '_') || (CUR == ':') ||
3843 (IS_COMBINING(CUR)) ||
3844 (IS_EXTENDER(CUR)))
3845 NEXT;
3846
3847 ret = xmlStrndup(q, CUR_PTR - q);
3848
3849 return(ret);
3850}
3851
3852/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003853 * xmlXPathStringEvalNumber:
3854 * @str: A string to scan
3855 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003856 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003857 * | '.' Digits
3858 * [31] Digits ::= [0-9]+
3859 *
3860 * Parse and evaluate a Number in the string
3861 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003862 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003863 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003864double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003865xmlXPathStringEvalNumber(const xmlChar *str) {
3866 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003867 double ret = 0.0;
3868 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003869 int ok = 0;
3870
3871 while (*cur == ' ') cur++;
3872 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003873 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003874 }
3875 while ((*cur >= '0') && (*cur <= '9')) {
3876 ret = ret * 10 + (*cur - '0');
3877 ok = 1;
3878 cur++;
3879 }
3880 if (*cur == '.') {
3881 cur++;
3882 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003883 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003884 }
3885 while ((*cur >= '0') && (*cur <= '9')) {
3886 mult /= 10;
3887 ret = ret + (*cur - '0') * mult;
3888 cur++;
3889 }
3890 }
3891 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003892 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003893 return(ret);
3894}
3895
3896/**
3897 * xmlXPathEvalNumber:
3898 * @ctxt: the XPath Parser context
3899 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003900 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003901 * | '.' Digits
3902 * [31] Digits ::= [0-9]+
3903 *
3904 * Parse and evaluate a Number, then push it on the stack
3905 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003906 */
3907void
3908xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003909 double ret = 0.0;
3910 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003911 int ok = 0;
3912
3913 CHECK_ERROR;
3914 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003915 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003916 }
3917 while ((CUR >= '0') && (CUR <= '9')) {
3918 ret = ret * 10 + (CUR - '0');
3919 ok = 1;
3920 NEXT;
3921 }
3922 if (CUR == '.') {
3923 NEXT;
3924 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003925 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003926 }
3927 while ((CUR >= '0') && (CUR <= '9')) {
3928 mult /= 10;
3929 ret = ret + (CUR - '0') * mult;
3930 NEXT;
3931 }
3932 }
3933 valuePush(ctxt, xmlXPathNewFloat(ret));
3934}
3935
3936/**
3937 * xmlXPathEvalLiteral:
3938 * @ctxt: the XPath Parser context
3939 *
3940 * Parse a Literal and push it on the stack.
3941 *
3942 * [29] Literal ::= '"' [^"]* '"'
3943 * | "'" [^']* "'"
3944 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003945 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003946 */
3947void
3948xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003949 const xmlChar *q;
3950 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003951
3952 if (CUR == '"') {
3953 NEXT;
3954 q = CUR_PTR;
3955 while ((IS_CHAR(CUR)) && (CUR != '"'))
3956 NEXT;
3957 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003958 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003959 } else {
3960 ret = xmlStrndup(q, CUR_PTR - q);
3961 NEXT;
3962 }
3963 } else if (CUR == '\'') {
3964 NEXT;
3965 q = CUR_PTR;
3966 while ((IS_CHAR(CUR)) && (CUR != '\''))
3967 NEXT;
3968 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003969 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003970 } else {
3971 ret = xmlStrndup(q, CUR_PTR - q);
3972 NEXT;
3973 }
3974 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003975 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003976 }
3977 if (ret == NULL) return;
3978 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003979 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003980}
3981
3982/**
3983 * xmlXPathEvalVariableReference:
3984 * @ctxt: the XPath Parser context
3985 *
3986 * Parse a VariableReference, evaluate it and push it on the stack.
3987 *
3988 * The variable bindings consist of a mapping from variable names
3989 * to variable values. The value of a variable is an object, which
3990 * of any of the types that are possible for the value of an expression,
3991 * and may also be of additional types not specified here.
3992 *
3993 * Early evaluation is possible since:
3994 * The variable bindings [...] used to evaluate a subexpression are
3995 * always the same as those used to evaluate the containing expression.
3996 *
3997 * [36] VariableReference ::= '$' QName
3998 */
3999void
4000xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004001 xmlChar *name;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004002 xmlXPathObjectPtr value;
4003
Daniel Veillard55b91f22000-10-05 16:30:11 +00004004 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004005 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004006 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004007 }
Daniel Veillard2d38f042000-10-11 10:54:10 +00004008 name = xmlXPathParseName(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004009 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004010 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004011 }
Daniel Veillard2d38f042000-10-11 10:54:10 +00004012 value = xmlXPathVariableLookup(ctxt->context, name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004013 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004014 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004015 }
4016 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00004017 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004018 SKIP_BLANKS;
4019}
4020
4021/**
4022 * xmlXPathIsNodeType:
4023 * @ctxt: the XPath Parser context
4024 * @name: a name string
4025 *
4026 * Is the name given a NodeType one.
4027 *
4028 * [38] NodeType ::= 'comment'
4029 * | 'text'
4030 * | 'processing-instruction'
4031 * | 'node'
4032 *
4033 * Returns 1 if true 0 otherwise
4034 */
4035int
4036xmlXPathIsNodeType(const xmlChar *name) {
4037 if (name == NULL)
4038 return(0);
4039
4040 if (xmlStrEqual(name, BAD_CAST "comment"))
4041 return(1);
4042 if (xmlStrEqual(name, BAD_CAST "text"))
4043 return(1);
4044 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4045 return(1);
4046 if (xmlStrEqual(name, BAD_CAST "node"))
4047 return(1);
4048 return(0);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004049}
4050
4051
4052/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00004053 * xmlXPathIsFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004054 * @ctxt: the XPath Parser context
4055 * @name: a name string
4056 *
4057 * Search for a function of the given name
4058 *
4059 * [35] FunctionName ::= QName - NodeType
4060 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004061 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004062 *
4063 * Returns the xmlXPathFunction if found, or NULL otherwise
4064 */
4065xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004066xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard52afe802000-10-22 16:56:02 +00004067 return((xmlXPathFunction) xmlHashLookup(ctxt->context->funcHash, name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004068}
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004069
4070/**
4071 * xmlXPathEvalFunctionCall:
4072 * @ctxt: the XPath Parser context
4073 *
4074 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4075 * [17] Argument ::= Expr
4076 *
4077 * Parse and evaluate a function call, the evaluation of all arguments are
4078 * pushed on the stack
4079 */
4080void
4081xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004082 xmlChar *name;
4083 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004084 xmlXPathFunction func;
4085 int nbargs = 0;
4086
4087 name = xmlXPathParseQName(ctxt, &prefix);
4088 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004089 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004090 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004091 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004092 func = xmlXPathIsFunction(ctxt, name);
4093 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004094 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004095 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004096 }
4097#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004098 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004099#endif
4100
4101 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004102 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004103 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004104 }
4105 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004106 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004107
4108 while (CUR != ')') {
4109 xmlXPathEvalExpr(ctxt);
4110 nbargs++;
4111 if (CUR == ')') break;
4112 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004113 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004114 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004115 }
4116 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004117 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004118 }
4119 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004120 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004121 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004122 func(ctxt, nbargs);
4123}
4124
4125/**
4126 * xmlXPathEvalPrimaryExpr:
4127 * @ctxt: the XPath Parser context
4128 *
4129 * [15] PrimaryExpr ::= VariableReference
4130 * | '(' Expr ')'
4131 * | Literal
4132 * | Number
4133 * | FunctionCall
4134 *
4135 * Parse and evaluate a primary expression, then push the result on the stack
4136 */
4137void
4138xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004139 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004140 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4141 else if (CUR == '(') {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004142 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004143 SKIP_BLANKS;
Daniel Veillard55b91f22000-10-05 16:30:11 +00004144 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004145 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004146 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004147 }
4148 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004149 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004150 } else if (IS_DIGIT(CUR)) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004151 xmlXPathEvalNumber(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004152 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004153 xmlXPathEvalLiteral(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004154 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004155 xmlXPathEvalFunctionCall(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004156 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004157 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004158}
4159
4160/**
4161 * xmlXPathEvalFilterExpr:
4162 * @ctxt: the XPath Parser context
4163 *
4164 * [20] FilterExpr ::= PrimaryExpr
4165 * | FilterExpr Predicate
4166 *
4167 * Parse and evaluate a filter expression, then push the result on the stack
4168 * Square brackets are used to filter expressions in the same way that
4169 * they are used in location paths. It is an error if the expression to
4170 * be filtered does not evaluate to a node-set. The context node list
4171 * used for evaluating the expression in square brackets is the node-set
4172 * to be filtered listed in document order.
4173 */
4174
4175void
4176xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004177 xmlXPathEvalPrimaryExpr(ctxt);
4178 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004179 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004180
4181 if (CUR != '[') return;
4182
4183 CHECK_TYPE(XPATH_NODESET);
4184
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004185 while (CUR == '[') {
4186 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004187 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004188 }
4189
4190
4191}
4192
4193/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00004194 * xmlXPathScanName:
4195 * @ctxt: the XPath Parser context
4196 *
4197 * Trickery: parse an XML name but without consuming the input flow
Daniel Veillard55b91f22000-10-05 16:30:11 +00004198 * Needed to avoid insanity in the parser state.
Daniel Veillardb96e6431999-08-29 21:02:19 +00004199 *
4200 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4201 * CombiningChar | Extender
4202 *
4203 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4204 *
4205 * [6] Names ::= Name (S Name)*
4206 *
4207 * Returns the Name parsed or NULL
4208 */
4209
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004210xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004211xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004212 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00004213 int len = 0;
4214
Daniel Veillard00fdf371999-10-08 09:40:39 +00004215 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004216 if (!IS_LETTER(CUR) && (CUR != '_') &&
4217 (CUR != ':')) {
4218 return(NULL);
4219 }
4220
4221 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4222 (NXT(len) == '.') || (NXT(len) == '-') ||
4223 (NXT(len) == '_') || (NXT(len) == ':') ||
4224 (IS_COMBINING(NXT(len))) ||
4225 (IS_EXTENDER(NXT(len)))) {
4226 buf[len] = NXT(len);
4227 len++;
4228 if (len >= XML_MAX_NAMELEN) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004229 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardb96e6431999-08-29 21:02:19 +00004230 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
4231 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4232 (NXT(len) == '.') || (NXT(len) == '-') ||
4233 (NXT(len) == '_') || (NXT(len) == ':') ||
4234 (IS_COMBINING(NXT(len))) ||
4235 (IS_EXTENDER(NXT(len))))
4236 len++;
4237 break;
4238 }
4239 }
4240 return(xmlStrndup(buf, len));
4241}
4242
4243/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004244 * xmlXPathEvalPathExpr:
4245 * @ctxt: the XPath Parser context
4246 *
4247 * [19] PathExpr ::= LocationPath
4248 * | FilterExpr
4249 * | FilterExpr '/' RelativeLocationPath
4250 * | FilterExpr '//' RelativeLocationPath
4251 *
4252 * Parse and evaluate a path expression, then push the result on the stack
4253 * The / operator and // operators combine an arbitrary expression
4254 * and a relative location path. It is an error if the expression
4255 * does not evaluate to a node-set.
4256 * The / operator does composition in the same way as when / is
4257 * used in a location path. As in location paths, // is short for
4258 * /descendant-or-self::node()/.
4259 */
4260
4261void
4262xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004263 int lc = 1; /* Should we branch to LocationPath ? */
4264 xmlChar *name = NULL; /* we may have to preparse a name to find out */
4265
Daniel Veillard00fdf371999-10-08 09:40:39 +00004266 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004267 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
4268 (CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004269 lc = 0;
4270 } else if (CUR == '/') {
4271 /* relative or absolute location path */
4272 lc = 1;
4273 } else if (CUR == '@') {
4274 /* relative abbreviated attribute location path */
4275 lc = 1;
4276 } else if (CUR == '.') {
4277 /* relative abbreviated attribute location path */
4278 lc = 1;
4279 } else {
4280 /*
4281 * Problem is finding if we have a name here whether it's:
4282 * - a nodetype
4283 * - a function call in which case it's followed by '('
4284 * - an axis in which case it's followed by ':'
4285 * - a element name
4286 * We do an a priori analysis here rather than having to
4287 * maintain parsed token content through the recursive function
4288 * calls. This looks uglier but makes the code quite easier to
4289 * read/write/debug.
4290 */
4291 SKIP_BLANKS;
4292 name = xmlXPathScanName(ctxt);
4293 if (name != NULL) {
4294 int len =xmlStrlen(name);
4295 int blank = 0;
4296
4297 while (NXT(len) != 0) {
4298 if (NXT(len) == '/') {
4299 /* element name */
4300#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004301 xmlGenericError(xmlGenericErrorContext,
4302 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004303#endif
4304 lc = 1;
4305 break;
4306 } else if (IS_BLANK(NXT(len))) {
4307 /* skip to next */
4308 blank = 1;
4309 } else if (NXT(len) == ':') {
4310#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004311 xmlGenericError(xmlGenericErrorContext,
4312 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004313#endif
4314 lc = 1;
4315 break;
4316 } else if ((NXT(len) == '(')) {
4317 /* Note Type or Function */
4318 if (xmlXPathIsNodeType(name)) {
4319#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004320 xmlGenericError(xmlGenericErrorContext,
4321 "PathExpr: Type search\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004322#endif
4323 lc = 1;
4324 } else {
4325#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004326 xmlGenericError(xmlGenericErrorContext,
4327 "PathExpr: function call\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004328#endif
4329 lc = 0;
4330 }
4331 break;
4332 } else if ((NXT(len) == '[')) {
4333 /* element name */
4334#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004335 xmlGenericError(xmlGenericErrorContext,
4336 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004337#endif
4338 lc = 1;
4339 break;
4340 } else {
4341 XP_ERROR(XPATH_EXPR_ERROR);
4342 }
4343 len++;
4344 }
4345 if (NXT(len) == 0) {
4346#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004347 xmlGenericError(xmlGenericErrorContext,
4348 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00004349#endif
4350 /* element name */
4351 lc = 1;
4352 }
4353 xmlFree(name);
4354 } else {
4355 /* make sure all cases are covered explicitely */
4356 XP_ERROR(XPATH_EXPR_ERROR);
4357 }
4358 }
4359
4360 if (lc) {
4361 xmlXPathEvalLocationPath(ctxt);
4362 } else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004363 xmlXPathEvalFilterExpr(ctxt);
4364 CHECK_ERROR;
4365 if ((CUR == '/') && (NXT(1) == '/')) {
4366 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004367 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00004368 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004369 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004370 ctxt->context->node = NULL;
4371 xmlXPathEvalRelativeLocationPath(ctxt);
4372 } else if (CUR == '/') {
4373 xmlXPathEvalRelativeLocationPath(ctxt);
4374 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004375 }
4376 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004377}
4378
4379/**
4380 * xmlXPathEvalUnionExpr:
4381 * @ctxt: the XPath Parser context
4382 *
4383 * [18] UnionExpr ::= PathExpr
4384 * | UnionExpr '|' PathExpr
4385 *
4386 * Parse and evaluate an union expression, then push the result on the stack
4387 */
4388
4389void
4390xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
4391 xmlXPathEvalPathExpr(ctxt);
4392 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004393 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004394 if (CUR == '|') {
Daniel Veillard740abf52000-10-02 23:04:54 +00004395 xmlXPathObjectPtr obj1,obj2;
4396
4397 CHECK_TYPE(XPATH_NODESET);
4398 obj1 = valuePop(ctxt);
4399 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004400
Daniel Veillard00fdf371999-10-08 09:40:39 +00004401 NEXT;
4402 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004403 xmlXPathEvalPathExpr(ctxt);
4404
Daniel Veillard740abf52000-10-02 23:04:54 +00004405 CHECK_TYPE(XPATH_NODESET);
4406 obj2 = valuePop(ctxt);
4407 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
4408 obj2->nodesetval);
4409 xmlXPathFreeObject(obj2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004410 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004411 }
4412}
4413
4414/**
4415 * xmlXPathEvalUnaryExpr:
4416 * @ctxt: the XPath Parser context
4417 *
4418 * [27] UnaryExpr ::= UnionExpr
4419 * | '-' UnaryExpr
4420 *
4421 * Parse and evaluate an unary expression, then push the result on the stack
4422 */
4423
4424void
4425xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
4426 int minus = 0;
4427
Daniel Veillard00fdf371999-10-08 09:40:39 +00004428 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004429 if (CUR == '-') {
4430 minus = 1;
4431 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004432 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004433 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004434 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004435 CHECK_ERROR;
4436 if (minus) {
4437 xmlXPathValueFlipSign(ctxt);
4438 }
4439}
4440
4441/**
4442 * xmlXPathEvalMultiplicativeExpr:
4443 * @ctxt: the XPath Parser context
4444 *
4445 * [26] MultiplicativeExpr ::= UnaryExpr
4446 * | MultiplicativeExpr MultiplyOperator UnaryExpr
4447 * | MultiplicativeExpr 'div' UnaryExpr
4448 * | MultiplicativeExpr 'mod' UnaryExpr
4449 * [34] MultiplyOperator ::= '*'
4450 *
4451 * Parse and evaluate an Additive expression, then push the result on the stack
4452 */
4453
4454void
4455xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
4456 xmlXPathEvalUnaryExpr(ctxt);
4457 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004458 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004459 while ((CUR == '*') ||
4460 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
4461 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
4462 int op = -1;
4463
4464 if (CUR == '*') {
4465 op = 0;
4466 NEXT;
4467 } else if (CUR == 'd') {
4468 op = 1;
4469 SKIP(3);
4470 } else if (CUR == 'm') {
4471 op = 2;
4472 SKIP(3);
4473 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004474 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004475 xmlXPathEvalUnaryExpr(ctxt);
4476 CHECK_ERROR;
4477 switch (op) {
4478 case 0:
4479 xmlXPathMultValues(ctxt);
4480 break;
4481 case 1:
4482 xmlXPathDivValues(ctxt);
4483 break;
4484 case 2:
4485 xmlXPathModValues(ctxt);
4486 break;
4487 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004488 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004489 }
4490}
4491
4492/**
4493 * xmlXPathEvalAdditiveExpr:
4494 * @ctxt: the XPath Parser context
4495 *
4496 * [25] AdditiveExpr ::= MultiplicativeExpr
4497 * | AdditiveExpr '+' MultiplicativeExpr
4498 * | AdditiveExpr '-' MultiplicativeExpr
4499 *
4500 * Parse and evaluate an Additive expression, then push the result on the stack
4501 */
4502
4503void
4504xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
4505 xmlXPathEvalMultiplicativeExpr(ctxt);
4506 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004507 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004508 while ((CUR == '+') || (CUR == '-')) {
4509 int plus;
4510
4511 if (CUR == '+') plus = 1;
4512 else plus = 0;
4513 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004514 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004515 xmlXPathEvalMultiplicativeExpr(ctxt);
4516 CHECK_ERROR;
4517 if (plus) xmlXPathAddValues(ctxt);
4518 else xmlXPathSubValues(ctxt);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004519 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004520 }
4521}
4522
4523/**
4524 * xmlXPathEvalRelationalExpr:
4525 * @ctxt: the XPath Parser context
4526 *
4527 * [24] RelationalExpr ::= AdditiveExpr
4528 * | RelationalExpr '<' AdditiveExpr
4529 * | RelationalExpr '>' AdditiveExpr
4530 * | RelationalExpr '<=' AdditiveExpr
4531 * | RelationalExpr '>=' AdditiveExpr
4532 *
4533 * A <= B > C is allowed ? Answer from James, yes with
4534 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
4535 * which is basically what got implemented.
4536 *
4537 * Parse and evaluate a Relational expression, then push the result
4538 * on the stack
4539 */
4540
4541void
4542xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
4543 xmlXPathEvalAdditiveExpr(ctxt);
4544 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004545 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004546 while ((CUR == '<') ||
4547 (CUR == '>') ||
4548 ((CUR == '<') && (NXT(1) == '=')) ||
4549 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004550 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004551
4552 if (CUR == '<') inf = 1;
4553 else inf = 0;
4554 if (NXT(1) == '=') strict = 0;
4555 else strict = 1;
4556 NEXT;
4557 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004558 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004559 xmlXPathEvalAdditiveExpr(ctxt);
4560 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004561 ret = xmlXPathCompareValues(ctxt, inf, strict);
4562 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard55b91f22000-10-05 16:30:11 +00004563 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004564 }
4565}
4566
4567/**
4568 * xmlXPathEvalEqualityExpr:
4569 * @ctxt: the XPath Parser context
4570 *
4571 * [23] EqualityExpr ::= RelationalExpr
4572 * | EqualityExpr '=' RelationalExpr
4573 * | EqualityExpr '!=' RelationalExpr
4574 *
4575 * A != B != C is allowed ? Answer from James, yes with
4576 * (RelationalExpr = RelationalExpr) = RelationalExpr
4577 * (RelationalExpr != RelationalExpr) != RelationalExpr
4578 * which is basically what got implemented.
4579 *
4580 * Parse and evaluate an Equality expression, then push the result on the stack
4581 *
4582 */
4583void
4584xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
4585 xmlXPathEvalRelationalExpr(ctxt);
4586 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004587 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004588 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00004589 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004590 int eq, equal;
4591
4592 if (CUR == '=') eq = 1;
4593 else eq = 0;
4594 NEXT;
4595 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004596 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004597 xmlXPathEvalRelationalExpr(ctxt);
4598 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00004599 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004600 if (eq) res = xmlXPathNewBoolean(equal);
4601 else res = xmlXPathNewBoolean(!equal);
4602 valuePush(ctxt, res);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004603 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004604 }
4605}
4606
4607/**
4608 * xmlXPathEvalAndExpr:
4609 * @ctxt: the XPath Parser context
4610 *
4611 * [22] AndExpr ::= EqualityExpr
4612 * | AndExpr 'and' EqualityExpr
4613 *
4614 * Parse and evaluate an AND expression, then push the result on the stack
4615 *
4616 */
4617void
4618xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
4619 xmlXPathEvalEqualityExpr(ctxt);
4620 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004621 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00004622 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004623 xmlXPathObjectPtr arg1, arg2;
4624
4625 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004626 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004627 xmlXPathEvalEqualityExpr(ctxt);
4628 CHECK_ERROR;
4629 arg2 = valuePop(ctxt);
4630 arg1 = valuePop(ctxt);
4631 arg1->boolval &= arg2->boolval;
4632 valuePush(ctxt, arg1);
4633 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004634 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004635 }
4636}
4637
4638/**
4639 * xmlXPathEvalExpr:
4640 * @ctxt: the XPath Parser context
4641 *
4642 * [14] Expr ::= OrExpr
4643 * [21] OrExpr ::= AndExpr
4644 * | OrExpr 'or' AndExpr
4645 *
4646 * Parse and evaluate an expression, then push the result on the stack
4647 *
4648 */
4649void
4650xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
4651 xmlXPathEvalAndExpr(ctxt);
4652 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004653 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004654 while ((CUR == 'o') && (NXT(1) == 'r')) {
4655 xmlXPathObjectPtr arg1, arg2;
4656
4657 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004658 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004659 xmlXPathEvalAndExpr(ctxt);
4660 CHECK_ERROR;
4661 arg2 = valuePop(ctxt);
4662 arg1 = valuePop(ctxt);
4663 arg1->boolval |= arg2->boolval;
4664 valuePush(ctxt, arg1);
4665 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004666 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004667 }
4668}
4669
4670/**
4671 * xmlXPathEvaluatePredicateResult:
4672 * @ctxt: the XPath Parser context
4673 * @res: the Predicate Expression evaluation result
4674 * @index: index of the current node in the current list
4675 *
4676 * Evaluate a predicate result for the current node.
4677 * A PredicateExpr is evaluated by evaluating the Expr and converting
4678 * the result to a boolean. If the result is a number, the result will
4679 * be converted to true if the number is equal to the position of the
4680 * context node in the context node list (as returned by the position
4681 * function) and will be converted to false otherwise; if the result
4682 * is not a number, then the result will be converted as if by a call
4683 * to the boolean function.
4684 */
4685int
4686xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004687 xmlXPathObjectPtr res) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004688 if (res == NULL) return(0);
4689 switch (res->type) {
4690 case XPATH_BOOLEAN:
4691 return(res->boolval);
4692 case XPATH_NUMBER:
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004693 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004694 case XPATH_NODESET:
4695 return(res->nodesetval->nodeNr != 0);
4696 case XPATH_STRING:
4697 return((res->stringval != NULL) &&
4698 (xmlStrlen(res->stringval) != 0));
4699 default:
4700 STRANGE
4701 }
4702 return(0);
4703}
4704
4705/**
4706 * xmlXPathEvalPredicate:
4707 * @ctxt: the XPath Parser context
4708 *
4709 * [8] Predicate ::= '[' PredicateExpr ']'
4710 * [9] PredicateExpr ::= Expr
4711 *
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004712 * ---------------------
4713 * For each node in the node-set to be filtered, the PredicateExpr is
4714 * evaluated with that node as the context node, with the number of nodes
4715 * in the node-set as the context size, and with the proximity position
4716 * of the node in the node-set with respect to the axis as the context
4717 * position; if PredicateExpr evaluates to true for that node, the node
4718 * is included in the new node-set; otherwise, it is not included.
4719 * ---------------------
4720 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004721 * Parse and evaluate a predicate for all the elements of the
4722 * current node list. Then refine the list by removing all
4723 * nodes where the predicate is false.
4724 */
4725void
4726xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004727 const xmlChar *cur;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004728 xmlXPathObjectPtr res;
Daniel Veillard740abf52000-10-02 23:04:54 +00004729 xmlXPathObjectPtr obj, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004730 xmlNodeSetPtr newset = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004731 xmlNodeSetPtr oldset;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004732 int i;
4733
Daniel Veillard00fdf371999-10-08 09:40:39 +00004734 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004735 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004736 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004737 }
4738 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004739 SKIP_BLANKS;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004740
4741 /*
4742 * Extract the old set, and then evaluate the result of the
4743 * expression for all the element in the set. use it to grow
4744 * up a new set.
4745 */
Daniel Veillard740abf52000-10-02 23:04:54 +00004746 CHECK_TYPE(XPATH_NODESET);
4747 obj = valuePop(ctxt);
4748 oldset = obj->nodesetval;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004749 ctxt->context->node = NULL;
4750
4751 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004752 ctxt->context->contextSize = 0;
4753 ctxt->context->proximityPosition = 0;
Daniel Veillardff9c3302000-10-13 16:38:25 +00004754 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004755 res = valuePop(ctxt);
4756 if (res != NULL)
4757 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00004758 valuePush(ctxt, obj);
Daniel Veillardff9c3302000-10-13 16:38:25 +00004759 CHECK_ERROR;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004760 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004761 /*
4762 * Save the expression pointer since we will have to evaluate
4763 * it multiple times. Initialize the new set.
4764 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004765 cur = ctxt->cur;
4766 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00004767
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004768 for (i = 0; i < oldset->nodeNr; i++) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004769 ctxt->cur = cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00004770
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004771 /*
4772 * Run the evaluation with a node list made of a single item
4773 * in the nodeset.
4774 */
4775 ctxt->context->node = oldset->nodeTab[i];
Daniel Veillard740abf52000-10-02 23:04:54 +00004776 tmp = xmlXPathNewNodeSet(ctxt->context->node);
4777 valuePush(ctxt, tmp);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004778 ctxt->context->contextSize = oldset->nodeNr;
4779 ctxt->context->proximityPosition = i + 1;
Daniel Veillardbe803962000-06-28 23:40:59 +00004780
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004781 xmlXPathEvalExpr(ctxt);
4782 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004783
4784 /*
4785 * The result of the evaluation need to be tested to
4786 * decided whether the filter succeeded or not
4787 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004788 res = valuePop(ctxt);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004789 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
4790 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
4791 }
Daniel Veillard740abf52000-10-02 23:04:54 +00004792
4793 /*
4794 * Cleanup
4795 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004796 if (res != NULL)
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004797 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00004798 if (ctxt->value == tmp) {
4799 res = valuePop(ctxt);
4800 xmlXPathFreeObject(res);
4801 }
Daniel Veillardbe803962000-06-28 23:40:59 +00004802
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004803 ctxt->context->node = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004804 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004805
4806 /*
4807 * The result is used as the new evaluation set.
4808 */
Daniel Veillard740abf52000-10-02 23:04:54 +00004809 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004810 ctxt->context->node = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004811 ctxt->context->contextSize = -1;
4812 ctxt->context->proximityPosition = -1;
Daniel Veillard740abf52000-10-02 23:04:54 +00004813 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004814 }
4815 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004816 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004817 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00004818
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004819 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004820 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004821#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004822 xmlGenericError(xmlGenericErrorContext, "After predicate : ");
4823 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
4824 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004825#endif
4826}
4827
4828/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00004829 * xmlXPathEvalNodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004830 * @ctxt: the XPath Parser context
Daniel Veillard55b91f22000-10-05 16:30:11 +00004831 * @test: pointer to a xmlXPathTestVal
4832 * @type: pointer to a xmlXPathTypeVal
4833 * @prefix: placeholder for a possible name prefix
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004834 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00004835 * [7] NodeTest ::= NameTest
4836 * | NodeType '(' ')'
4837 * | 'processing-instruction' '(' Literal ')'
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004838 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00004839 * [37] NameTest ::= '*'
4840 * | NCName ':' '*'
4841 * | QName
4842 * [38] NodeType ::= 'comment'
4843 * | 'text'
4844 * | 'processing-instruction'
4845 * | 'node'
4846 *
4847 * Returns the name found and update @test, @type and @prefix appropriately
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004848 */
Daniel Veillard55b91f22000-10-05 16:30:11 +00004849xmlChar *
4850xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
4851 xmlXPathTypeVal *type, xmlChar **prefix, xmlChar *name) {
4852 int blanks;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004853
Daniel Veillard55b91f22000-10-05 16:30:11 +00004854 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
4855 STRANGE;
4856 return(NULL);
4857 }
4858 *type = 0;
4859 *test = 0;
4860 *prefix = NULL;
4861 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004862
Daniel Veillard55b91f22000-10-05 16:30:11 +00004863 if ((name == NULL) && (CUR == '*')) {
4864 /*
4865 * All elements
4866 */
4867 NEXT;
4868 *test = NODE_TEST_ALL;
4869 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004870 }
4871
Daniel Veillard55b91f22000-10-05 16:30:11 +00004872 if (name == NULL)
4873 name = xmlXPathParseNCName(ctxt);
4874 if (name == NULL) {
4875 XP_ERROR0(XPATH_EXPR_ERROR);
4876 }
4877
4878 blanks = IS_BLANK(CUR);
4879 SKIP_BLANKS;
4880 if (CUR == '(') {
4881 NEXT;
4882 /*
4883 * NodeType or PI search
4884 */
4885 if (xmlStrEqual(name, BAD_CAST "comment"))
4886 *type = NODE_TYPE_COMMENT;
4887 else if (xmlStrEqual(name, BAD_CAST "node"))
4888 *type = NODE_TYPE_NODE;
4889 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4890 *type = NODE_TYPE_PI;
4891 else if (xmlStrEqual(name, BAD_CAST "text"))
4892 *type = NODE_TYPE_TEXT;
4893 else
4894 XP_ERROR0(XPATH_EXPR_ERROR);
4895
4896 *test = NODE_TEST_TYPE;
4897
4898 SKIP_BLANKS;
4899 if (*type == NODE_TYPE_PI) {
4900 /*
4901 * Specific case: search a PI by name.
4902 */
4903 xmlXPathObjectPtr cur;
4904
4905 if (name != NULL)
4906 xmlFree(name);
4907
4908 xmlXPathEvalLiteral(ctxt);
4909 CHECK_ERROR 0;
4910 xmlXPathStringFunction(ctxt, 1);
4911 CHECK_ERROR0;
4912 cur = valuePop(ctxt);
4913 name = xmlStrdup(cur->stringval);
4914 xmlXPathFreeObject(cur);
4915 SKIP_BLANKS;
4916 }
4917 if (CUR != ')')
4918 XP_ERROR0(XPATH_UNCLOSED_ERROR);
4919 NEXT;
4920 return(name);
4921 }
4922 *test = NODE_TEST_NAME;
4923 if ((!blanks) && (CUR == ':')) {
4924 NEXT;
4925
4926 *prefix = name;
4927
4928 if (CUR == '*') {
4929 /*
4930 * All elements
4931 */
4932 NEXT;
4933 *test = NODE_TEST_ALL;
4934 return(NULL);
4935 }
4936
4937 name = xmlXPathParseNCName(ctxt);
4938 if (name == NULL) {
4939 XP_ERROR0(XPATH_EXPR_ERROR);
4940 }
4941 }
4942 return(name);
4943}
4944
4945/**
4946 * xmlXPathIsAxisName:
4947 * @name: a preparsed name token
4948 *
4949 * [6] AxisName ::= 'ancestor'
4950 * | 'ancestor-or-self'
4951 * | 'attribute'
4952 * | 'child'
4953 * | 'descendant'
4954 * | 'descendant-or-self'
4955 * | 'following'
4956 * | 'following-sibling'
4957 * | 'namespace'
4958 * | 'parent'
4959 * | 'preceding'
4960 * | 'preceding-sibling'
4961 * | 'self'
4962 *
4963 * Returns the axis or 0
4964 */
4965xmlXPathAxisVal
4966xmlXPathIsAxisName(const xmlChar *name) {
4967 xmlXPathAxisVal ret = 0;
4968 switch (name[0]) {
4969 case 'a':
4970 if (xmlStrEqual(name, BAD_CAST "ancestor"))
4971 ret = AXIS_ANCESTOR;
4972 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
4973 ret = AXIS_ANCESTOR_OR_SELF;
4974 if (xmlStrEqual(name, BAD_CAST "attribute"))
4975 ret = AXIS_ATTRIBUTE;
4976 break;
4977 case 'c':
4978 if (xmlStrEqual(name, BAD_CAST "child"))
4979 ret = AXIS_CHILD;
4980 break;
4981 case 'd':
4982 if (xmlStrEqual(name, BAD_CAST "descendant"))
4983 ret = AXIS_DESCENDANT;
4984 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
4985 ret = AXIS_DESCENDANT_OR_SELF;
4986 break;
4987 case 'f':
4988 if (xmlStrEqual(name, BAD_CAST "following"))
4989 ret = AXIS_FOLLOWING;
4990 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
4991 ret = AXIS_FOLLOWING_SIBLING;
4992 break;
4993 case 'n':
4994 if (xmlStrEqual(name, BAD_CAST "namespace"))
4995 ret = AXIS_NAMESPACE;
4996 break;
4997 case 'p':
4998 if (xmlStrEqual(name, BAD_CAST "parent"))
4999 ret = AXIS_PARENT;
5000 if (xmlStrEqual(name, BAD_CAST "preceding"))
5001 ret = AXIS_PRECEDING;
5002 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
5003 ret = AXIS_PRECEDING_SIBLING;
5004 break;
5005 case 's':
5006 if (xmlStrEqual(name, BAD_CAST "self"))
5007 ret = AXIS_SELF;
5008 break;
5009 }
5010 return(ret);
5011}
5012
5013/**
5014 * xmlXPathEvalAxisSpecifier:
5015 * @ctxt: the XPath Parser context
5016 *
5017 *
5018 * Returns the axis found
5019 */
5020xmlXPathAxisVal
5021xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
5022 xmlXPathAxisVal ret = AXIS_CHILD;
5023 int blank = 0;
5024 xmlChar *name;
5025
5026 if (CUR == '@') {
5027 NEXT;
5028 return(AXIS_ATTRIBUTE);
5029 } else {
5030 name = xmlXPathParseNCName(ctxt);
5031 if (name == NULL) {
5032 XP_ERROR0(XPATH_EXPR_ERROR);
5033 }
5034 if (IS_BLANK(CUR))
5035 blank = 1;
5036 SKIP_BLANKS;
5037 if ((CUR == ':') && (NXT(1) == ':')) {
5038 ret = xmlXPathIsAxisName(name);
5039 } else if ((blank) && (CUR == ':'))
5040 XP_ERROR0(XPATH_EXPR_ERROR);
5041
5042 xmlFree(name);
5043 }
5044 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005045}
5046
5047/**
5048 * xmlXPathEvalStep:
5049 * @ctxt: the XPath Parser context
5050 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005051 * [4] Step ::= AxisSpecifier NodeTest Predicate*
5052 * | AbbreviatedStep
Daniel Veillardac260302000-10-04 13:33:43 +00005053 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005054 * [12] AbbreviatedStep ::= '.' | '..'
5055 *
5056 * [5] AxisSpecifier ::= AxisName '::'
5057 * | AbbreviatedAxisSpecifier
5058 *
5059 * [13] AbbreviatedAxisSpecifier ::= '@'?
Daniel Veillardac260302000-10-04 13:33:43 +00005060 *
5061 * Modified for XPtr range support as:
5062 *
5063 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5064 * | AbbreviatedStep
5065 * | 'range-to' '(' Expr ')' Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005066 *
5067 * Evaluate one step in a Location Path
5068 * A location step of . is short for self::node(). This is
5069 * particularly useful in conjunction with //. For example, the
5070 * location path .//para is short for
5071 * self::node()/descendant-or-self::node()/child::para
5072 * and so will select all para descendant elements of the context
5073 * node.
5074 * Similarly, a location step of .. is short for parent::node().
5075 * For example, ../title is short for parent::node()/child::title
5076 * and so will select the title children of the parent of the context
5077 * node.
5078 */
5079void
5080xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005081 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005082 if ((CUR == '.') && (NXT(1) == '.')) {
5083 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005084 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005085 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005086 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005087 } else if (CUR == '.') {
5088 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005089 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005090 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005091 xmlChar *name = NULL;
5092 xmlChar *prefix = NULL;
5093 xmlXPathTestVal test;
5094 xmlXPathAxisVal axis;
5095 xmlXPathTypeVal type;
5096
5097 /*
5098 * The modification needed for XPointer change to the production
5099 */
Daniel Veillardac260302000-10-04 13:33:43 +00005100#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard55b91f22000-10-05 16:30:11 +00005101 if (ctxt->context->xptr) {
5102 name = xmlXPathParseNCName(ctxt);
5103 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
5104 xmlFree(name);
5105 SKIP_BLANKS;
5106 if (CUR != '(') {
5107 XP_ERROR(XPATH_EXPR_ERROR);
5108 }
5109 NEXT;
5110 SKIP_BLANKS;
Daniel Veillardac260302000-10-04 13:33:43 +00005111
Daniel Veillard55b91f22000-10-05 16:30:11 +00005112 xmlXPtrRangeToFunction(ctxt, 1);
Daniel Veillardac260302000-10-04 13:33:43 +00005113 CHECK_ERROR;
5114
Daniel Veillard55b91f22000-10-05 16:30:11 +00005115 SKIP_BLANKS;
5116 if (CUR != ')') {
5117 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardac260302000-10-04 13:33:43 +00005118 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005119 NEXT;
5120 goto eval_predicates;
Daniel Veillardac260302000-10-04 13:33:43 +00005121 }
Daniel Veillardac260302000-10-04 13:33:43 +00005122 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005123#endif
5124 if (name == NULL)
5125 name = xmlXPathParseNCName(ctxt);
5126 if (name != NULL) {
5127 axis = xmlXPathIsAxisName(name);
5128 if (axis != 0) {
5129 SKIP_BLANKS;
5130 if ((CUR == ':') && (NXT(1) == ':')) {
5131 SKIP(2);
5132 xmlFree(name);
5133 name = NULL;
5134 } else {
5135 /* an element name can conflict with an axis one :-\ */
5136 axis = AXIS_CHILD;
5137 }
5138 } else {
5139 axis = AXIS_CHILD;
5140 }
5141 } else if (CUR == '@') {
5142 NEXT;
5143 axis = AXIS_ATTRIBUTE;
5144 } else {
5145 axis = AXIS_CHILD;
5146 }
5147
5148 CHECK_ERROR;
5149
5150 name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
5151 if (test == 0)
5152 return;
5153
5154#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005155 xmlGenericError(xmlGenericErrorContext,
5156 "Basis : computing new set\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005157#endif
5158 xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
5159#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005160 xmlGenericError(xmlGenericErrorContext, "Basis : ");
5161 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005162#endif
5163 if (name != NULL)
5164 xmlFree(name);
5165 if (prefix != NULL)
5166 xmlFree(prefix);
5167
5168eval_predicates:
Daniel Veillard00fdf371999-10-08 09:40:39 +00005169 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005170 while (CUR == '[') {
5171 xmlXPathEvalPredicate(ctxt);
5172 }
5173 }
5174#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005175 xmlGenericError(xmlGenericErrorContext, "Step : ");
5176 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5177 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005178#endif
5179}
5180
5181/**
5182 * xmlXPathEvalRelativeLocationPath:
5183 * @ctxt: the XPath Parser context
5184 *
5185 * [3] RelativeLocationPath ::= Step
5186 * | RelativeLocationPath '/' Step
5187 * | AbbreviatedRelativeLocationPath
5188 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
5189 *
5190 */
5191void
5192xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005193 SKIP_BLANKS;
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00005194 if ((CUR == '/') && (NXT(1) == '/')) {
5195 SKIP(2);
5196 SKIP_BLANKS;
5197 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
5198 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
5199 } else if (CUR == '/') {
5200 NEXT;
5201 SKIP_BLANKS;
5202 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005203 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005204 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005205 while (CUR == '/') {
5206 if ((CUR == '/') && (NXT(1) == '/')) {
5207 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005208 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005209 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005210 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005211 xmlXPathEvalStep(ctxt);
5212 } else if (CUR == '/') {
5213 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005214 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005215 xmlXPathEvalStep(ctxt);
5216 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005217 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005218 }
5219}
5220
5221/**
5222 * xmlXPathEvalLocationPath:
5223 * @ctxt: the XPath Parser context
5224 *
5225 * [1] LocationPath ::= RelativeLocationPath
5226 * | AbsoluteLocationPath
5227 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
5228 * | AbbreviatedAbsoluteLocationPath
5229 * [10] AbbreviatedAbsoluteLocationPath ::=
5230 * '//' RelativeLocationPath
5231 *
5232 * // is short for /descendant-or-self::node()/. For example,
5233 * //para is short for /descendant-or-self::node()/child::para and
5234 * so will select any para element in the document (even a para element
5235 * that is a document element will be selected by //para since the
5236 * document element node is a child of the root node); div//para is
5237 * short for div/descendant-or-self::node()/child::para and so will
5238 * select all para descendants of div children.
5239 */
5240void
5241xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005242 SKIP_BLANKS;
5243 if (CUR != '/') {
5244 xmlXPathEvalRelativeLocationPath(ctxt);
5245 } else {
5246 while (CUR == '/') {
5247 if ((CUR == '/') && (NXT(1) == '/')) {
5248 SKIP(2);
5249 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005250 xmlXPathNodeCollectAndTest(ctxt,
Daniel Veillard00fdf371999-10-08 09:40:39 +00005251 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
5252 XML_ELEMENT_NODE, NULL, NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00005253 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005254 } else if (CUR == '/') {
5255 NEXT;
5256 SKIP_BLANKS;
5257 xmlXPathRoot(ctxt);
5258 if (CUR != 0)
5259 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005260 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005261 }
5262 }
5263}
5264
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005265/**
5266 * xmlXPathEval:
5267 * @str: the XPath expression
Daniel Veillard740abf52000-10-02 23:04:54 +00005268 * @ctx: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005269 *
5270 * Evaluate the XPath Location Path in the given context.
5271 *
5272 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
5273 * the caller has to free the object.
5274 */
5275xmlXPathObjectPtr
Daniel Veillard740abf52000-10-02 23:04:54 +00005276xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
5277 xmlXPathParserContextPtr ctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005278 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005279 xmlXPathObjectPtr init = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005280 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005281
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005282 xmlXPathInit();
5283
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00005284 CHECK_CONTEXT(ctx)
5285
Daniel Veillard740abf52000-10-02 23:04:54 +00005286 ctxt = xmlXPathNewParserContext(str, ctx);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005287 if (ctx->node != NULL) {
5288 init = xmlXPathNewNodeSet(ctx->node);
5289 valuePush(ctxt, init);
5290 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005291 if (str[0] == '/')
Daniel Veillard55b91f22000-10-05 16:30:11 +00005292 xmlXPathRoot(ctxt);
5293 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005294
Daniel Veillard740abf52000-10-02 23:04:54 +00005295 if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005296 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard740abf52000-10-02 23:04:54 +00005297 "xmlXPathEval: evaluation failed to return a node set\n");
5298 } else {
5299 res = valuePop(ctxt);
5300 }
5301
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005302 do {
Daniel Veillard740abf52000-10-02 23:04:54 +00005303 tmp = valuePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005304 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00005305 xmlXPathFreeObject(tmp);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005306 if (tmp != init)
5307 stack++;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005308 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005309 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005310 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005311 xmlGenericError(xmlGenericErrorContext,
5312 "xmlXPathEval: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005313 stack);
5314 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005315 if (ctxt->error != XPATH_EXPRESSION_OK) {
5316 xmlXPathFreeObject(res);
5317 res = NULL;
5318 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005319
Daniel Veillard740abf52000-10-02 23:04:54 +00005320 xmlXPathFreeParserContext(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005321 return(res);
5322}
5323
5324/**
5325 * xmlXPathEvalExpression:
5326 * @str: the XPath expression
5327 * @ctxt: the XPath context
5328 *
5329 * Evaluate the XPath expression in the given context.
5330 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00005331 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005332 * the caller has to free the object.
5333 */
5334xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005335xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005336 xmlXPathParserContextPtr pctxt;
5337 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005338 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005339
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005340 xmlXPathInit();
5341
Daniel Veillard740abf52000-10-02 23:04:54 +00005342 CHECK_CONTEXT(ctxt)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005343
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005344 pctxt = xmlXPathNewParserContext(str, ctxt);
5345 xmlXPathEvalExpr(pctxt);
5346
5347 res = valuePop(pctxt);
5348 do {
5349 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005350 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00005351 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005352 stack++;
5353 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005354 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005355 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005356 xmlGenericError(xmlGenericErrorContext,
5357 "xmlXPathEvalExpression: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00005358 stack);
5359 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005360 xmlXPathFreeParserContext(pctxt);
5361 return(res);
5362}
5363
Daniel Veillard52afe802000-10-22 16:56:02 +00005364void
5365xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
5366{
5367 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
5368 xmlXPathBooleanFunction);
5369 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
5370 xmlXPathCeilingFunction);
5371 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
5372 xmlXPathCountFunction);
5373 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
5374 xmlXPathConcatFunction);
5375 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
5376 xmlXPathContainsFunction);
5377 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
5378 xmlXPathIdFunction);
5379 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
5380 xmlXPathFalseFunction);
5381 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
5382 xmlXPathFloorFunction);
5383 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
5384 xmlXPathLastFunction);
5385 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
5386 xmlXPathLangFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00005387 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
5388 xmlXPathLocalNameFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00005389 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
5390 xmlXPathNotFunction);
5391 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
5392 xmlXPathNameFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00005393 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
5394 xmlXPathNamespaceURIFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00005395 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
5396 xmlXPathNormalizeFunction);
5397 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize",
5398 xmlXPathNormalizeFunction);
5399 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
5400 xmlXPathNumberFunction);
5401 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
5402 xmlXPathPositionFunction);
5403 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
5404 xmlXPathRoundFunction);
5405 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
5406 xmlXPathStringFunction);
5407 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
5408 xmlXPathStringLengthFunction);
5409 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
5410 xmlXPathStartsWithFunction);
5411 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
5412 xmlXPathSubstringFunction);
5413 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
5414 xmlXPathSubstringBeforeFunction);
5415 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
5416 xmlXPathSubstringAfterFunction);
5417 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
5418 xmlXPathSumFunction);
5419 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
5420 xmlXPathTrueFunction);
5421 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
5422 xmlXPathTranslateFunction);
5423}
5424
Daniel Veillard361d8452000-04-03 19:48:13 +00005425#endif /* LIBXML_XPATH_ENABLED */