blob: fde7c3ba2edcf70adbbfeae31656eb356e5f8be9 [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
Daniel Veillardce6e98d2000-11-25 09:54:49 +000014 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
Daniel Veillard1566d3a1999-07-15 14:24:29 +000017 */
18
Daniel Veillard7f7d1111999-09-22 09:46:25 +000019#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000020#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000021#else
22#include "config.h"
23#endif
24
Daniel Veillardb71379b2000-10-09 12:30:39 +000025#include <libxml/xmlversion.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000026#ifdef LIBXML_XPATH_ENABLED
27
Daniel Veillard7f7d1111999-09-22 09:46:25 +000028#include <stdio.h>
29#include <string.h>
30
31#ifdef HAVE_SYS_TYPES_H
32#include <sys/types.h>
33#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000034#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000035#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000036#endif
Daniel Veillardf17e09b2001-01-25 13:55:35 +000037#ifdef HAVE_FLOAT_H
Daniel Veillardb05deb71999-08-10 19:04:08 +000038#include <float.h>
39#endif
40#ifdef HAVE_IEEEFP_H
41#include <ieeefp.h>
42#endif
43#ifdef HAVE_NAN_H
44#include <nan.h>
45#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000046#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000047#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000048#endif
49
Daniel Veillard361d8452000-04-03 19:48:13 +000050#include <libxml/xmlmemory.h>
51#include <libxml/tree.h>
52#include <libxml/valid.h>
53#include <libxml/xpath.h>
Daniel Veillard29a11cc2000-10-25 13:32:39 +000054#include <libxml/xpathInternals.h>
Daniel Veillard361d8452000-04-03 19:48:13 +000055#include <libxml/parserInternals.h>
Daniel Veillard52afe802000-10-22 16:56:02 +000056#include <libxml/hash.h>
Daniel Veillardac260302000-10-04 13:33:43 +000057#ifdef LIBXML_XPTR_ENABLED
58#include <libxml/xpointer.h>
59#endif
Daniel Veillardc2df4cd2000-10-12 23:15:24 +000060#ifdef LIBXML_DEBUG_ENABLED
61#include <libxml/debugXML.h>
62#endif
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +000063#include <libxml/xmlerror.h>
Daniel Veillard1566d3a1999-07-15 14:24:29 +000064
Daniel Veillarddbfd6411999-12-28 16:35:14 +000065/* #define DEBUG */
66/* #define DEBUG_STEP */
67/* #define DEBUG_EXPR */
68
Daniel Veillardc2df4cd2000-10-12 23:15:24 +000069void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
70double xmlXPathStringEvalNumber(const xmlChar *str);
71
Daniel Veillard1566d3a1999-07-15 14:24:29 +000072/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000073 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000074 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000075 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000076double xmlXPathNAN = 0;
77double xmlXPathPINF = 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +000078double xmlXPathNINF = -1;
Daniel Veillarde2d034d1999-07-27 19:52:06 +000079
Daniel Veillardb05deb71999-08-10 19:04:08 +000080#ifndef isinf
81#ifndef HAVE_ISINF
82
83#if HAVE_FPCLASS
84
85int isinf(double d) {
86 fpclass_t type = fpclass(d);
87 switch (type) {
88 case FP_NINF:
89 return(-1);
90 case FP_PINF:
91 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000092 }
93 return(0);
94}
95
96#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
97
98#if HAVE_FP_CLASS_H
99#include <fp_class.h>
100#endif
101
102int isinf(double d) {
103#if HAVE_FP_CLASS
104 int fpclass = fp_class(d);
105#else
106 int fpclass = fp_class_d(d);
107#endif
108 if (fpclass == FP_POS_INF)
109 return(1);
110 if (fpclass == FP_NEG_INF)
111 return(-1);
112 return(0);
113}
114
115#elif defined(HAVE_CLASS)
116
117int isinf(double d) {
118 int fpclass = class(d);
119 if (fpclass == FP_PLUS_INF)
120 return(1);
121 if (fpclass == FP_MINUS_INF)
122 return(-1);
123 return(0);
124}
125#elif defined(finite) || defined(HAVE_FINITE)
126int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000127#elif defined(HUGE_VAL)
Daniel Veillardfc708e22000-04-08 13:17:27 +0000128int isinf(double x)
Daniel Veillard991e63d1999-08-15 23:32:28 +0000129{
130 if (x == HUGE_VAL)
131 return(1);
132 if (x == -HUGE_VAL)
133 return(-1);
134 return(0);
135}
136#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000137
138#endif /* ! HAVE_ISINF */
139#endif /* ! defined(isinf) */
140
141#ifndef isnan
142#ifndef HAVE_ISNAN
143
144#ifdef HAVE_ISNAND
145#define isnan(f) isnand(f)
146#endif /* HAVE_iSNAND */
147
148#endif /* ! HAVE_iSNAN */
149#endif /* ! defined(isnan) */
150
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000151/**
152 * xmlXPathInit:
153 *
154 * Initialize the XPath environment
155 */
156void
157xmlXPathInit(void) {
158 static int initialized = 0;
159
160 if (initialized) return;
161
162 xmlXPathNAN = 0;
163 xmlXPathNAN /= 0;
164
165 xmlXPathPINF = 1;
166 xmlXPathPINF /= 0;
167
Daniel Veillardf6bf9212000-10-26 14:07:44 +0000168 xmlXPathNINF = -1;
169 xmlXPathNINF /= 0;
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000170
171 initialized = 1;
172}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000173
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000174/************************************************************************
175 * *
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000176 * Debugging related functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000177 * *
178 ************************************************************************/
179
Daniel Veillard7e99c632000-10-06 12:59:53 +0000180#define TODO \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000181 xmlGenericError(xmlGenericErrorContext, \
182 "Unimplemented block at %s:%d\n", \
Daniel Veillard7e99c632000-10-06 12:59:53 +0000183 __FILE__, __LINE__);
184
185#define STRANGE \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000186 xmlGenericError(xmlGenericErrorContext, \
187 "Internal error at %s:%d\n", \
Daniel Veillard7e99c632000-10-06 12:59:53 +0000188 __FILE__, __LINE__);
189
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000190#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000191void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
192 int i;
193 char shift[100];
194
195 for (i = 0;((i < depth) && (i < 25));i++)
196 shift[2 * i] = shift[2 * i + 1] = ' ';
197 shift[2 * i] = shift[2 * i + 1] = 0;
198 if (cur == NULL) {
199 fprintf(output, shift);
200 fprintf(output, "Node is NULL !\n");
201 return;
202
203 }
204
205 if ((cur->type == XML_DOCUMENT_NODE) ||
206 (cur->type == XML_HTML_DOCUMENT_NODE)) {
207 fprintf(output, shift);
208 fprintf(output, " /\n");
209 } else if (cur->type == XML_ATTRIBUTE_NODE)
210 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
211 else
212 xmlDebugDumpOneNode(output, cur, depth);
213}
214
215void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
216 int i;
217 char shift[100];
218
219 for (i = 0;((i < depth) && (i < 25));i++)
220 shift[2 * i] = shift[2 * i + 1] = ' ';
221 shift[2 * i] = shift[2 * i + 1] = 0;
222
223 if (cur == NULL) {
224 fprintf(output, shift);
225 fprintf(output, "NodeSet is NULL !\n");
226 return;
227
228 }
229
230 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
231 for (i = 0;i < cur->nodeNr;i++) {
232 fprintf(output, shift);
233 fprintf(output, "%d", i + 1);
234 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
235 }
236}
237
238#if defined(LIBXML_XPTR_ENABLED)
239void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
240void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
241 int i;
242 char shift[100];
243
244 for (i = 0;((i < depth) && (i < 25));i++)
245 shift[2 * i] = shift[2 * i + 1] = ' ';
246 shift[2 * i] = shift[2 * i + 1] = 0;
247
248 if (cur == NULL) {
249 fprintf(output, shift);
250 fprintf(output, "LocationSet is NULL !\n");
251 return;
252
253 }
254
255 for (i = 0;i < cur->locNr;i++) {
256 fprintf(output, shift);
257 fprintf(output, "%d : ", i + 1);
258 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
259 }
260}
261#endif
262
263void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
264 int i;
265 char shift[100];
266
267 for (i = 0;((i < depth) && (i < 25));i++)
268 shift[2 * i] = shift[2 * i + 1] = ' ';
269 shift[2 * i] = shift[2 * i + 1] = 0;
270
271 fprintf(output, shift);
272
273 if (cur == NULL) {
274 fprintf(output, "Object is empty (NULL)\n");
275 return;
276 }
277 switch(cur->type) {
278 case XPATH_UNDEFINED:
279 fprintf(output, "Object is uninitialized\n");
280 break;
281 case XPATH_NODESET:
282 fprintf(output, "Object is a Node Set :\n");
283 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
284 break;
Daniel Veillarde4566462001-01-22 09:58:39 +0000285 case XPATH_XSLT_TREE:
286 fprintf(output, "Object is an XSLT value tree :\n");
287 xmlXPathDebugDumpNode(output, cur->user, depth);
288 break;
Daniel Veillardc2df4cd2000-10-12 23:15:24 +0000289 case XPATH_BOOLEAN:
290 fprintf(output, "Object is a Boolean : ");
291 if (cur->boolval) fprintf(output, "true\n");
292 else fprintf(output, "false\n");
293 break;
294 case XPATH_NUMBER:
295 fprintf(output, "Object is a number : %0g\n", cur->floatval);
296 break;
297 case XPATH_STRING:
298 fprintf(output, "Object is a string : ");
299 xmlDebugDumpString(output, cur->stringval);
300 fprintf(output, "\n");
301 break;
302 case XPATH_POINT:
303 fprintf(output, "Object is a point : index %d in node", cur->index);
304 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
305 fprintf(output, "\n");
306 break;
307 case XPATH_RANGE:
308 if ((cur->user2 == NULL) ||
309 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
310 fprintf(output, "Object is a collapsed range :\n");
311 fprintf(output, shift);
312 if (cur->index >= 0)
313 fprintf(output, "index %d in ", cur->index);
314 fprintf(output, "node\n");
315 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
316 depth + 1);
317 } else {
318 fprintf(output, "Object is a range :\n");
319 fprintf(output, shift);
320 fprintf(output, "From ");
321 if (cur->index >= 0)
322 fprintf(output, "index %d in ", cur->index);
323 fprintf(output, "node\n");
324 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
325 depth + 1);
326 fprintf(output, shift);
327 fprintf(output, "To ");
328 if (cur->index2 >= 0)
329 fprintf(output, "index %d in ", cur->index2);
330 fprintf(output, "node\n");
331 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
332 depth + 1);
333 fprintf(output, "\n");
334 }
335 break;
336 case XPATH_LOCATIONSET:
337#if defined(LIBXML_XPTR_ENABLED)
338 fprintf(output, "Object is a Location Set:\n");
339 xmlXPathDebugDumpLocationSet(output,
340 (xmlLocationSetPtr) cur->user, depth);
341#endif
342 break;
343 case XPATH_USERS:
344 fprintf(output, "Object is user defined\n");
345 break;
346 }
347}
348#endif
349
350/************************************************************************
351 * *
352 * Parser stacks related functions and macros *
353 * *
354 ************************************************************************/
355
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000356/*
357 * Generic function for accessing stacks in the Parser Context
358 */
359
360#define PUSH_AND_POP(type, name) \
361extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
362 if (ctxt->name##Nr >= ctxt->name##Max) { \
363 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000364 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000365 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
366 if (ctxt->name##Tab == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000367 xmlGenericError(xmlGenericErrorContext, \
368 "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000369 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000370 } \
371 } \
372 ctxt->name##Tab[ctxt->name##Nr] = value; \
373 ctxt->name = value; \
374 return(ctxt->name##Nr++); \
375} \
376extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
377 type ret; \
378 if (ctxt->name##Nr <= 0) return(0); \
379 ctxt->name##Nr--; \
380 if (ctxt->name##Nr > 0) \
381 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
382 else \
383 ctxt->name = NULL; \
384 ret = ctxt->name##Tab[ctxt->name##Nr]; \
385 ctxt->name##Tab[ctxt->name##Nr] = 0; \
386 return(ret); \
387} \
388
389PUSH_AND_POP(xmlXPathObjectPtr, value)
390
391/*
392 * Macros for accessing the content. Those should be used only by the parser,
393 * and not exported.
394 *
395 * Dirty macros, i.e. one need to make assumption on the context to use them
396 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000397 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000398 * CUR returns the current xmlChar value, i.e. a 8 bit value
399 * in ISO-Latin or UTF-8.
400 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000401 * only to compare to ASCII values otherwise it would break when
402 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000403 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000404 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000405 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000406 * strings within the parser.
407 * CURRENT Returns the current char value, with the full decoding of
408 * UTF-8 if we are using this mode. It returns an int.
409 * NEXT Skip to the next character, this does the proper decoding
410 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000411 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000412 */
413
414#define CUR (*ctxt->cur)
415#define SKIP(val) ctxt->cur += (val)
416#define NXT(val) ctxt->cur[(val)]
417#define CUR_PTR ctxt->cur
418
419#define SKIP_BLANKS \
420 while (IS_BLANK(*(ctxt->cur))) NEXT
421
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000422#define CURRENT (*ctxt->cur)
423#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000424
425/************************************************************************
426 * *
427 * Error handling routines *
428 * *
429 ************************************************************************/
430
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000431
432const char *xmlXPathErrorMessages[] = {
433 "Ok",
434 "Number encoding",
435 "Unfinished litteral",
436 "Start of litteral",
437 "Expected $ for variable reference",
438 "Undefined variable",
439 "Invalid predicate",
440 "Invalid expression",
441 "Missing closing curly brace",
442 "Unregistered function",
443 "Invalid operand",
444 "Invalid type",
445 "Invalid number of arguments",
Daniel Veillardf09e7e32000-10-01 15:53:30 +0000446 "Invalid context size",
447 "Invalid context position",
Daniel Veillardb71379b2000-10-09 12:30:39 +0000448 "Memory allocation error",
449 "Syntax error",
450 "Resource error",
Daniel Veillarda6d8eb62000-12-27 10:46:47 +0000451 "Sub resource error",
452 "Undefined namespace prefix"
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000453};
454
455/**
456 * xmlXPathError:
457 * @ctxt: the XPath Parser context
458 * @file: the file name
459 * @line: the line number
460 * @no: the error number
461 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000462 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000463 *
464 * Returns the newly created object.
465 */
466void
467xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
468 int line, int no) {
469 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000470 const xmlChar *cur;
471 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000472
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000473 xmlGenericError(xmlGenericErrorContext,
474 "Error %s:%d: %s\n", file, line,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000475 xmlXPathErrorMessages[no]);
476
477 cur = ctxt->cur;
478 base = ctxt->base;
479 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
480 cur--;
481 }
482 n = 0;
483 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
484 cur--;
485 if ((*cur == '\n') || (*cur == '\r')) cur++;
486 base = cur;
487 n = 0;
488 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000489 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000490 n++;
491 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000492 xmlGenericError(xmlGenericErrorContext, "\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000493 cur = ctxt->cur;
494 while ((*cur == '\n') || (*cur == '\r'))
495 cur--;
496 n = 0;
497 while ((cur != base) && (n++ < 80)) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000498 xmlGenericError(xmlGenericErrorContext, " ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000499 base++;
500 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000501 xmlGenericError(xmlGenericErrorContext,"^\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000502}
503
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000504
505/************************************************************************
506 * *
507 * Routines to handle NodeSets *
508 * *
509 ************************************************************************/
510
Daniel Veillardf17e09b2001-01-25 13:55:35 +0000511/**
512 * xmlXPathCmpNodes:
513 * @node1: the first node
514 * @node2: the second node
515 *
516 * Compare two nodes w.r.t document order
517 *
518 * Returns -2 in case of error 1 if first point < second point, 0 if
Daniel Veillard2f913b72001-01-31 13:23:49 +0000519 * that's the same node, -1 otherwise
Daniel Veillardf17e09b2001-01-25 13:55:35 +0000520 */
521int
522xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
523 int depth1, depth2;
524 xmlNodePtr cur, root;
525
526 if ((node1 == NULL) || (node2 == NULL))
527 return(-2);
528 /*
529 * a couple of optimizations which will avoid computations in most cases
530 */
531 if (node1 == node2)
532 return(0);
533 if (node1 == node2->prev)
534 return(1);
535 if (node1 == node2->next)
536 return(-1);
537
538 /*
539 * compute depth to root
540 */
541 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
542 if (cur == node1)
543 return(1);
544 depth2++;
545 }
546 root = cur;
547 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
548 if (cur == node2)
549 return(-1);
550 depth1++;
551 }
552 /*
553 * Distinct document (or distinct entities :-( ) case.
554 */
555 if (root != cur) {
556 return(-2);
557 }
558 /*
559 * get the nearest common ancestor.
560 */
561 while (depth1 > depth2) {
562 depth1--;
563 node1 = node1->parent;
564 }
565 while (depth2 > depth1) {
566 depth2--;
567 node2 = node2->parent;
568 }
569 while (node1->parent != node2->parent) {
570 node1 = node1->parent;
571 node2 = node2->parent;
572 /* should not happen but just in case ... */
573 if ((node1 == NULL) || (node2 == NULL))
574 return(-2);
575 }
576 /*
577 * Find who's first.
578 */
579 if (node1 == node2->next)
580 return(-1);
581 for (cur = node1->next;cur != NULL;cur = cur->next)
582 if (cur == node2)
583 return(1);
584 return(-1); /* assume there is no sibling list corruption */
585}
586
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000587#define XML_NODESET_DEFAULT 10
588/**
589 * xmlXPathNodeSetCreate:
590 * @val: an initial xmlNodePtr, or NULL
591 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000592 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000593 *
594 * Returns the newly created object.
595 */
596xmlNodeSetPtr
597xmlXPathNodeSetCreate(xmlNodePtr val) {
598 xmlNodeSetPtr ret;
599
Daniel Veillard6454aec1999-09-02 22:04:43 +0000600 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000601 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000602 xmlGenericError(xmlGenericErrorContext,
603 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000604 return(NULL);
605 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000606 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000607 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000608 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000609 sizeof(xmlNodePtr));
610 if (ret->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000611 xmlGenericError(xmlGenericErrorContext,
612 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000613 return(NULL);
614 }
615 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000616 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000617 ret->nodeMax = XML_NODESET_DEFAULT;
618 ret->nodeTab[ret->nodeNr++] = val;
619 }
620 return(ret);
621}
622
623/**
624 * xmlXPathNodeSetAdd:
625 * @cur: the initial node set
626 * @val: a new xmlNodePtr
627 *
628 * add a new xmlNodePtr ot an existing NodeSet
629 */
630void
631xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
632 int i;
633
634 if (val == NULL) return;
635
636 /*
637 * check against doublons
638 */
639 for (i = 0;i < cur->nodeNr;i++)
640 if (cur->nodeTab[i] == val) return;
641
642 /*
643 * grow the nodeTab if needed
644 */
645 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000646 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000647 sizeof(xmlNodePtr));
648 if (cur->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000649 xmlGenericError(xmlGenericErrorContext,
650 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000651 return;
652 }
653 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000654 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000655 cur->nodeMax = XML_NODESET_DEFAULT;
656 } else if (cur->nodeNr == cur->nodeMax) {
657 xmlNodePtr *temp;
658
659 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000660 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000661 sizeof(xmlNodePtr));
662 if (temp == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000663 xmlGenericError(xmlGenericErrorContext,
664 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000665 return;
666 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000667 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000668 }
669 cur->nodeTab[cur->nodeNr++] = val;
670}
671
672/**
673 * xmlXPathNodeSetMerge:
Daniel Veillard2d38f042000-10-11 10:54:10 +0000674 * @val1: the first NodeSet or NULL
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000675 * @val2: the second NodeSet
676 *
677 * Merges two nodesets, all nodes from @val2 are added to @val1
Daniel Veillard2d38f042000-10-11 10:54:10 +0000678 * if @val1 is NULL, a new set is created and copied from @val2
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000679 *
680 * Returns val1 once extended or NULL in case of error.
681 */
682xmlNodeSetPtr
683xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000684 int i, j, initNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000685
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000686 if (val2 == NULL) return(val1);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000687 if (val1 == NULL) {
688 val1 = xmlXPathNodeSetCreate(NULL);
689 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000690
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000691 initNr = val1->nodeNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000692
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000693 for (i = 0;i < val2->nodeNr;i++) {
694 /*
695 * check against doublons
696 */
697 for (j = 0; j < initNr; j++)
698 if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
699
700 /*
701 * grow the nodeTab if needed
702 */
703 if (val1->nodeMax == 0) {
704 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
705 sizeof(xmlNodePtr));
706 if (val1->nodeTab == NULL) {
707 xmlGenericError(xmlGenericErrorContext,
708 "xmlXPathNodeSetMerge: out of memory\n");
709 return(NULL);
710 }
711 memset(val1->nodeTab, 0 ,
712 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
713 val1->nodeMax = XML_NODESET_DEFAULT;
714 } else if (val1->nodeNr == val1->nodeMax) {
715 xmlNodePtr *temp;
716
717 val1->nodeMax *= 2;
718 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
719 sizeof(xmlNodePtr));
720 if (temp == NULL) {
721 xmlGenericError(xmlGenericErrorContext,
722 "xmlXPathNodeSetMerge: out of memory\n");
723 return(NULL);
724 }
725 val1->nodeTab = temp;
726 }
727 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
728 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000729
730 return(val1);
731}
732
733/**
734 * xmlXPathNodeSetDel:
735 * @cur: the initial node set
736 * @val: an xmlNodePtr
737 *
738 * Removes an xmlNodePtr from an existing NodeSet
739 */
740void
741xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
742 int i;
743
744 if (cur == NULL) return;
745 if (val == NULL) return;
746
747 /*
748 * check against doublons
749 */
750 for (i = 0;i < cur->nodeNr;i++)
751 if (cur->nodeTab[i] == val) break;
752
753 if (i >= cur->nodeNr) {
754#ifdef DEBUG
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000755 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000756 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
757 val->name);
758#endif
759 return;
760 }
761 cur->nodeNr--;
762 for (;i < cur->nodeNr;i++)
763 cur->nodeTab[i] = cur->nodeTab[i + 1];
764 cur->nodeTab[cur->nodeNr] = NULL;
765}
766
767/**
768 * xmlXPathNodeSetRemove:
769 * @cur: the initial node set
770 * @val: the index to remove
771 *
772 * Removes an entry from an existing NodeSet list.
773 */
774void
775xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
776 if (cur == NULL) return;
777 if (val >= cur->nodeNr) return;
778 cur->nodeNr--;
779 for (;val < cur->nodeNr;val++)
780 cur->nodeTab[val] = cur->nodeTab[val + 1];
781 cur->nodeTab[cur->nodeNr] = NULL;
782}
783
784/**
785 * xmlXPathFreeNodeSet:
786 * @obj: the xmlNodeSetPtr to free
787 *
788 * Free the NodeSet compound (not the actual nodes !).
789 */
790void
791xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
792 if (obj == NULL) return;
793 if (obj->nodeTab != NULL) {
794#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000795 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000796#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000797 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000798 }
799#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000800 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000801#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000802 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000803}
804
Daniel Veillard8a7642f2001-01-22 10:45:16 +0000805/**
806 * xmlXPathFreeValueTree:
807 * @obj: the xmlNodeSetPtr to free
808 *
809 * Free the NodeSet compound and the actual tree, this is different
810 * from xmlXPathFreeNodeSet()
811 */
812void
813xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
814 int i;
815
816 if (obj == NULL) return;
817 for (i = 0;i < obj->nodeNr;i++)
818 if (obj->nodeTab[i] != NULL)
819 xmlFreeNode(obj->nodeTab[i]);
820
821 if (obj->nodeTab != NULL) {
822#ifdef DEBUG
823 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
824#endif
825 xmlFree(obj->nodeTab);
826 }
827#ifdef DEBUG
828 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
829#endif
830 xmlFree(obj);
831}
832
Daniel Veillardb96e6431999-08-29 21:02:19 +0000833#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000834/**
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000835 * xmlGenericErrorContextNodeSet:
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000836 * @output: a FILE * for the output
837 * @obj: the xmlNodeSetPtr to free
838 *
839 * Quick display of a NodeSet
840 */
841void
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000842xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000843 int i;
844
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000845 if (output == NULL) output = xmlGenericErrorContext;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000846 if (obj == NULL) {
847 fprintf(output, "NodeSet == NULL !\n");
848 return;
849 }
850 if (obj->nodeNr == 0) {
851 fprintf(output, "NodeSet is empty\n");
852 return;
853 }
854 if (obj->nodeTab == NULL) {
855 fprintf(output, " nodeTab == NULL !\n");
856 return;
857 }
858 for (i = 0; i < obj->nodeNr; i++) {
859 if (obj->nodeTab[i] == NULL) {
860 fprintf(output, " NULL !\n");
861 return;
862 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000863 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
864 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000865 fprintf(output, " /");
866 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000867 fprintf(output, " noname!");
868 else fprintf(output, " %s", obj->nodeTab[i]->name);
869 }
870 fprintf(output, "\n");
871}
872#endif
873
Daniel Veillard7e99c632000-10-06 12:59:53 +0000874/**
875 * xmlXPathNewNodeSet:
876 * @val: the NodePtr value
877 *
878 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
879 * it with the single Node @val
880 *
881 * Returns the newly created object.
882 */
883xmlXPathObjectPtr
884xmlXPathNewNodeSet(xmlNodePtr val) {
885 xmlXPathObjectPtr ret;
886
887 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
888 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000889 xmlGenericError(xmlGenericErrorContext,
890 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000891 return(NULL);
892 }
893 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
894 ret->type = XPATH_NODESET;
895 ret->nodesetval = xmlXPathNodeSetCreate(val);
896 return(ret);
897}
898
899/**
Daniel Veillarde4566462001-01-22 09:58:39 +0000900 * xmlXPathNewValueTree:
901 * @val: the NodePtr value
902 *
903 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
904 * it with the tree root @val
905 *
906 * Returns the newly created object.
907 */
908xmlXPathObjectPtr
909xmlXPathNewValueTree(xmlNodePtr val) {
910 xmlXPathObjectPtr ret;
911
912 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
913 if (ret == NULL) {
914 xmlGenericError(xmlGenericErrorContext,
915 "xmlXPathNewNodeSet: out of memory\n");
916 return(NULL);
917 }
918 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
919 ret->type = XPATH_XSLT_TREE;
920 ret->nodesetval = xmlXPathNodeSetCreate(val);
921 return(ret);
922}
923
924/**
Daniel Veillard7e99c632000-10-06 12:59:53 +0000925 * xmlXPathNewNodeSetList:
926 * @val: an existing NodeSet
927 *
928 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
929 * it with the Nodeset @val
930 *
931 * Returns the newly created object.
932 */
933xmlXPathObjectPtr
934xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
935 xmlXPathObjectPtr ret;
936 int i;
937
938 if (val == NULL)
939 ret = NULL;
940 else if (val->nodeTab == NULL)
941 ret = xmlXPathNewNodeSet(NULL);
942 else
943 {
944 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
945 for (i = 1; i < val->nodeNr; ++i)
946 xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
947 }
948
949 return(ret);
950}
951
952/**
953 * xmlXPathWrapNodeSet:
954 * @val: the NodePtr value
955 *
956 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
957 *
958 * Returns the newly created object.
959 */
960xmlXPathObjectPtr
961xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
962 xmlXPathObjectPtr ret;
963
964 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
965 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000966 xmlGenericError(xmlGenericErrorContext,
967 "xmlXPathWrapNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000968 return(NULL);
969 }
970 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
971 ret->type = XPATH_NODESET;
972 ret->nodesetval = val;
973 return(ret);
974}
975
976/**
977 * xmlXPathFreeNodeSetList:
978 * @obj: an existing NodeSetList object
979 *
980 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
981 * the list contrary to xmlXPathFreeObject().
982 */
983void
984xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
985 if (obj == NULL) return;
986#ifdef DEBUG
987 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
988#endif
989 xmlFree(obj);
990}
991
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000992/************************************************************************
993 * *
Daniel Veillard2d38f042000-10-11 10:54:10 +0000994 * Routines to handle extra functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000995 * *
996 ************************************************************************/
997
998/**
Daniel Veillard2d38f042000-10-11 10:54:10 +0000999 * xmlXPathRegisterFunc:
1000 * @ctxt: the XPath context
1001 * @name: the function name
1002 * @f: the function implementation or NULL
1003 *
1004 * Register a new function. If @f is NULL it unregisters the function
1005 *
1006 * Returns 0 in case of success, -1 in case of error
1007 */
1008int
1009xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1010 xmlXPathFunction f) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001011 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1012}
1013
1014/**
1015 * xmlXPathRegisterFuncNS:
1016 * @ctxt: the XPath context
1017 * @name: the function name
1018 * @ns_uri: the function namespace URI
1019 * @f: the function implementation or NULL
1020 *
1021 * Register a new function. If @f is NULL it unregisters the function
1022 *
1023 * Returns 0 in case of success, -1 in case of error
1024 */
1025int
1026xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1027 const xmlChar *ns_uri, xmlXPathFunction f) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001028 if (ctxt == NULL)
1029 return(-1);
1030 if (name == NULL)
1031 return(-1);
1032
Daniel Veillard52afe802000-10-22 16:56:02 +00001033 if (ctxt->funcHash == NULL)
1034 ctxt->funcHash = xmlHashCreate(0);
1035 if (ctxt->funcHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +00001036 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001037 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001038}
1039
1040/**
1041 * xmlXPathFunctionLookup:
1042 * @ctxt: the XPath context
1043 * @name: the function name
1044 *
1045 * Search in the Function array of the context for the given
1046 * function.
1047 *
1048 * Returns the xmlXPathFunction or NULL if not found
1049 */
1050xmlXPathFunction
1051xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001052 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1053}
1054
1055/**
1056 * xmlXPathFunctionLookupNS:
1057 * @ctxt: the XPath context
1058 * @name: the function name
1059 * @ns_uri: the function namespace URI
1060 *
1061 * Search in the Function array of the context for the given
1062 * function.
1063 *
1064 * Returns the xmlXPathFunction or NULL if not found
1065 */
1066xmlXPathFunction
1067xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1068 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001069 if (ctxt == NULL)
1070 return(NULL);
Daniel Veillard52afe802000-10-22 16:56:02 +00001071 if (ctxt->funcHash == NULL)
1072 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001073 if (name == NULL)
1074 return(NULL);
1075
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001076 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001077}
1078
1079/**
1080 * xmlXPathRegisteredFuncsCleanup:
1081 * @ctxt: the XPath context
1082 *
1083 * Cleanup the XPath context data associated to registered functions
1084 */
1085void
1086xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001087 if (ctxt == NULL)
1088 return;
1089
Daniel Veillard52afe802000-10-22 16:56:02 +00001090 xmlHashFree(ctxt->funcHash, NULL);
1091 ctxt->funcHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001092}
1093
1094/************************************************************************
1095 * *
1096 * Routines to handle Variable *
1097 * *
1098 ************************************************************************/
1099
1100/**
1101 * xmlXPathRegisterVariable:
1102 * @ctxt: the XPath context
1103 * @name: the variable name
1104 * @value: the variable value or NULL
1105 *
1106 * Register a new variable value. If @value is NULL it unregisters
1107 * the variable
1108 *
1109 * Returns 0 in case of success, -1 in case of error
1110 */
1111int
1112xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1113 xmlXPathObjectPtr value) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001114 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1115}
1116
1117/**
1118 * xmlXPathRegisterVariableNS:
1119 * @ctxt: the XPath context
1120 * @name: the variable name
1121 * @ns_uri: the variable namespace URI
1122 * @value: the variable value or NULL
1123 *
1124 * Register a new variable value. If @value is NULL it unregisters
1125 * the variable
1126 *
1127 * Returns 0 in case of success, -1 in case of error
1128 */
1129int
1130xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1131 const xmlChar *ns_uri,
1132 xmlXPathObjectPtr value) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001133 if (ctxt == NULL)
1134 return(-1);
1135 if (name == NULL)
1136 return(-1);
1137
Daniel Veillard126f2792000-10-24 17:10:12 +00001138 if (ctxt->varHash == NULL)
1139 ctxt->varHash = xmlHashCreate(0);
1140 if (ctxt->varHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +00001141 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001142 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1143 (void *) value,
1144 (xmlHashDeallocator)xmlXPathFreeObject));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001145}
1146
1147/**
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001148 * xmlXPathRegisterVariableLookup:
1149 * @ctxt: the XPath context
1150 * @f: the lookup function
1151 * @data: the lookup data
1152 *
1153 * register an external mechanism to do variable lookup
1154 */
1155void
1156xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1157 xmlXPathVariableLookupFunc f, void *data) {
1158 if (ctxt == NULL)
1159 return;
1160 ctxt->varLookupFunc = (void *) f;
1161 ctxt->varLookupData = data;
1162}
1163
1164/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001165 * xmlXPathVariableLookup:
1166 * @ctxt: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001167 * @name: the variable name
1168 *
1169 * Search in the Variable array of the context for the given
1170 * variable value.
1171 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001172 * Returns the value or NULL if not found
1173 */
1174xmlXPathObjectPtr
Daniel Veillard2d38f042000-10-11 10:54:10 +00001175xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001176 if (ctxt == NULL)
1177 return(NULL);
1178
1179 if (ctxt->varLookupFunc != NULL) {
1180 xmlXPathObjectPtr ret;
1181
1182 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1183 (ctxt->varLookupData, name, NULL);
1184 if (ret != NULL) return(ret);
1185 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001186 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1187}
1188
1189/**
1190 * xmlXPathVariableLookupNS:
1191 * @ctxt: the XPath context
1192 * @name: the variable name
1193 * @ns_uri: the variable namespace URI
1194 *
1195 * Search in the Variable array of the context for the given
1196 * variable value.
1197 *
1198 * Returns the value or NULL if not found
1199 */
1200xmlXPathObjectPtr
1201xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1202 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001203 if (ctxt == NULL)
1204 return(NULL);
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001205
1206 if (ctxt->varLookupFunc != NULL) {
1207 xmlXPathObjectPtr ret;
1208
1209 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1210 (ctxt->varLookupData, name, ns_uri);
1211 if (ret != NULL) return(ret);
1212 }
1213
Daniel Veillard126f2792000-10-24 17:10:12 +00001214 if (ctxt->varHash == NULL)
1215 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001216 if (name == NULL)
1217 return(NULL);
1218
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001219 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001220}
1221
Daniel Veillard2d38f042000-10-11 10:54:10 +00001222/**
1223 * xmlXPathRegisteredVariablesCleanup:
1224 * @ctxt: the XPath context
1225 *
1226 * Cleanup the XPath context data associated to registered variables
1227 */
1228void
1229xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001230 if (ctxt == NULL)
1231 return;
1232
Daniel Veillard126f2792000-10-24 17:10:12 +00001233 xmlHashFree(ctxt->varHash, NULL);
1234 ctxt->varHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001235}
1236
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001237/**
1238 * xmlXPathRegisterNs:
1239 * @ctxt: the XPath context
1240 * @prefix: the namespace prefix
1241 * @ns_uri: the namespace name
1242 *
1243 * Register a new namespace. If @ns_uri is NULL it unregisters
1244 * the namespace
1245 *
1246 * Returns 0 in case of success, -1 in case of error
1247 */
1248int
1249xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1250 const xmlChar *ns_uri) {
1251 if (ctxt == NULL)
1252 return(-1);
1253 if (prefix == NULL)
1254 return(-1);
1255
1256 if (ctxt->nsHash == NULL)
1257 ctxt->nsHash = xmlHashCreate(10);
1258 if (ctxt->nsHash == NULL)
1259 return(-1);
1260 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1261 (xmlHashDeallocator)xmlFree));
1262}
1263
1264/**
1265 * xmlXPathNsLookup:
1266 * @ctxt: the XPath context
1267 * @prefix: the namespace prefix value
1268 *
1269 * Search in the namespace declaration array of the context for the given
1270 * namespace name associated to the given prefix
1271 *
1272 * Returns the value or NULL if not found
1273 */
1274const xmlChar *
1275xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1276 if (ctxt == NULL)
1277 return(NULL);
1278 if (prefix == NULL)
1279 return(NULL);
1280 if (ctxt->nsHash == NULL)
1281 return(NULL);
1282
1283 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1284}
1285
1286/**
1287 * xmlXPathRegisteredVariablesCleanup:
1288 * @ctxt: the XPath context
1289 *
1290 * Cleanup the XPath context data associated to registered variables
1291 */
1292void
1293xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1294 if (ctxt == NULL)
1295 return;
1296
1297 xmlHashFree(ctxt->nsHash, NULL);
1298 ctxt->nsHash = NULL;
1299}
1300
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001301/************************************************************************
1302 * *
1303 * Routines to handle Values *
1304 * *
1305 ************************************************************************/
1306
1307/* Allocations are terrible, one need to optimize all this !!! */
1308
1309/**
1310 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001311 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001312 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001313 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001314 *
1315 * Returns the newly created object.
1316 */
1317xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001318xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001319 xmlXPathObjectPtr ret;
1320
Daniel Veillard6454aec1999-09-02 22:04:43 +00001321 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001322 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001323 xmlGenericError(xmlGenericErrorContext,
1324 "xmlXPathNewFloat: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001325 return(NULL);
1326 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001327 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001328 ret->type = XPATH_NUMBER;
1329 ret->floatval = val;
1330 return(ret);
1331}
1332
1333/**
1334 * xmlXPathNewBoolean:
1335 * @val: the boolean value
1336 *
1337 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1338 *
1339 * Returns the newly created object.
1340 */
1341xmlXPathObjectPtr
1342xmlXPathNewBoolean(int val) {
1343 xmlXPathObjectPtr ret;
1344
Daniel Veillard6454aec1999-09-02 22:04:43 +00001345 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001346 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001347 xmlGenericError(xmlGenericErrorContext,
1348 "xmlXPathNewBoolean: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001349 return(NULL);
1350 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001351 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001352 ret->type = XPATH_BOOLEAN;
1353 ret->boolval = (val != 0);
1354 return(ret);
1355}
1356
1357/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001358 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001359 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001360 *
1361 * Create a new xmlXPathObjectPtr of type string and of value @val
1362 *
1363 * Returns the newly created object.
1364 */
1365xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001366xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001367 xmlXPathObjectPtr ret;
1368
Daniel Veillard6454aec1999-09-02 22:04:43 +00001369 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001370 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001371 xmlGenericError(xmlGenericErrorContext,
1372 "xmlXPathNewString: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001373 return(NULL);
1374 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001375 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001376 ret->type = XPATH_STRING;
Daniel Veillard5a2b6972001-01-20 21:15:50 +00001377 if (val != NULL)
1378 ret->stringval = xmlStrdup(val);
1379 else
1380 ret->stringval = xmlStrdup((const xmlChar *)"");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001381 return(ret);
1382}
1383
1384/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001385 * xmlXPathNewCString:
1386 * @val: the char * value
1387 *
1388 * Create a new xmlXPathObjectPtr of type string and of value @val
1389 *
1390 * Returns the newly created object.
1391 */
1392xmlXPathObjectPtr
1393xmlXPathNewCString(const char *val) {
1394 xmlXPathObjectPtr ret;
1395
Daniel Veillard6454aec1999-09-02 22:04:43 +00001396 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001397 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001398 xmlGenericError(xmlGenericErrorContext,
1399 "xmlXPathNewCString: out of memory\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001400 return(NULL);
1401 }
1402 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1403 ret->type = XPATH_STRING;
1404 ret->stringval = xmlStrdup(BAD_CAST val);
1405 return(ret);
1406}
1407
1408/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001409 * xmlXPathObjectCopy:
1410 * @val: the original object
1411 *
1412 * allocate a new copy of a given object
1413 *
1414 * Returns the newly created object.
1415 */
1416xmlXPathObjectPtr
1417xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1418 xmlXPathObjectPtr ret;
1419
1420 if (val == NULL)
1421 return(NULL);
1422
1423 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1424 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001425 xmlGenericError(xmlGenericErrorContext,
1426 "xmlXPathObjectCopy: out of memory\n");
Daniel Veillard2d38f042000-10-11 10:54:10 +00001427 return(NULL);
1428 }
1429 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1430 switch (val->type) {
1431 case XPATH_BOOLEAN:
1432 case XPATH_NUMBER:
Daniel Veillard2d38f042000-10-11 10:54:10 +00001433 case XPATH_POINT:
1434 case XPATH_RANGE:
1435 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00001436 case XPATH_STRING:
1437 ret->stringval = xmlStrdup(val->stringval);
Daniel Veillarde99a4762001-02-01 04:34:35 +00001438 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00001439 case XPATH_XSLT_TREE:
Daniel Veillard8a7642f2001-01-22 10:45:16 +00001440 if ((val->nodesetval != NULL) &&
1441 (val->nodesetval->nodeTab != NULL))
1442 ret->nodesetval = xmlXPathNodeSetCreate(
1443 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
1444 else
1445 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
1446 break;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001447 case XPATH_NODESET:
1448 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1449 break;
1450 case XPATH_LOCATIONSET:
1451#ifdef LIBXML_XPTR_ENABLED
1452 {
1453 xmlLocationSetPtr loc = val->user;
1454 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1455 break;
1456 }
1457#endif
1458 case XPATH_UNDEFINED:
1459 case XPATH_USERS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001460 xmlGenericError(xmlGenericErrorContext,
1461 "xmlXPathObjectCopy: unsupported type %d\n",
Daniel Veillard2d38f042000-10-11 10:54:10 +00001462 val->type);
Daniel Veillarde4566462001-01-22 09:58:39 +00001463 break;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001464 }
1465 return(ret);
1466}
1467
1468/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001469 * xmlXPathFreeObject:
1470 * @obj: the object to free
1471 *
1472 * Free up an xmlXPathObjectPtr object.
1473 */
1474void
1475xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1476 if (obj == NULL) return;
Daniel Veillardac260302000-10-04 13:33:43 +00001477 if (obj->type == XPATH_NODESET) {
1478 if (obj->nodesetval != NULL)
1479 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001480#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard7e99c632000-10-06 12:59:53 +00001481 } else if (obj->type == XPATH_LOCATIONSET) {
1482 if (obj->user != NULL)
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00001483 xmlXPtrFreeLocationSet(obj->user);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001484#endif
Daniel Veillardac260302000-10-04 13:33:43 +00001485 } else if (obj->type == XPATH_STRING) {
1486 if (obj->stringval != NULL)
1487 xmlFree(obj->stringval);
Daniel Veillarde4566462001-01-22 09:58:39 +00001488 } else if (obj->type == XPATH_XSLT_TREE) {
1489 if (obj->nodesetval != NULL)
Daniel Veillard8a7642f2001-01-22 10:45:16 +00001490 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillardac260302000-10-04 13:33:43 +00001491 }
1492
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001493#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001494 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001495#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001496 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001497}
1498
1499/************************************************************************
1500 * *
1501 * Routines to handle XPath contexts *
1502 * *
1503 ************************************************************************/
1504
1505/**
1506 * xmlXPathNewContext:
1507 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001508 *
1509 * Create a new xmlXPathContext
1510 *
1511 * Returns the xmlXPathContext just allocated.
1512 */
1513xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001514xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001515 xmlXPathContextPtr ret;
1516
Daniel Veillard6454aec1999-09-02 22:04:43 +00001517 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001518 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001519 xmlGenericError(xmlGenericErrorContext,
1520 "xmlXPathNewContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001521 return(NULL);
1522 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001523 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001524 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001525 ret->node = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001526
Daniel Veillard126f2792000-10-24 17:10:12 +00001527 ret->varHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001528
1529 ret->nb_types = 0;
1530 ret->max_types = 0;
1531 ret->types = NULL;
1532
Daniel Veillard52afe802000-10-22 16:56:02 +00001533 ret->funcHash = xmlHashCreate(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001534
1535 ret->nb_axis = 0;
1536 ret->max_axis = 0;
1537 ret->axis = NULL;
1538
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001539 ret->nsHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001540 ret->user = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001541
1542 ret->contextSize = -1;
1543 ret->proximityPosition = -1;
Daniel Veillard52afe802000-10-22 16:56:02 +00001544
1545 xmlXPathRegisterAllFunctions(ret);
1546
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001547 return(ret);
1548}
1549
1550/**
1551 * xmlXPathFreeContext:
1552 * @ctxt: the context to free
1553 *
1554 * Free up an xmlXPathContext
1555 */
1556void
1557xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001558 xmlXPathRegisteredNsCleanup(ctxt);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001559 xmlXPathRegisteredFuncsCleanup(ctxt);
1560 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001561#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001562 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001563#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001564 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001565}
1566
1567/************************************************************************
1568 * *
1569 * Routines to handle XPath parser contexts *
1570 * *
1571 ************************************************************************/
1572
Daniel Veillard740abf52000-10-02 23:04:54 +00001573#define CHECK_CTXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001574 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001575 xmlGenericError(xmlGenericErrorContext, \
1576 "%s:%d Internal error: ctxt == NULL\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001577 __FILE__, __LINE__); \
1578 } \
1579
1580
Daniel Veillard740abf52000-10-02 23:04:54 +00001581#define CHECK_CONTEXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001582 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001583 xmlGenericError(xmlGenericErrorContext, \
1584 "%s:%d Internal error: no context\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001585 __FILE__, __LINE__); \
1586 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001587 else if (ctxt->doc == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001588 xmlGenericError(xmlGenericErrorContext, \
1589 "%s:%d Internal error: no document\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001590 __FILE__, __LINE__); \
1591 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001592 else if (ctxt->doc->children == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001593 xmlGenericError(xmlGenericErrorContext, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001594 "%s:%d Internal error: document without root\n", \
1595 __FILE__, __LINE__); \
1596 } \
1597
1598
1599/**
1600 * xmlXPathNewParserContext:
1601 * @str: the XPath expression
1602 * @ctxt: the XPath context
1603 *
1604 * Create a new xmlXPathParserContext
1605 *
1606 * Returns the xmlXPathParserContext just allocated.
1607 */
1608xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001609xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001610 xmlXPathParserContextPtr ret;
1611
Daniel Veillard6454aec1999-09-02 22:04:43 +00001612 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001613 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001614 xmlGenericError(xmlGenericErrorContext,
1615 "xmlXPathNewParserContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001616 return(NULL);
1617 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001618 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001619 ret->cur = ret->base = str;
1620 ret->context = ctxt;
1621
1622 /* Allocate the value stack */
1623 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001624 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001625 ret->valueNr = 0;
1626 ret->valueMax = 10;
1627 ret->value = NULL;
1628 return(ret);
1629}
1630
1631/**
1632 * xmlXPathFreeParserContext:
1633 * @ctxt: the context to free
1634 *
1635 * Free up an xmlXPathParserContext
1636 */
1637void
1638xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1639 if (ctxt->valueTab != NULL) {
1640#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001641 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001642#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001643 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001644 }
1645#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001646 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001647#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001648 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001649}
1650
1651/************************************************************************
1652 * *
1653 * The implicit core function library *
1654 * *
1655 ************************************************************************/
1656
1657/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001658 * Auto-pop and cast to a number
1659 */
1660void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1661
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001662
1663#define POP_FLOAT \
1664 arg = valuePop(ctxt); \
1665 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001666 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001667 } \
1668 if (arg->type != XPATH_NUMBER) { \
1669 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001670 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001671 arg = valuePop(ctxt); \
1672 }
1673
1674/**
Daniel Veillard389e6b72001-01-15 19:41:13 +00001675 * xmlXPathCompareNodeSetFloat:
1676 * @ctxt: the XPath Parser context
1677 * @inf: less than (1) or greater than (0)
1678 * @strict: is the comparison strict
1679 * @arg: the node set
1680 * @f: the value
1681 *
1682 * Implement the compare operation between a nodeset and a number
1683 * @ns < @val (1, 1, ...
1684 * @ns <= @val (1, 0, ...
1685 * @ns > @val (0, 1, ...
1686 * @ns >= @val (0, 0, ...
1687 *
1688 * If one object to be compared is a node-set and the other is a number,
1689 * then the comparison will be true if and only if there is a node in the
1690 * node-set such that the result of performing the comparison on the number
1691 * to be compared and on the result of converting the string-value of that
1692 * node to a number using the number function is true.
1693 *
1694 * Returns 0 or 1 depending on the results of the test.
1695 */
1696int
1697xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
1698 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
1699 int i, ret = 0;
1700 xmlNodeSetPtr ns;
1701 xmlChar *str2;
1702
Daniel Veillarde99a4762001-02-01 04:34:35 +00001703 if ((f == NULL) || (arg == NULL) ||
1704 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00001705 xmlXPathFreeObject(arg);
1706 xmlXPathFreeObject(f);
1707 return(0);
1708 }
1709 ns = arg->nodesetval;
1710 for (i = 0;i < ns->nodeNr;i++) {
1711 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1712 if (str2 != NULL) {
1713 valuePush(ctxt,
1714 xmlXPathNewString(str2));
1715 xmlFree(str2);
1716 xmlXPathNumberFunction(ctxt, 1);
1717 valuePush(ctxt, xmlXPathObjectCopy(f));
1718 ret = xmlXPathCompareValues(ctxt, inf, strict);
1719 if (ret)
1720 break;
1721 }
1722 }
1723 xmlXPathFreeObject(arg);
1724 xmlXPathFreeObject(f);
1725 return(ret);
1726}
1727
1728/**
1729 * xmlXPathCompareNodeSetString:
1730 * @ctxt: the XPath Parser context
1731 * @inf: less than (1) or greater than (0)
1732 * @strict: is the comparison strict
1733 * @arg: the node set
1734 * @s: the value
1735 *
1736 * Implement the compare operation between a nodeset and a string
1737 * @ns < @val (1, 1, ...
1738 * @ns <= @val (1, 0, ...
1739 * @ns > @val (0, 1, ...
1740 * @ns >= @val (0, 0, ...
1741 *
1742 * If one object to be compared is a node-set and the other is a string,
1743 * then the comparison will be true if and only if there is a node in
1744 * the node-set such that the result of performing the comparison on the
1745 * string-value of the node and the other string is true.
1746 *
1747 * Returns 0 or 1 depending on the results of the test.
1748 */
1749int
1750xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
1751 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
1752 int i, ret = 0;
1753 xmlNodeSetPtr ns;
1754 xmlChar *str2;
1755
Daniel Veillarde99a4762001-02-01 04:34:35 +00001756 if ((s == NULL) || (arg == NULL) ||
1757 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00001758 xmlXPathFreeObject(arg);
1759 xmlXPathFreeObject(s);
1760 return(0);
1761 }
1762 ns = arg->nodesetval;
1763 for (i = 0;i < ns->nodeNr;i++) {
1764 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1765 if (str2 != NULL) {
1766 valuePush(ctxt,
1767 xmlXPathNewString(str2));
1768 xmlFree(str2);
1769 valuePush(ctxt, xmlXPathObjectCopy(s));
1770 ret = xmlXPathCompareValues(ctxt, inf, strict);
1771 if (ret)
1772 break;
1773 }
1774 }
1775 xmlXPathFreeObject(arg);
1776 xmlXPathFreeObject(s);
1777 return(ret);
1778}
1779
1780/**
1781 * xmlXPathCompareNodeSets:
1782 * @ctxt: the XPath Parser context
1783 * @op: less than (-1), equal (0) or greater than (1)
1784 * @strict: is the comparison strict
1785 * @ns1: the fist node set
1786 * @ns2: the second node set
1787 *
1788 * Implement the compare operation on nodesets:
1789 *
1790 * If both objects to be compared are node-sets, then the comparison will be true if
1791 * and only if there is a node in the first node-set and a node in the second node-set
1792 * such that the result of performing the comparison on the string-values of the two
1793 * nodes is true.
1794 */
1795int
1796xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
1797 xmlXPathObjectPtr ns1, xmlXPathObjectPtr ns2) {
1798 TODO
1799 return(0);
1800}
1801
1802/**
1803 * xmlXPathCompareNodeSetValue:
1804 * @ctxt: the XPath Parser context
1805 * @inf: less than (1) or greater than (0)
1806 * @strict: is the comparison strict
1807 * @arg: the node set
1808 * @val: the value
1809 *
1810 * Implement the compare operation between a nodeset and a value
1811 * @ns < @val (1, 1, ...
1812 * @ns <= @val (1, 0, ...
1813 * @ns > @val (0, 1, ...
1814 * @ns >= @val (0, 0, ...
1815 *
1816 * If one object to be compared is a node-set and the other is a boolean, then the
1817 * comparison will be true if and only if the result of performing the comparison
1818 * on the boolean and on the result of converting the node-set to a boolean using
1819 * the boolean function is true.
1820 *
1821 * Returns 0 or 1 depending on the results of the test.
1822 */
1823int
1824xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
1825 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
Daniel Veillarde99a4762001-02-01 04:34:35 +00001826 if ((val == NULL) || (arg == NULL) ||
1827 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard389e6b72001-01-15 19:41:13 +00001828 return(0);
1829
1830 switch(val->type) {
1831 case XPATH_NUMBER:
1832 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
1833 case XPATH_NODESET:
Daniel Veillarde99a4762001-02-01 04:34:35 +00001834 case XPATH_XSLT_TREE:
Daniel Veillard389e6b72001-01-15 19:41:13 +00001835 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
1836 case XPATH_STRING:
1837 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
1838 case XPATH_BOOLEAN:
1839 valuePush(ctxt, arg);
1840 xmlXPathBooleanFunction(ctxt, 1);
1841 valuePush(ctxt, val);
1842 return(xmlXPathCompareValues(ctxt, inf, strict));
1843 default:
1844 TODO
1845 return(0);
1846 }
1847 return(0);
1848}
1849
1850/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001851 * xmlXPathEqualNodeSetString
1852 * @arg: the nodeset object argument
1853 * @str: the string to compare to.
1854 *
1855 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1856 * If one object to be compared is a node-set and the other is a string,
1857 * then the comparison will be true if and only if there is a node in
1858 * the node-set such that the result of performing the comparison on the
1859 * string-value of the node and the other string is true.
1860 *
1861 * Returns 0 or 1 depending on the results of the test.
1862 */
1863int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001864xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001865 int i;
1866 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001867 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001868
Daniel Veillarde99a4762001-02-01 04:34:35 +00001869 if ((str == NULL) || (arg == NULL) ||
1870 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001871 return(0);
1872 ns = arg->nodesetval;
1873 for (i = 0;i < ns->nodeNr;i++) {
1874 str2 = xmlNodeGetContent(ns->nodeTab[i]);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001875 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001876 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001877 return(1);
1878 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001879 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001880 }
1881 return(0);
1882}
1883
1884/**
1885 * xmlXPathEqualNodeSetFloat
1886 * @arg: the nodeset object argument
1887 * @f: the float to compare to
1888 *
1889 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1890 * If one object to be compared is a node-set and the other is a number,
1891 * then the comparison will be true if and only if there is a node in
1892 * the node-set such that the result of performing the comparison on the
1893 * number to be compared and on the result of converting the string-value
1894 * of that node to a number using the number function is true.
1895 *
1896 * Returns 0 or 1 depending on the results of the test.
1897 */
1898int
1899xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001900 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001901
Daniel Veillarde99a4762001-02-01 04:34:35 +00001902 if ((arg == NULL) ||
1903 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001904 return(0);
1905
1906 if (isnan(f))
1907 sprintf(buf, "NaN");
1908 else if (isinf(f) > 0)
1909 sprintf(buf, "+Infinity");
1910 else if (isinf(f) < 0)
1911 sprintf(buf, "-Infinity");
1912 else
1913 sprintf(buf, "%0g", f);
1914
Daniel Veillardb96e6431999-08-29 21:02:19 +00001915 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001916}
1917
1918
1919/**
1920 * xmlXPathEqualNodeSets
1921 * @arg1: first nodeset object argument
1922 * @arg2: second nodeset object argument
1923 *
1924 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1925 * If both objects to be compared are node-sets, then the comparison
1926 * will be true if and only if there is a node in the first node-set and
1927 * a node in the second node-set such that the result of performing the
1928 * comparison on the string-values of the two nodes is true.
1929 *
1930 * (needless to say, this is a costly operation)
1931 *
1932 * Returns 0 or 1 depending on the results of the test.
1933 */
1934int
1935xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1936 int i;
1937 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001938 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001939
Daniel Veillarde99a4762001-02-01 04:34:35 +00001940 if ((arg1 == NULL) ||
1941 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001942 return(0);
Daniel Veillarde99a4762001-02-01 04:34:35 +00001943 if ((arg2 == NULL) ||
1944 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001945 return(0);
1946
1947 ns = arg1->nodesetval;
1948 for (i = 0;i < ns->nodeNr;i++) {
1949 str = xmlNodeGetContent(ns->nodeTab[i]);
1950 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001951 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001952 return(1);
1953 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001954 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001955 }
1956 return(0);
1957}
1958
1959/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001960 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001961 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001962 *
1963 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1964 *
1965 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001966 */
1967int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001968xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1969 xmlXPathObjectPtr arg1, arg2;
1970 int ret = 0;
1971
1972 arg1 = valuePop(ctxt);
1973 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001974 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001975
1976 arg2 = valuePop(ctxt);
1977 if (arg2 == NULL) {
1978 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001979 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001980 }
1981
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001982 if (arg1 == arg2) {
1983#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001984 xmlGenericError(xmlGenericErrorContext,
1985 "Equal: by pointer\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001986#endif
1987 return(1);
1988 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001989
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001990 switch (arg1->type) {
1991 case XPATH_UNDEFINED:
1992#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001993 xmlGenericError(xmlGenericErrorContext,
1994 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001995#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001996 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00001997 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001998 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001999 switch (arg2->type) {
2000 case XPATH_UNDEFINED:
2001#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002002 xmlGenericError(xmlGenericErrorContext,
2003 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00002004#endif
2005 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00002006 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002007 case XPATH_NODESET:
2008 ret = xmlXPathEqualNodeSets(arg1, arg2);
2009 break;
2010 case XPATH_BOOLEAN:
2011 if ((arg1->nodesetval == NULL) ||
2012 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2013 else
2014 ret = 1;
2015 ret = (ret == arg2->boolval);
2016 break;
2017 case XPATH_NUMBER:
2018 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2019 break;
2020 case XPATH_STRING:
2021 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2022 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002023 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002024 case XPATH_POINT:
2025 case XPATH_RANGE:
2026 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002027 TODO
2028 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002029 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002030 break;
2031 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002032 switch (arg2->type) {
2033 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002034#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002035 xmlGenericError(xmlGenericErrorContext,
2036 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002037#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00002038 break;
2039 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002040 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002041 if ((arg2->nodesetval == NULL) ||
2042 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2043 else
2044 ret = 1;
2045 break;
2046 case XPATH_BOOLEAN:
2047#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002048 xmlGenericError(xmlGenericErrorContext,
2049 "Equal: %d boolean %d \n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00002050 arg1->boolval, arg2->boolval);
2051#endif
2052 ret = (arg1->boolval == arg2->boolval);
2053 break;
2054 case XPATH_NUMBER:
2055 if (arg2->floatval) ret = 1;
2056 else ret = 0;
2057 ret = (arg1->boolval == ret);
2058 break;
2059 case XPATH_STRING:
2060 if ((arg2->stringval == NULL) ||
2061 (arg2->stringval[0] == 0)) ret = 0;
2062 else
2063 ret = 1;
2064 ret = (arg1->boolval == ret);
2065 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002066 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002067 case XPATH_POINT:
2068 case XPATH_RANGE:
2069 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002070 TODO
2071 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002072 }
2073 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002074 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002075 switch (arg2->type) {
2076 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002077#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002078 xmlGenericError(xmlGenericErrorContext,
2079 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002080#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00002081 break;
2082 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002083 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002084 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2085 break;
2086 case XPATH_BOOLEAN:
2087 if (arg1->floatval) ret = 1;
2088 else ret = 0;
2089 ret = (arg2->boolval == ret);
2090 break;
2091 case XPATH_STRING:
2092 valuePush(ctxt, arg2);
2093 xmlXPathNumberFunction(ctxt, 1);
2094 arg2 = valuePop(ctxt);
2095 /* no break on purpose */
2096 case XPATH_NUMBER:
2097 ret = (arg1->floatval == arg2->floatval);
2098 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002099 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002100 case XPATH_POINT:
2101 case XPATH_RANGE:
2102 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002103 TODO
2104 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002105 }
2106 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002107 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002108 switch (arg2->type) {
2109 case XPATH_UNDEFINED:
2110#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002111 xmlGenericError(xmlGenericErrorContext,
2112 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00002113#endif
2114 break;
2115 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002116 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002117 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2118 break;
2119 case XPATH_BOOLEAN:
2120 if ((arg1->stringval == NULL) ||
2121 (arg1->stringval[0] == 0)) ret = 0;
2122 else
2123 ret = 1;
2124 ret = (arg2->boolval == ret);
2125 break;
2126 case XPATH_STRING:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002127 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002128 break;
2129 case XPATH_NUMBER:
2130 valuePush(ctxt, arg1);
2131 xmlXPathNumberFunction(ctxt, 1);
2132 arg1 = valuePop(ctxt);
2133 ret = (arg1->floatval == arg2->floatval);
2134 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002135 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002136 case XPATH_POINT:
2137 case XPATH_RANGE:
2138 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002139 TODO
2140 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002141 }
2142 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002143 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002144 case XPATH_POINT:
2145 case XPATH_RANGE:
2146 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002147 TODO
2148 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002149 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00002150 xmlXPathFreeObject(arg1);
2151 xmlXPathFreeObject(arg2);
2152 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002153}
2154
Daniel Veillard389e6b72001-01-15 19:41:13 +00002155
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002156/**
2157 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002158 * @ctxt: the XPath Parser context
Daniel Veillard389e6b72001-01-15 19:41:13 +00002159 * @inf: less than (1) or greater than (0)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002160 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002161 *
2162 * Implement the compare operation on XPath objects:
2163 * @arg1 < @arg2 (1, 1, ...
2164 * @arg1 <= @arg2 (1, 0, ...
2165 * @arg1 > @arg2 (0, 1, ...
2166 * @arg1 >= @arg2 (0, 0, ...
2167 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00002168 * When neither object to be compared is a node-set and the operator is
2169 * <=, <, >=, >, then the objects are compared by converted both objects
2170 * to numbers and comparing the numbers according to IEEE 754. The <
2171 * comparison will be true if and only if the first number is less than the
2172 * second number. The <= comparison will be true if and only if the first
2173 * number is less than or equal to the second number. The > comparison
2174 * will be true if and only if the first number is greater than the second
2175 * number. The >= comparison will be true if and only if the first number
2176 * is greater than or equal to the second number.
Daniel Veillard389e6b72001-01-15 19:41:13 +00002177 *
2178 * Returns 1 if the comparaison succeeded, 0 if it failed
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002179 */
2180int
Daniel Veillard991e63d1999-08-15 23:32:28 +00002181xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
2182 int ret = 0;
2183 xmlXPathObjectPtr arg1, arg2;
2184
2185 arg2 = valuePop(ctxt);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002186 if (arg2 == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002187 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002188 }
2189
2190 arg1 = valuePop(ctxt);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002191 if (arg1 == NULL) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00002192 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002193 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002194 }
2195
Daniel Veillard389e6b72001-01-15 19:41:13 +00002196 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
2197 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
2198 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
2199 } else {
2200 if (arg1->type == XPATH_NODESET) {
2201 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, arg1, arg2);
2202 } else {
2203 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, !strict, arg2, arg2);
2204 }
2205 }
2206 return(ret);
2207 }
2208
Daniel Veillard991e63d1999-08-15 23:32:28 +00002209 if (arg1->type != XPATH_NUMBER) {
2210 valuePush(ctxt, arg1);
2211 xmlXPathNumberFunction(ctxt, 1);
2212 arg1 = valuePop(ctxt);
2213 }
2214 if (arg1->type != XPATH_NUMBER) {
2215 xmlXPathFreeObject(arg1);
2216 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002217 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002218 }
2219 if (arg2->type != XPATH_NUMBER) {
2220 valuePush(ctxt, arg2);
2221 xmlXPathNumberFunction(ctxt, 1);
2222 arg2 = valuePop(ctxt);
2223 }
2224 if (arg2->type != XPATH_NUMBER) {
2225 xmlXPathFreeObject(arg1);
2226 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002227 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002228 }
2229 /*
2230 * Add tests for infinity and nan
2231 * => feedback on 3.4 for Inf and NaN
2232 */
2233 if (inf && strict)
2234 ret = (arg1->floatval < arg2->floatval);
2235 else if (inf && !strict)
2236 ret = (arg1->floatval <= arg2->floatval);
2237 else if (!inf && strict)
2238 ret = (arg1->floatval > arg2->floatval);
2239 else if (!inf && !strict)
2240 ret = (arg1->floatval >= arg2->floatval);
2241 xmlXPathFreeObject(arg1);
2242 xmlXPathFreeObject(arg2);
2243 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002244}
2245
2246/**
2247 * xmlXPathValueFlipSign:
2248 * @ctxt: the XPath Parser context
2249 *
2250 * Implement the unary - operation on an XPath object
2251 * The numeric operators convert their operands to numbers as if
2252 * by calling the number function.
2253 */
2254void
2255xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
2256 xmlXPathObjectPtr arg;
2257
2258 POP_FLOAT
2259 arg->floatval = -arg->floatval;
2260 valuePush(ctxt, arg);
2261}
2262
2263/**
2264 * xmlXPathAddValues:
2265 * @ctxt: the XPath Parser context
2266 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002267 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002268 * The numeric operators convert their operands to numbers as if
2269 * by calling the number function.
2270 */
2271void
2272xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
2273 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002274 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002275
2276 POP_FLOAT
2277 val = arg->floatval;
2278 xmlXPathFreeObject(arg);
2279
2280 POP_FLOAT
2281 arg->floatval += val;
2282 valuePush(ctxt, arg);
2283}
2284
2285/**
2286 * xmlXPathSubValues:
2287 * @ctxt: the XPath Parser context
2288 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002289 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002290 * The numeric operators convert their operands to numbers as if
2291 * by calling the number function.
2292 */
2293void
2294xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
2295 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002296 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002297
2298 POP_FLOAT
2299 val = arg->floatval;
2300 xmlXPathFreeObject(arg);
2301
2302 POP_FLOAT
2303 arg->floatval -= val;
2304 valuePush(ctxt, arg);
2305}
2306
2307/**
2308 * xmlXPathMultValues:
2309 * @ctxt: the XPath Parser context
2310 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002311 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002312 * The numeric operators convert their operands to numbers as if
2313 * by calling the number function.
2314 */
2315void
2316xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
2317 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002318 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002319
2320 POP_FLOAT
2321 val = arg->floatval;
2322 xmlXPathFreeObject(arg);
2323
2324 POP_FLOAT
2325 arg->floatval *= val;
2326 valuePush(ctxt, arg);
2327}
2328
2329/**
2330 * xmlXPathDivValues:
2331 * @ctxt: the XPath Parser context
2332 *
Daniel Veillard2b325a02001-01-31 20:46:31 +00002333 * Implement the div operation on XPath objects @arg1 / @arg2:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002334 * The numeric operators convert their operands to numbers as if
2335 * by calling the number function.
2336 */
2337void
2338xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
2339 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002340 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002341
2342 POP_FLOAT
2343 val = arg->floatval;
2344 xmlXPathFreeObject(arg);
2345
2346 POP_FLOAT
2347 arg->floatval /= val;
2348 valuePush(ctxt, arg);
2349}
2350
2351/**
2352 * xmlXPathModValues:
2353 * @ctxt: the XPath Parser context
2354 *
Daniel Veillard2b325a02001-01-31 20:46:31 +00002355 * Implement the mod operation on XPath objects: @arg1 / @arg2
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002356 * The numeric operators convert their operands to numbers as if
2357 * by calling the number function.
2358 */
2359void
2360xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
2361 xmlXPathObjectPtr arg;
Daniel Veillard2b325a02001-01-31 20:46:31 +00002362 int arg1, arg2;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002363
2364 POP_FLOAT
Daniel Veillard2b325a02001-01-31 20:46:31 +00002365 arg2 = (int) arg->floatval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002366 xmlXPathFreeObject(arg);
2367
2368 POP_FLOAT
Daniel Veillard2b325a02001-01-31 20:46:31 +00002369 arg1 = (int) arg->floatval;
2370 arg->floatval = arg1 % arg2;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002371 valuePush(ctxt, arg);
2372}
2373
2374/************************************************************************
2375 * *
2376 * The traversal functions *
2377 * *
2378 ************************************************************************/
2379
Daniel Veillard740abf52000-10-02 23:04:54 +00002380typedef enum {
2381 AXIS_ANCESTOR = 1,
2382 AXIS_ANCESTOR_OR_SELF,
2383 AXIS_ATTRIBUTE,
2384 AXIS_CHILD,
2385 AXIS_DESCENDANT,
2386 AXIS_DESCENDANT_OR_SELF,
2387 AXIS_FOLLOWING,
2388 AXIS_FOLLOWING_SIBLING,
2389 AXIS_NAMESPACE,
2390 AXIS_PARENT,
2391 AXIS_PRECEDING,
2392 AXIS_PRECEDING_SIBLING,
2393 AXIS_SELF
2394} xmlXPathAxisVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002395
2396/*
2397 * A traversal function enumerates nodes along an axis.
2398 * Initially it must be called with NULL, and it indicates
2399 * termination on the axis by returning NULL.
2400 */
2401typedef xmlNodePtr (*xmlXPathTraversalFunction)
2402 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
2403
2404/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002405 * xmlXPathNextSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002406 * @ctxt: the XPath Parser context
2407 * @cur: the current node in the traversal
2408 *
2409 * Traversal function for the "self" direction
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002410 * The self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00002411 *
2412 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002413 */
2414xmlNodePtr
2415xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2416 if (cur == NULL)
2417 return(ctxt->context->node);
2418 return(NULL);
2419}
2420
2421/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002422 * xmlXPathNextChild:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002423 * @ctxt: the XPath Parser context
2424 * @cur: the current node in the traversal
2425 *
2426 * Traversal function for the "child" direction
2427 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002428 *
2429 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002430 */
2431xmlNodePtr
2432xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002433 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002434 if (ctxt->context->node == NULL) return(NULL);
2435 switch (ctxt->context->node->type) {
2436 case XML_ELEMENT_NODE:
2437 case XML_TEXT_NODE:
2438 case XML_CDATA_SECTION_NODE:
2439 case XML_ENTITY_REF_NODE:
2440 case XML_ENTITY_NODE:
2441 case XML_PI_NODE:
2442 case XML_COMMENT_NODE:
2443 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002444 case XML_DTD_NODE:
2445 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002446 case XML_DOCUMENT_NODE:
2447 case XML_DOCUMENT_TYPE_NODE:
2448 case XML_DOCUMENT_FRAG_NODE:
2449 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002450#ifdef LIBXML_SGML_ENABLED
2451 case XML_SGML_DOCUMENT_NODE:
2452#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002453 return(((xmlDocPtr) ctxt->context->node)->children);
2454 case XML_ELEMENT_DECL:
2455 case XML_ATTRIBUTE_DECL:
2456 case XML_ENTITY_DECL:
2457 case XML_ATTRIBUTE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002458 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002459 case XML_XINCLUDE_START:
2460 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002461 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002462 }
2463 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002464 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002465 if ((cur->type == XML_DOCUMENT_NODE) ||
2466 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002467 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002468 return(cur->next);
2469}
2470
2471/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002472 * xmlXPathNextDescendant:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002473 * @ctxt: the XPath Parser context
2474 * @cur: the current node in the traversal
2475 *
2476 * Traversal function for the "descendant" direction
2477 * the descendant axis contains the descendants of the context node in document
2478 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002479 *
2480 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002481 */
2482xmlNodePtr
2483xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002484 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002485 if (ctxt->context->node == NULL)
2486 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002487 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2488 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002489 return(NULL);
2490
Daniel Veillardb05deb71999-08-10 19:04:08 +00002491 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00002492 return(ctxt->context->doc->children);
2493 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002494 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002495
Daniel Veillardbe803962000-06-28 23:40:59 +00002496 if (cur->children != NULL)
2497 {
2498 if (cur->children->type != XML_ENTITY_DECL)
2499 return(cur->children);
2500 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002501 if (cur->next != NULL) return(cur->next);
2502
2503 do {
2504 cur = cur->parent;
2505 if (cur == NULL) return(NULL);
2506 if (cur == ctxt->context->node) return(NULL);
2507 if (cur->next != NULL) {
2508 cur = cur->next;
2509 return(cur);
2510 }
2511 } while (cur != NULL);
2512 return(cur);
2513}
2514
2515/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002516 * xmlXPathNextDescendantOrSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002517 * @ctxt: the XPath Parser context
2518 * @cur: the current node in the traversal
2519 *
2520 * Traversal function for the "descendant-or-self" direction
2521 * the descendant-or-self axis contains the context node and the descendants
2522 * of the context node in document order; thus the context node is the first
2523 * node on the axis, and the first child of the context node is the second node
2524 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002525 *
2526 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002527 */
2528xmlNodePtr
2529xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002530 if (cur == NULL) {
2531 if (ctxt->context->node == NULL)
2532 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002533 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2534 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002535 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002536 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002537 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002538
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002539 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002540}
2541
2542/**
2543 * xmlXPathNextParent:
2544 * @ctxt: the XPath Parser context
2545 * @cur: the current node in the traversal
2546 *
2547 * Traversal function for the "parent" direction
2548 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002549 *
2550 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002551 */
2552xmlNodePtr
2553xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2554 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002555 * the parent of an attribute or namespace node is the element
2556 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002557 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002558 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002559 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002560 if (ctxt->context->node == NULL) return(NULL);
2561 switch (ctxt->context->node->type) {
2562 case XML_ELEMENT_NODE:
2563 case XML_TEXT_NODE:
2564 case XML_CDATA_SECTION_NODE:
2565 case XML_ENTITY_REF_NODE:
2566 case XML_ENTITY_NODE:
2567 case XML_PI_NODE:
2568 case XML_COMMENT_NODE:
2569 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002570 case XML_DTD_NODE:
2571 case XML_ELEMENT_DECL:
2572 case XML_ATTRIBUTE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002573 case XML_XINCLUDE_START:
2574 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002575 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002576 if (ctxt->context->node->parent == NULL)
2577 return((xmlNodePtr) ctxt->context->doc);
2578 return(ctxt->context->node->parent);
2579 case XML_ATTRIBUTE_NODE: {
2580 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2581
Daniel Veillardcf461992000-03-14 18:30:20 +00002582 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002583 }
2584 case XML_DOCUMENT_NODE:
2585 case XML_DOCUMENT_TYPE_NODE:
2586 case XML_DOCUMENT_FRAG_NODE:
2587 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002588#ifdef LIBXML_SGML_ENABLED
2589 case XML_SGML_DOCUMENT_NODE:
2590#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002591 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002592 case XML_NAMESPACE_DECL:
2593 /*
2594 * TODO !!! may require extending struct _xmlNs with
2595 * parent field
2596 * C.f. Infoset case...
2597 */
2598 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002599 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002600 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002601 return(NULL);
2602}
2603
2604/**
2605 * xmlXPathNextAncestor:
2606 * @ctxt: the XPath Parser context
2607 * @cur: the current node in the traversal
2608 *
2609 * Traversal function for the "ancestor" direction
2610 * the ancestor axis contains the ancestors of the context node; the ancestors
2611 * of the context node consist of the parent of context node and the parent's
2612 * parent and so on; the nodes are ordered in reverse document order; thus the
2613 * parent is the first node on the axis, and the parent's parent is the second
2614 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002615 *
2616 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002617 */
2618xmlNodePtr
2619xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2620 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002621 * the parent of an attribute or namespace node is the element
2622 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002623 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002624 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002625 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002626 if (ctxt->context->node == NULL) return(NULL);
2627 switch (ctxt->context->node->type) {
2628 case XML_ELEMENT_NODE:
2629 case XML_TEXT_NODE:
2630 case XML_CDATA_SECTION_NODE:
2631 case XML_ENTITY_REF_NODE:
2632 case XML_ENTITY_NODE:
2633 case XML_PI_NODE:
2634 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002635 case XML_DTD_NODE:
2636 case XML_ELEMENT_DECL:
2637 case XML_ATTRIBUTE_DECL:
2638 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002639 case XML_NOTATION_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002640 case XML_XINCLUDE_START:
2641 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002642 if (ctxt->context->node->parent == NULL)
2643 return((xmlNodePtr) ctxt->context->doc);
2644 return(ctxt->context->node->parent);
2645 case XML_ATTRIBUTE_NODE: {
2646 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2647
Daniel Veillardcf461992000-03-14 18:30:20 +00002648 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002649 }
2650 case XML_DOCUMENT_NODE:
2651 case XML_DOCUMENT_TYPE_NODE:
2652 case XML_DOCUMENT_FRAG_NODE:
2653 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002654#ifdef LIBXML_SGML_ENABLED
2655 case XML_SGML_DOCUMENT_NODE:
2656#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002657 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002658 case XML_NAMESPACE_DECL:
2659 /*
2660 * TODO !!! may require extending struct _xmlNs with
2661 * parent field
2662 * C.f. Infoset case...
2663 */
2664 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002665 }
2666 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002667 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002668 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002669 return((xmlNodePtr) ctxt->context->doc);
2670 if (cur == (xmlNodePtr) ctxt->context->doc)
2671 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002672 switch (cur->type) {
2673 case XML_ELEMENT_NODE:
2674 case XML_TEXT_NODE:
2675 case XML_CDATA_SECTION_NODE:
2676 case XML_ENTITY_REF_NODE:
2677 case XML_ENTITY_NODE:
2678 case XML_PI_NODE:
2679 case XML_COMMENT_NODE:
2680 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002681 case XML_DTD_NODE:
2682 case XML_ELEMENT_DECL:
2683 case XML_ATTRIBUTE_DECL:
2684 case XML_ENTITY_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002685 case XML_XINCLUDE_START:
2686 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002687 return(cur->parent);
2688 case XML_ATTRIBUTE_NODE: {
2689 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2690
Daniel Veillardcf461992000-03-14 18:30:20 +00002691 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002692 }
2693 case XML_DOCUMENT_NODE:
2694 case XML_DOCUMENT_TYPE_NODE:
2695 case XML_DOCUMENT_FRAG_NODE:
2696 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002697#ifdef LIBXML_SGML_ENABLED
2698 case XML_SGML_DOCUMENT_NODE:
2699#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002700 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002701 case XML_NAMESPACE_DECL:
2702 /*
2703 * TODO !!! may require extending struct _xmlNs with
2704 * parent field
2705 * C.f. Infoset case...
2706 */
2707 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002708 }
2709 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002710}
2711
2712/**
2713 * xmlXPathNextAncestorOrSelf:
2714 * @ctxt: the XPath Parser context
2715 * @cur: the current node in the traversal
2716 *
2717 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00002718 * he ancestor-or-self axis contains the context node and ancestors of
2719 * the context node in reverse document order; thus the context node is
2720 * the first node on the axis, and the context node's parent the second;
2721 * parent here is defined the same as with the parent axis.
2722 *
2723 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002724 */
2725xmlNodePtr
2726xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002727 if (cur == NULL)
2728 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002729 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002730}
2731
2732/**
2733 * xmlXPathNextFollowingSibling:
2734 * @ctxt: the XPath Parser context
2735 * @cur: the current node in the traversal
2736 *
2737 * Traversal function for the "following-sibling" direction
2738 * The following-sibling axis contains the following siblings of the context
2739 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002740 *
2741 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002742 */
2743xmlNodePtr
2744xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002745 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2746 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2747 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002748 if (cur == (xmlNodePtr) ctxt->context->doc)
2749 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002750 if (cur == NULL)
2751 return(ctxt->context->node->next);
2752 return(cur->next);
2753}
2754
2755/**
2756 * xmlXPathNextPrecedingSibling:
2757 * @ctxt: the XPath Parser context
2758 * @cur: the current node in the traversal
2759 *
2760 * Traversal function for the "preceding-sibling" direction
2761 * The preceding-sibling axis contains the preceding siblings of the context
2762 * node in reverse document order; the first preceding sibling is first on the
2763 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002764 *
2765 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002766 */
2767xmlNodePtr
2768xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002769 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2770 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2771 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002772 if (cur == (xmlNodePtr) ctxt->context->doc)
2773 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002774 if (cur == NULL)
2775 return(ctxt->context->node->prev);
2776 return(cur->prev);
2777}
2778
2779/**
2780 * xmlXPathNextFollowing:
2781 * @ctxt: the XPath Parser context
2782 * @cur: the current node in the traversal
2783 *
2784 * Traversal function for the "following" direction
2785 * The following axis contains all nodes in the same document as the context
2786 * node that are after the context node in document order, excluding any
2787 * descendants and excluding attribute nodes and namespace nodes; the nodes
2788 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00002789 *
2790 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002791 */
2792xmlNodePtr
2793xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002794 if (cur != NULL && cur->children != NULL)
2795 return cur->children ;
Daniel Veillardac260302000-10-04 13:33:43 +00002796 if (cur == NULL) cur = ctxt->context->node;
2797 if (cur == NULL) return(NULL) ; /* ERROR */
2798 if (cur->next != NULL) return(cur->next) ;
Daniel Veillard740abf52000-10-02 23:04:54 +00002799 do {
2800 cur = cur->parent;
2801 if (cur == NULL) return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002802 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002803 if (cur->next != NULL) return(cur->next);
Daniel Veillard740abf52000-10-02 23:04:54 +00002804 } while (cur != NULL);
2805 return(cur);
2806}
2807
2808/*
Daniel Veillardac260302000-10-04 13:33:43 +00002809 * xmlXPathIsAncestor:
2810 * @ancestor: the ancestor node
2811 * @node: the current node
2812 *
2813 * Check that @ancestor is a @node's ancestor
2814 *
Daniel Veillard740abf52000-10-02 23:04:54 +00002815 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2816 */
2817static int
Daniel Veillardac260302000-10-04 13:33:43 +00002818xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002819 if ((ancestor == NULL) || (node == NULL)) return(0);
2820 /* nodes need to be in the same document */
2821 if (ancestor->doc != node->doc) return(0);
2822 /* avoid searching if ancestor or node is the root node */
2823 if (ancestor == (xmlNodePtr) node->doc) return(1);
2824 if (node == (xmlNodePtr) ancestor->doc) return(0);
2825 while (node->parent != NULL) {
2826 if (node->parent == ancestor)
2827 return(1);
2828 node = node->parent;
Daniel Veillard740abf52000-10-02 23:04:54 +00002829 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002830 return(0);
Daniel Veillard740abf52000-10-02 23:04:54 +00002831}
2832
2833/**
2834 * xmlXPathNextPreceding:
2835 * @ctxt: the XPath Parser context
2836 * @cur: the current node in the traversal
2837 *
2838 * Traversal function for the "preceding" direction
2839 * the preceding axis contains all nodes in the same document as the context
2840 * node that are before the context node in document order, excluding any
2841 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2842 * ordered in reverse document order
2843 *
2844 * Returns the next element following that axis
2845 */
2846xmlNodePtr
2847xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2848 if (cur == NULL)
2849 cur = ctxt->context->node ;
2850 do {
2851 if (cur->prev != NULL) {
2852 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2853 ;
2854 return(cur) ;
2855 }
2856
2857 cur = cur->parent;
2858 if (cur == NULL) return(NULL);
2859 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002860 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillard740abf52000-10-02 23:04:54 +00002861 return(cur);
2862}
2863
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002864/**
2865 * xmlXPathNextNamespace:
2866 * @ctxt: the XPath Parser context
2867 * @cur: the current attribute in the traversal
2868 *
2869 * Traversal function for the "namespace" direction
2870 * the namespace axis contains the namespace nodes of the context node;
2871 * the order of nodes on this axis is implementation-defined; the axis will
2872 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00002873 *
2874 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002875 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002876xmlNodePtr
2877xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2878 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002879 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2880 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002881 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002882 ctxt->context->namespaces =
2883 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2884 if (ctxt->context->namespaces == NULL) return(NULL);
2885 ctxt->context->nsNr = 0;
2886 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002887 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002888}
2889
2890/**
2891 * xmlXPathNextAttribute:
2892 * @ctxt: the XPath Parser context
2893 * @cur: the current attribute in the traversal
2894 *
2895 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00002896 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00002897 *
2898 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002899 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002900xmlNodePtr
2901xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2902 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002903 if (cur == NULL) {
2904 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2905 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002906 return((xmlNodePtr)ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002907 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002908 return((xmlNodePtr)cur->next);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002909}
2910
2911/************************************************************************
2912 * *
2913 * NodeTest Functions *
2914 * *
2915 ************************************************************************/
2916
Daniel Veillard740abf52000-10-02 23:04:54 +00002917typedef enum {
2918 NODE_TEST_NONE = 0,
2919 NODE_TEST_TYPE = 1,
2920 NODE_TEST_PI = 2,
2921 NODE_TEST_ALL = 3,
2922 NODE_TEST_NS = 4,
2923 NODE_TEST_NAME = 5
2924} xmlXPathTestVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002925
Daniel Veillard740abf52000-10-02 23:04:54 +00002926typedef enum {
Daniel Veillard2f913b72001-01-31 13:23:49 +00002927 NODE_TYPE_NODE = 0,
Daniel Veillard55b91f22000-10-05 16:30:11 +00002928 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
2929 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard2f913b72001-01-31 13:23:49 +00002930 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard740abf52000-10-02 23:04:54 +00002931} xmlXPathTypeVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002932
2933#define IS_FUNCTION 200
2934
2935/**
2936 * xmlXPathNodeCollectAndTest:
2937 * @ctxt: the XPath Parser context
Daniel Veillard740abf52000-10-02 23:04:54 +00002938 * @axis: the XPath axis
2939 * @test: the XPath test
2940 * @type: the XPath type
2941 * @prefix: the namesapce prefix if any
2942 * @name: the name used in the search if any
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002943 *
2944 * This is the function implementing a step: based on the current list
2945 * of nodes, it builds up a new list, looking at all nodes under that
2946 * axis and selecting them.
2947 *
2948 * Returns the new NodeSet resulting from the search.
2949 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002950void
2951xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2952 xmlXPathTestVal test, xmlXPathTypeVal type,
2953 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002954#ifdef DEBUG_STEP
2955 int n = 0, t = 0;
2956#endif
2957 int i;
2958 xmlNodeSetPtr ret;
2959 xmlXPathTraversalFunction next = NULL;
2960 xmlNodePtr cur = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00002961 xmlXPathObjectPtr obj;
2962 xmlNodeSetPtr nodelist;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002963
Daniel Veillard740abf52000-10-02 23:04:54 +00002964 CHECK_TYPE(XPATH_NODESET);
2965 obj = valuePop(ctxt);
2966
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002967#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002968 xmlGenericError(xmlGenericErrorContext,
2969 "new step : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002970#endif
2971 switch (axis) {
2972 case AXIS_ANCESTOR:
2973#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002974 xmlGenericError(xmlGenericErrorContext,
2975 "axis 'ancestors' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002976#endif
2977 next = xmlXPathNextAncestor; break;
2978 case AXIS_ANCESTOR_OR_SELF:
2979#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002980 xmlGenericError(xmlGenericErrorContext,
2981 "axis 'ancestors-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002982#endif
2983 next = xmlXPathNextAncestorOrSelf; break;
2984 case AXIS_ATTRIBUTE:
2985#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002986 xmlGenericError(xmlGenericErrorContext,
2987 "axis 'attributes' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002988#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002989 next = xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002990 break;
2991 case AXIS_CHILD:
2992#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002993 xmlGenericError(xmlGenericErrorContext,
2994 "axis 'child' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002995#endif
2996 next = xmlXPathNextChild; break;
2997 case AXIS_DESCENDANT:
2998#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002999 xmlGenericError(xmlGenericErrorContext,
3000 "axis 'descendant' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003001#endif
3002 next = xmlXPathNextDescendant; break;
3003 case AXIS_DESCENDANT_OR_SELF:
3004#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003005 xmlGenericError(xmlGenericErrorContext,
3006 "axis 'descendant-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003007#endif
3008 next = xmlXPathNextDescendantOrSelf; break;
3009 case AXIS_FOLLOWING:
3010#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003011 xmlGenericError(xmlGenericErrorContext,
3012 "axis 'following' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003013#endif
3014 next = xmlXPathNextFollowing; break;
3015 case AXIS_FOLLOWING_SIBLING:
3016#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003017 xmlGenericError(xmlGenericErrorContext,
3018 "axis 'following-siblings' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003019#endif
3020 next = xmlXPathNextFollowingSibling; break;
3021 case AXIS_NAMESPACE:
3022#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003023 xmlGenericError(xmlGenericErrorContext,
3024 "axis 'namespace' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003025#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003026 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003027 break;
3028 case AXIS_PARENT:
3029#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003030 xmlGenericError(xmlGenericErrorContext,
3031 "axis 'parent' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003032#endif
3033 next = xmlXPathNextParent; break;
3034 case AXIS_PRECEDING:
3035#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003036 xmlGenericError(xmlGenericErrorContext,
3037 "axis 'preceding' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003038#endif
3039 next = xmlXPathNextPreceding; break;
3040 case AXIS_PRECEDING_SIBLING:
3041#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003042 xmlGenericError(xmlGenericErrorContext,
3043 "axis 'preceding-sibling' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003044#endif
3045 next = xmlXPathNextPrecedingSibling; break;
3046 case AXIS_SELF:
3047#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003048 xmlGenericError(xmlGenericErrorContext,
3049 "axis 'self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003050#endif
3051 next = xmlXPathNextSelf; break;
3052 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003053 if (next == NULL)
3054 return;
3055
3056 nodelist = obj->nodesetval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003057 ret = xmlXPathNodeSetCreate(NULL);
3058#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003059 xmlGenericError(xmlGenericErrorContext,
3060 " context contains %d nodes\n",
Daniel Veillard740abf52000-10-02 23:04:54 +00003061 nodelist->nodeNr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003062 switch (test) {
Daniel Veillard2f913b72001-01-31 13:23:49 +00003063 case NODE_TEST_NODE:
3064 xmlGenericError(xmlGenericErrorContext,
3065 " searching all nodes\n");
3066 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003067 case NODE_TEST_NONE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003068 xmlGenericError(xmlGenericErrorContext,
3069 " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003070 break;
3071 case NODE_TEST_TYPE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003072 xmlGenericError(xmlGenericErrorContext,
3073 " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003074 break;
3075 case NODE_TEST_PI:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003076 xmlGenericError(xmlGenericErrorContext,
3077 " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003078 break;
3079 case NODE_TEST_ALL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003080 xmlGenericError(xmlGenericErrorContext,
3081 " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003082 break;
3083 case NODE_TEST_NS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003084 xmlGenericError(xmlGenericErrorContext,
3085 " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003086 prefix);
3087 break;
3088 case NODE_TEST_NAME:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003089 xmlGenericError(xmlGenericErrorContext,
3090 " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003091 if (prefix != NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003092 xmlGenericError(xmlGenericErrorContext,
3093 " with namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003094 prefix);
3095 break;
3096 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003097 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003098#endif
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00003099 /*
3100 * 2.3 Node Tests
3101 * - For the attribute axis, the principal node type is attribute.
3102 * - For the namespace axis, the principal node type is namespace.
3103 * - For other axes, the principal node type is element.
3104 *
3105 * A node test * is true for any node of the
3106 * principal node type. For example, child::* willi
3107 * select all element children of the context node
3108 */
Daniel Veillard740abf52000-10-02 23:04:54 +00003109 for (i = 0;i < nodelist->nodeNr; i++) {
3110 ctxt->context->node = nodelist->nodeTab[i];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003111
3112 cur = NULL;
3113 do {
3114 cur = next(ctxt, cur);
3115 if (cur == NULL) break;
3116#ifdef DEBUG_STEP
3117 t++;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003118 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003119#endif
3120 switch (test) {
3121 case NODE_TEST_NONE:
3122 STRANGE
Daniel Veillard740abf52000-10-02 23:04:54 +00003123 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003124 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003125 if ((cur->type == type) ||
Daniel Veillard2f913b72001-01-31 13:23:49 +00003126 ((type == NODE_TYPE_NODE) &&
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003127 ((cur->type == XML_DOCUMENT_NODE) ||
Daniel Veillard2f913b72001-01-31 13:23:49 +00003128 (cur->type == XML_HTML_DOCUMENT_NODE) ||
3129 (cur->type == XML_ELEMENT_NODE) ||
3130 (cur->type == XML_PI_NODE) ||
3131 (cur->type == XML_COMMENT_NODE) ||
3132 (cur->type == XML_CDATA_SECTION_NODE) ||
3133 (cur->type == XML_TEXT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003134#ifdef DEBUG_STEP
3135 n++;
3136#endif
3137 xmlXPathNodeSetAdd(ret, cur);
3138 }
3139 break;
3140 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003141 if (cur->type == XML_PI_NODE) {
3142 if ((name != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003143 (!xmlStrEqual(name, cur->name)))
Daniel Veillardb96e6431999-08-29 21:02:19 +00003144 break;
3145#ifdef DEBUG_STEP
3146 n++;
3147#endif
3148 xmlXPathNodeSetAdd(ret, cur);
3149 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003150 break;
3151 case NODE_TEST_ALL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003152 if (axis == AXIS_ATTRIBUTE) {
3153 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003154#ifdef DEBUG_STEP
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003155 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003156#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003157 xmlXPathNodeSetAdd(ret, cur);
3158 }
3159 } else if (axis == AXIS_NAMESPACE) {
3160 if (cur->type == XML_NAMESPACE_DECL) {
3161#ifdef DEBUG_STEP
3162 n++;
3163#endif
3164 xmlXPathNodeSetAdd(ret, cur);
3165 }
3166 } else {
3167 if ((cur->type == XML_ELEMENT_NODE) ||
3168 (cur->type == XML_DOCUMENT_NODE) ||
3169 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003170 if (prefix == NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003171#ifdef DEBUG_STEP
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003172 n++;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003173#endif
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003174 xmlXPathNodeSetAdd(ret, cur);
3175 } else if ((cur->ns != NULL) &&
3176 (xmlStrEqual(prefix,
3177 cur->ns->href))) {
3178#ifdef DEBUG_STEP
3179 n++;
3180#endif
3181 xmlXPathNodeSetAdd(ret, cur);
3182 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003183 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003184 }
3185 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003186 case NODE_TEST_NS: {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003187 TODO;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003188 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003189 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003190 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003191 switch (cur->type) {
3192 case XML_ELEMENT_NODE:
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003193 if (xmlStrEqual(name, cur->name)) {
3194 if (prefix == NULL) {
3195 if ((cur->ns == NULL) ||
3196 (cur->ns->prefix == NULL)) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003197#ifdef DEBUG_STEP
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003198 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003199#endif
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003200 xmlXPathNodeSetAdd(ret, cur);
3201 }
3202 } else {
3203 if ((cur->ns != NULL) &&
3204 (xmlStrEqual(prefix,
3205 cur->ns->href))) {
3206#ifdef DEBUG_STEP
3207 n++;
3208#endif
3209 xmlXPathNodeSetAdd(ret, cur);
3210 }
3211 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003212 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003213 break;
3214 case XML_ATTRIBUTE_NODE: {
3215 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003216 if (xmlStrEqual(name, attr->name)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003217#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00003218 n++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003219#endif
3220 xmlXPathNodeSetAdd(ret, cur);
3221 }
3222 break;
3223 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003224 case XML_NAMESPACE_DECL: {
3225 TODO;
3226 break;
3227 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003228 default:
3229 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003230 }
3231 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003232 }
3233 } while (cur != NULL);
3234 }
3235#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003236 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003237 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
3238#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00003239 xmlXPathFreeObject(obj);
3240 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003241}
3242
3243
3244/************************************************************************
3245 * *
3246 * Implicit tree core function library *
3247 * *
3248 ************************************************************************/
3249
3250/**
3251 * xmlXPathRoot:
3252 * @ctxt: the XPath Parser context
3253 *
3254 * Initialize the context to the root of the document
3255 */
3256void
3257xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003258 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Daniel Veillard740abf52000-10-02 23:04:54 +00003259 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003260}
3261
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003262/************************************************************************
3263 * *
3264 * The explicit core function library *
3265 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3266 * *
3267 ************************************************************************/
3268
3269
3270/**
3271 * xmlXPathLastFunction:
3272 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003273 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003274 *
3275 * Implement the last() XPath function
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003276 * number last()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003277 * The last function returns the number of nodes in the context node list.
3278 */
3279void
3280xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3281 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003282 if (ctxt->context->contextSize > 0) {
3283 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3284#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003285 xmlGenericError(xmlGenericErrorContext,
3286 "last() : %d\n", ctxt->context->contextSize);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003287#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003288 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003289 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003290 }
3291}
3292
3293/**
3294 * xmlXPathPositionFunction:
3295 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003296 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003297 *
3298 * Implement the position() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003299 * number position()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003300 * The position function returns the position of the context node in the
3301 * context node list. The first position is 1, and so the last positionr
3302 * will be equal to last().
3303 */
3304void
3305xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003306 CHECK_ARITY(0);
Daniel Veillardff9c3302000-10-13 16:38:25 +00003307 if (ctxt->context->proximityPosition >= 0) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003308 valuePush(ctxt,
Daniel Veillardff9c3302000-10-13 16:38:25 +00003309 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003310#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003311 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003312 ctxt->context->proximityPosition);
3313#endif
3314 } else {
3315 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003316 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003317}
3318
3319/**
3320 * xmlXPathCountFunction:
3321 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003322 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003323 *
3324 * Implement the count() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003325 * number count(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003326 */
3327void
3328xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3329 xmlXPathObjectPtr cur;
3330
3331 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003332 if ((ctxt->value == NULL) ||
3333 ((ctxt->value->type != XPATH_NODESET) &&
3334 (ctxt->value->type != XPATH_XSLT_TREE)))
3335 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003336 cur = valuePop(ctxt);
3337
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003338 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003339 xmlXPathFreeObject(cur);
3340}
3341
3342/**
3343 * xmlXPathIdFunction:
3344 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003345 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 *
3347 * Implement the id() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003348 * node-set id(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003349 * The id function selects elements by their unique ID
3350 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3351 * then the result is the union of the result of applying id to the
3352 * string value of each of the nodes in the argument node-set. When the
3353 * argument to id is of any other type, the argument is converted to a
3354 * string as if by a call to the string function; the string is split
3355 * into a whitespace-separated list of tokens (whitespace is any sequence
3356 * of characters matching the production S); the result is a node-set
3357 * containing the elements in the same document as the context node that
3358 * have a unique ID equal to any of the tokens in the list.
3359 */
3360void
3361xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003362 const xmlChar *tokens;
3363 const xmlChar *cur;
3364 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003365 xmlAttrPtr attr;
3366 xmlNodePtr elem = NULL;
3367 xmlXPathObjectPtr ret, obj;
3368
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003369 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003370 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003371 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003372 if (obj->type == XPATH_NODESET) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003373 xmlXPathObjectPtr newobj;
3374 int i;
3375
3376 ret = xmlXPathNewNodeSet(NULL);
3377
3378 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3379 valuePush(ctxt,
3380 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3381 xmlXPathStringFunction(ctxt, 1);
3382 xmlXPathIdFunction(ctxt, 1);
3383 newobj = valuePop(ctxt);
3384 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3385 newobj->nodesetval);
3386 xmlXPathFreeObject(newobj);
3387 }
3388
3389 xmlXPathFreeObject(obj);
3390 valuePush(ctxt, ret);
3391 return;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003392 }
3393 if (obj->type != XPATH_STRING) {
3394 valuePush(ctxt, obj);
3395 xmlXPathStringFunction(ctxt, 1);
3396 obj = valuePop(ctxt);
3397 if (obj->type != XPATH_STRING) {
3398 xmlXPathFreeObject(obj);
3399 return;
3400 }
3401 }
3402 tokens = obj->stringval;
3403
3404 ret = xmlXPathNewNodeSet(NULL);
3405 valuePush(ctxt, ret);
3406 if (tokens == NULL) {
3407 xmlXPathFreeObject(obj);
3408 return;
3409 }
3410
3411 cur = tokens;
3412
3413 while (IS_BLANK(*cur)) cur++;
3414 while (*cur != 0) {
3415 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3416 (*cur == '.') || (*cur == '-') ||
3417 (*cur == '_') || (*cur == ':') ||
3418 (IS_COMBINING(*cur)) ||
3419 (IS_EXTENDER(*cur)))
3420 cur++;
3421
3422 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3423
3424 ID = xmlStrndup(tokens, cur - tokens);
3425 attr = xmlGetID(ctxt->context->doc, ID);
3426 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003427 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003428 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3429 }
3430 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003431 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003432
3433 while (IS_BLANK(*cur)) cur++;
3434 tokens = cur;
3435 }
3436 xmlXPathFreeObject(obj);
3437 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003438}
3439
3440/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003441 * xmlXPathLocalNameFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003442 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003443 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003444 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003445 * Implement the local-name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003446 * string local-name(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003447 * The local-name function returns a string containing the local part
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003448 * of the name of the node in the argument node-set that is first in
3449 * document order. If the node-set is empty or the first node has no
3450 * name, an empty string is returned. If the argument is omitted it
3451 * defaults to the context node.
3452 */
3453void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003454xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003455 xmlXPathObjectPtr cur;
3456
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003457 if (nargs == 0) {
3458 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3459 nargs = 1;
3460 }
3461
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003462 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003463 if ((ctxt->value == NULL) ||
3464 ((ctxt->value->type != XPATH_NODESET) &&
3465 (ctxt->value->type != XPATH_XSLT_TREE)))
3466 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003467 cur = valuePop(ctxt);
3468
3469 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003470 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003471 } else {
3472 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003473 switch (cur->nodesetval->nodeTab[i]->type) {
3474 case XML_ELEMENT_NODE:
3475 case XML_ATTRIBUTE_NODE:
3476 case XML_PI_NODE:
3477 valuePush(ctxt,
3478 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
3479 break;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003480 case XML_NAMESPACE_DECL:
3481 valuePush(ctxt, xmlXPathNewString(
3482 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
3483 break;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003484 default:
3485 valuePush(ctxt, xmlXPathNewCString(""));
3486 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003487 }
3488 xmlXPathFreeObject(cur);
3489}
3490
3491/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003492 * xmlXPathNamespaceURIFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003493 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003494 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003495 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003496 * Implement the namespace-uri() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003497 * string namespace-uri(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003498 * The namespace-uri function returns a string containing the
3499 * namespace URI of the expanded name of the node in the argument
3500 * node-set that is first in document order. If the node-set is empty,
3501 * the first node has no name, or the expanded name has no namespace
3502 * URI, an empty string is returned. If the argument is omitted it
3503 * defaults to the context node.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003504 */
3505void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003506xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003507 xmlXPathObjectPtr cur;
3508
Daniel Veillardb96e6431999-08-29 21:02:19 +00003509 if (nargs == 0) {
3510 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3511 nargs = 1;
3512 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003513 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003514 if ((ctxt->value == NULL) ||
3515 ((ctxt->value->type != XPATH_NODESET) &&
3516 (ctxt->value->type != XPATH_XSLT_TREE)))
3517 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003518 cur = valuePop(ctxt);
3519
3520 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003521 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003522 } else {
3523 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003524 switch (cur->nodesetval->nodeTab[i]->type) {
3525 case XML_ELEMENT_NODE:
3526 case XML_ATTRIBUTE_NODE:
3527 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3528 valuePush(ctxt, xmlXPathNewCString(""));
3529 else
3530 valuePush(ctxt, xmlXPathNewString(
3531 cur->nodesetval->nodeTab[i]->ns->href));
3532 break;
3533 default:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003534 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003535 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003536 }
3537 xmlXPathFreeObject(cur);
3538}
3539
3540/**
3541 * xmlXPathNameFunction:
3542 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003543 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003544 *
3545 * Implement the name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003546 * string name(node-set?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003547 * The name function returns a string containing a QName representing
3548 * the name of the node in the argument node-set that is first in documenti
3549 * order. The QName must represent the name with respect to the namespace
3550 * declarations in effect on the node whose name is being represented.
3551 * Typically, this will be the form in which the name occurred in the XML
3552 * source. This need not be the case if there are namespace declarations
3553 * in effect on the node that associate multiple prefixes with the same
3554 * namespace. However, an implementation may include information about
3555 * the original prefix in its representation of nodes; in this case, an
3556 * implementation can ensure that the returned string is always the same
3557 * as the QName used in the XML source. If the argument it omitted it
3558 * defaults to the context node.
3559 * Libxml keep the original prefix so the "real qualified name" used is
3560 * returned.
3561 */
3562void
3563xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3564 xmlXPathObjectPtr cur;
3565
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003566 if (nargs == 0) {
3567 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3568 nargs = 1;
3569 }
3570
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003571 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003572 if ((ctxt->value == NULL) ||
3573 ((ctxt->value->type != XPATH_NODESET) &&
3574 (ctxt->value->type != XPATH_XSLT_TREE)))
3575 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003576 cur = valuePop(ctxt);
3577
3578 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003579 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003580 } else {
3581 int i = 0; /* Should be first in document order !!!!! */
3582
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003583 switch (cur->nodesetval->nodeTab[i]->type) {
3584 case XML_ELEMENT_NODE:
3585 case XML_ATTRIBUTE_NODE:
3586 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3587 valuePush(ctxt, xmlXPathNewString(
3588 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003589
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003590 else {
3591 char name[2000];
Daniel Veillard39c7d712000-09-10 16:14:55 +00003592#ifdef HAVE_SNPRINTF
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003593 snprintf(name, sizeof(name), "%s:%s",
3594 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3595 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003596#else
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003597 sprintf(name, "%s:%s",
3598 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3599 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003600#endif
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003601 name[sizeof(name) - 1] = 0;
3602 valuePush(ctxt, xmlXPathNewCString(name));
3603 }
3604 break;
3605 default:
3606 valuePush(ctxt,
3607 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3608 xmlXPathLocalNameFunction(ctxt, 1);
3609 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003610 }
3611 xmlXPathFreeObject(cur);
3612}
3613
3614/**
3615 * xmlXPathStringFunction:
3616 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003617 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003618 *
3619 * Implement the string() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003620 * string string(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003621 * he string function converts an object to a string as follows:
3622 * - A node-set is converted to a string by returning the value of
3623 * the node in the node-set that is first in document order.
3624 * If the node-set is empty, an empty string is returned.
3625 * - A number is converted to a string as follows
3626 * + NaN is converted to the string NaN
3627 * + positive zero is converted to the string 0
3628 * + negative zero is converted to the string 0
3629 * + positive infinity is converted to the string Infinity
3630 * + negative infinity is converted to the string -Infinity
3631 * + if the number is an integer, the number is represented in
3632 * decimal form as a Number with no decimal point and no leading
3633 * zeros, preceded by a minus sign (-) if the number is negative
3634 * + otherwise, the number is represented in decimal form as a
3635 * Number including a decimal point with at least one digit
3636 * before the decimal point and at least one digit after the
3637 * decimal point, preceded by a minus sign (-) if the number
3638 * is negative; there must be no leading zeros before the decimal
3639 * point apart possibly from the one required digit immediatelyi
3640 * before the decimal point; beyond the one required digit
3641 * after the decimal point there must be as many, but only as
3642 * many, more digits as are needed to uniquely distinguish the
3643 * number from all other IEEE 754 numeric values.
3644 * - The boolean false value is converted to the string false.
3645 * The boolean true value is converted to the string true.
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003646 *
3647 * If the argument is omitted, it defaults to a node-set with the
3648 * context node as its only member.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003649 */
3650void
3651xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3652 xmlXPathObjectPtr cur;
3653
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003654 if (nargs == 0) {
3655 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3656 nargs = 1;
3657 }
3658
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003659 CHECK_ARITY(1);
3660 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003661 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003662 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003663 case XPATH_UNDEFINED:
3664#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003665 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00003666#endif
3667 valuePush(ctxt, xmlXPathNewCString(""));
3668 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00003669 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003670 case XPATH_NODESET:
3671 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003672 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003673 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003674 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003675 int i = 0; /* Should be first in document order !!!!! */
3676 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
3677 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard5a2b6972001-01-20 21:15:50 +00003678 if (res != NULL)
3679 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003680 }
3681 xmlXPathFreeObject(cur);
3682 return;
3683 case XPATH_STRING:
3684 valuePush(ctxt, cur);
3685 return;
3686 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003687 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
3688 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003689 xmlXPathFreeObject(cur);
3690 return;
3691 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003692 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003693
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003694 if (isnan(cur->floatval))
3695 sprintf(buf, "NaN");
3696 else if (isinf(cur->floatval) > 0)
3697 sprintf(buf, "+Infinity");
3698 else if (isinf(cur->floatval) < 0)
3699 sprintf(buf, "-Infinity");
3700 else
3701 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003702 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003703 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003704 return;
3705 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003706 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003707 case XPATH_POINT:
3708 case XPATH_RANGE:
3709 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003710 TODO
3711 valuePush(ctxt, xmlXPathNewCString(""));
3712 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003713 }
3714 STRANGE
3715}
3716
3717/**
3718 * xmlXPathStringLengthFunction:
3719 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003720 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003721 *
3722 * Implement the string-length() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003723 * number string-length(string?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003724 * The string-length returns the number of characters in the string
3725 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3726 * the context node converted to a string, in other words the value
3727 * of the context node.
3728 */
3729void
3730xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3731 xmlXPathObjectPtr cur;
3732
3733 if (nargs == 0) {
3734 if (ctxt->context->node == NULL) {
3735 valuePush(ctxt, xmlXPathNewFloat(0));
3736 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003737 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003738
3739 content = xmlNodeGetContent(ctxt->context->node);
3740 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003741 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003742 }
3743 return;
3744 }
3745 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003746 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003747 CHECK_TYPE(XPATH_STRING);
3748 cur = valuePop(ctxt);
3749 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3750 xmlXPathFreeObject(cur);
3751}
3752
3753/**
3754 * xmlXPathConcatFunction:
3755 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003756 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003757 *
3758 * Implement the concat() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003759 * string concat(string, string, string*)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003760 * The concat function returns the concatenation of its arguments.
3761 */
3762void
3763xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003764 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003765 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003766
3767 if (nargs < 2) {
3768 CHECK_ARITY(2);
3769 }
3770
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003771 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003772 cur = valuePop(ctxt);
3773 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3774 xmlXPathFreeObject(cur);
3775 return;
3776 }
3777 nargs--;
3778
3779 while (nargs > 0) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003780 CAST_TO_STRING;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003781 newobj = valuePop(ctxt);
3782 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3783 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003784 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003785 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003786 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003787 tmp = xmlStrcat(newobj->stringval, cur->stringval);
3788 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003789 cur->stringval = tmp;
3790
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003791 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003792 nargs--;
3793 }
3794 valuePush(ctxt, cur);
3795}
3796
3797/**
3798 * xmlXPathContainsFunction:
3799 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003800 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003801 *
3802 * Implement the contains() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003803 * boolean contains(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003804 * The contains function returns true if the first argument string
3805 * contains the second argument string, and otherwise returns false.
3806 */
3807void
3808xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3809 xmlXPathObjectPtr hay, needle;
3810
3811 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003812 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003813 CHECK_TYPE(XPATH_STRING);
3814 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003815 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003816 hay = valuePop(ctxt);
3817 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3818 xmlXPathFreeObject(hay);
3819 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003820 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003821 }
3822 if (xmlStrstr(hay->stringval, needle->stringval))
3823 valuePush(ctxt, xmlXPathNewBoolean(1));
3824 else
3825 valuePush(ctxt, xmlXPathNewBoolean(0));
3826 xmlXPathFreeObject(hay);
3827 xmlXPathFreeObject(needle);
3828}
3829
3830/**
3831 * xmlXPathStartsWithFunction:
3832 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003833 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003834 *
3835 * Implement the starts-with() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003836 * boolean starts-with(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003837 * The starts-with function returns true if the first argument string
3838 * starts with the second argument string, and otherwise returns false.
3839 */
3840void
3841xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3842 xmlXPathObjectPtr hay, needle;
3843 int n;
3844
3845 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003846 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003847 CHECK_TYPE(XPATH_STRING);
3848 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003849 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003850 hay = valuePop(ctxt);
3851 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3852 xmlXPathFreeObject(hay);
3853 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003854 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003855 }
3856 n = xmlStrlen(needle->stringval);
3857 if (xmlStrncmp(hay->stringval, needle->stringval, n))
3858 valuePush(ctxt, xmlXPathNewBoolean(0));
3859 else
3860 valuePush(ctxt, xmlXPathNewBoolean(1));
3861 xmlXPathFreeObject(hay);
3862 xmlXPathFreeObject(needle);
3863}
3864
3865/**
3866 * xmlXPathSubstringFunction:
3867 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003868 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003869 *
3870 * Implement the substring() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003871 * string substring(string, number, number?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003872 * The substring function returns the substring of the first argument
3873 * starting at the position specified in the second argument with
3874 * length specified in the third argument. For example,
3875 * substring("12345",2,3) returns "234". If the third argument is not
3876 * specified, it returns the substring starting at the position specified
3877 * in the second argument and continuing to the end of the string. For
3878 * example, substring("12345",2) returns "2345". More precisely, each
3879 * character in the string (see [3.6 Strings]) is considered to have a
3880 * numeric position: the position of the first character is 1, the position
3881 * of the second character is 2 and so on. The returned substring contains
3882 * those characters for which the position of the character is greater than
3883 * or equal to the second argument and, if the third argument is specified,
3884 * less than the sum of the second and third arguments; the comparisons
3885 * and addition used for the above follow the standard IEEE 754 rules. Thus:
3886 * - substring("12345", 1.5, 2.6) returns "234"
3887 * - substring("12345", 0, 3) returns "12"
3888 * - substring("12345", 0 div 0, 3) returns ""
3889 * - substring("12345", 1, 0 div 0) returns ""
3890 * - substring("12345", -42, 1 div 0) returns "12345"
3891 * - substring("12345", -1 div 0, 1 div 0) returns ""
3892 */
3893void
3894xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3895 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003896 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003897 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003898 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003899
3900 /*
3901 * Conformance needs to be checked !!!!!
3902 */
3903 if (nargs < 2) {
3904 CHECK_ARITY(2);
3905 }
3906 if (nargs > 3) {
3907 CHECK_ARITY(3);
3908 }
3909 if (nargs == 3) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003910 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003911 CHECK_TYPE(XPATH_NUMBER);
3912 len = valuePop(ctxt);
3913 le = len->floatval;
3914 xmlXPathFreeObject(len);
3915 } else {
3916 le = 2000000000;
3917 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003918 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003919 CHECK_TYPE(XPATH_NUMBER);
3920 start = valuePop(ctxt);
3921 in = start->floatval;
3922 xmlXPathFreeObject(start);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003923 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003924 CHECK_TYPE(XPATH_STRING);
3925 str = valuePop(ctxt);
3926 le += in;
3927
3928 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003929 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003930 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003931
3932 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003933 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003934 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003935
3936 /* back to a zero based len */
3937 i--;
3938 l--;
3939
3940 /* check against the string len */
3941 if (l > 1024) {
3942 l = xmlStrlen(str->stringval);
3943 }
3944 if (i < 0) {
3945 i = 0;
3946 }
3947
3948 /* number of chars to copy */
3949 l -= i;
3950
3951 ret = xmlStrsub(str->stringval, i, l);
3952 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00003953 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003954 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003955 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003956 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003957 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003958 xmlXPathFreeObject(str);
3959}
3960
3961/**
3962 * xmlXPathSubstringBeforeFunction:
3963 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003964 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003965 *
3966 * Implement the substring-before() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003967 * string substring-before(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003968 * The substring-before function returns the substring of the first
3969 * argument string that precedes the first occurrence of the second
3970 * argument string in the first argument string, or the empty string
3971 * if the first argument string does not contain the second argument
3972 * string. For example, substring-before("1999/04/01","/") returns 1999.
3973 */
3974void
3975xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00003976 xmlXPathObjectPtr str;
3977 xmlXPathObjectPtr find;
3978 xmlBufferPtr target;
3979 const xmlChar *point;
3980 int offset;
3981
3982 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003983 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003984 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003985 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00003986 str = valuePop(ctxt);
3987
3988 target = xmlBufferCreate();
3989 if (target) {
3990 point = xmlStrstr(str->stringval, find->stringval);
3991 if (point) {
3992 offset = (int)(point - str->stringval);
3993 xmlBufferAdd(target, str->stringval, offset);
3994 }
3995 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3996 xmlBufferFree(target);
3997 }
3998
3999 xmlXPathFreeObject(str);
4000 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004001}
4002
4003/**
4004 * xmlXPathSubstringAfterFunction:
4005 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004006 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004007 *
4008 * Implement the substring-after() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004009 * string substring-after(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004010 * The substring-after function returns the substring of the first
4011 * argument string that follows the first occurrence of the second
4012 * argument string in the first argument string, or the empty stringi
4013 * if the first argument string does not contain the second argument
4014 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4015 * and substring-after("1999/04/01","19") returns 99/04/01.
4016 */
4017void
4018xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004019 xmlXPathObjectPtr str;
4020 xmlXPathObjectPtr find;
4021 xmlBufferPtr target;
4022 const xmlChar *point;
4023 int offset;
4024
4025 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004026 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004027 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004028 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004029 str = valuePop(ctxt);
4030
4031 target = xmlBufferCreate();
4032 if (target) {
4033 point = xmlStrstr(str->stringval, find->stringval);
4034 if (point) {
4035 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4036 xmlBufferAdd(target, &str->stringval[offset],
4037 xmlStrlen(str->stringval) - offset);
4038 }
4039 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4040 xmlBufferFree(target);
4041 }
4042
4043 xmlXPathFreeObject(str);
4044 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004045}
4046
4047/**
4048 * xmlXPathNormalizeFunction:
4049 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004050 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004051 *
Daniel Veillard767662d2000-10-27 17:04:52 +00004052 * Implement the normalize-space() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004053 * string normalize-space(string?)
Daniel Veillard767662d2000-10-27 17:04:52 +00004054 * The normalize-space function returns the argument string with white
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004055 * space normalized by stripping leading and trailing whitespace
4056 * and replacing sequences of whitespace characters by a single
4057 * space. Whitespace characters are the same allowed by the S production
4058 * in XML. If the argument is omitted, it defaults to the context
4059 * node converted to a string, in other words the value of the context node.
4060 */
4061void
4062xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004063 xmlXPathObjectPtr obj = NULL;
4064 xmlChar *source = NULL;
4065 xmlBufferPtr target;
4066 xmlChar blank;
4067
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004068 if (nargs == 0) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004069 /* Use current context node */
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004070 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4071 xmlXPathStringFunction(ctxt, 1);
4072 nargs = 1;
Daniel Veillard46057e12000-09-24 18:49:59 +00004073 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004074
4075 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004076 CAST_TO_STRING;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004077 CHECK_TYPE(XPATH_STRING);
4078 obj = valuePop(ctxt);
4079 source = obj->stringval;
4080
Daniel Veillard46057e12000-09-24 18:49:59 +00004081 target = xmlBufferCreate();
4082 if (target && source) {
4083
4084 /* Skip leading whitespaces */
4085 while (IS_BLANK(*source))
4086 source++;
4087
4088 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4089 blank = 0;
4090 while (*source) {
4091 if (IS_BLANK(*source)) {
4092 blank = *source;
4093 } else {
4094 if (blank) {
4095 xmlBufferAdd(target, &blank, 1);
4096 blank = 0;
4097 }
4098 xmlBufferAdd(target, source, 1);
4099 }
4100 source++;
4101 }
4102
4103 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4104 xmlBufferFree(target);
4105 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004106 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004107}
4108
4109/**
4110 * xmlXPathTranslateFunction:
4111 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004112 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004113 *
4114 * Implement the translate() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004115 * string translate(string, string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004116 * The translate function returns the first argument string with
4117 * occurrences of characters in the second argument string replaced
4118 * by the character at the corresponding position in the third argument
4119 * string. For example, translate("bar","abc","ABC") returns the string
4120 * BAr. If there is a character in the second argument string with no
4121 * character at a corresponding position in the third argument string
4122 * (because the second argument string is longer than the third argument
4123 * string), then occurrences of that character in the first argument
4124 * string are removed. For example, translate("--aaa--","abc-","ABC")
4125 * returns "AAA". If a character occurs more than once in second
4126 * argument string, then the first occurrence determines the replacement
4127 * character. If the third argument string is longer than the second
4128 * argument string, then excess characters are ignored.
4129 */
4130void
4131xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004132 xmlXPathObjectPtr str;
4133 xmlXPathObjectPtr from;
4134 xmlXPathObjectPtr to;
4135 xmlBufferPtr target;
4136 int i, offset, max;
4137 xmlChar ch;
4138 const xmlChar *point;
4139
4140 CHECK_ARITY(3);
4141
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004142 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004143 to = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004144 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004145 from = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004146 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004147 str = valuePop(ctxt);
4148
4149 target = xmlBufferCreate();
4150 if (target) {
4151 max = xmlStrlen(to->stringval);
4152 for (i = 0; (ch = str->stringval[i]); i++) {
4153 point = xmlStrchr(from->stringval, ch);
4154 if (point) {
4155 /* Warning: This may not work with UTF-8 */
4156 offset = (int)(point - from->stringval);
4157 if (offset < max)
4158 xmlBufferAdd(target, &to->stringval[offset], 1);
4159 } else
4160 xmlBufferAdd(target, &ch, 1);
4161 }
4162 }
4163 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4164 xmlBufferFree(target);
4165 xmlXPathFreeObject(str);
4166 xmlXPathFreeObject(from);
4167 xmlXPathFreeObject(to);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004168}
4169
4170/**
4171 * xmlXPathBooleanFunction:
4172 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004173 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004174 *
4175 * Implement the boolean() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004176 * boolean boolean(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004177 * he boolean function converts its argument to a boolean as follows:
4178 * - a number is true if and only if it is neither positive or
4179 * negative zero nor NaN
4180 * - a node-set is true if and only if it is non-empty
4181 * - a string is true if and only if its length is non-zero
4182 */
4183void
4184xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4185 xmlXPathObjectPtr cur;
4186 int res = 0;
4187
4188 CHECK_ARITY(1);
4189 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004190 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004191 switch (cur->type) {
4192 case XPATH_NODESET:
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00004193 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004194 if ((cur->nodesetval == NULL) ||
4195 (cur->nodesetval->nodeNr == 0)) res = 0;
4196 else
4197 res = 1;
4198 break;
4199 case XPATH_STRING:
4200 if ((cur->stringval == NULL) ||
4201 (cur->stringval[0] == 0)) res = 0;
4202 else
4203 res = 1;
4204 break;
4205 case XPATH_BOOLEAN:
4206 valuePush(ctxt, cur);
4207 return;
4208 case XPATH_NUMBER:
4209 if (cur->floatval) res = 1;
4210 break;
4211 default:
4212 STRANGE
4213 }
4214 xmlXPathFreeObject(cur);
4215 valuePush(ctxt, xmlXPathNewBoolean(res));
4216}
4217
4218/**
4219 * xmlXPathNotFunction:
4220 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004221 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004222 *
4223 * Implement the not() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004224 * boolean not(boolean)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004225 * The not function returns true if its argument is false,
4226 * and false otherwise.
4227 */
4228void
4229xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4230 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004231 CAST_TO_BOOLEAN;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004232 CHECK_TYPE(XPATH_BOOLEAN);
4233 ctxt->value->boolval = ! ctxt->value->boolval;
4234}
4235
4236/**
4237 * xmlXPathTrueFunction:
4238 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004239 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004240 *
4241 * Implement the true() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004242 * boolean true()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004243 */
4244void
4245xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4246 CHECK_ARITY(0);
4247 valuePush(ctxt, xmlXPathNewBoolean(1));
4248}
4249
4250/**
4251 * xmlXPathFalseFunction:
4252 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004253 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004254 *
4255 * Implement the false() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004256 * boolean false()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004257 */
4258void
4259xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4260 CHECK_ARITY(0);
4261 valuePush(ctxt, xmlXPathNewBoolean(0));
4262}
4263
4264/**
4265 * xmlXPathLangFunction:
4266 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004267 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004268 *
4269 * Implement the lang() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004270 * boolean lang(string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004271 * The lang function returns true or false depending on whether the
4272 * language of the context node as specified by xml:lang attributes
4273 * is the same as or is a sublanguage of the language specified by
4274 * the argument string. The language of the context node is determined
4275 * by the value of the xml:lang attribute on the context node, or, if
4276 * the context node has no xml:lang attribute, by the value of the
4277 * xml:lang attribute on the nearest ancestor of the context node that
4278 * has an xml:lang attribute. If there is no such attribute, then lang
4279 * returns false. If there is such an attribute, then lang returns
4280 * true if the attribute value is equal to the argument ignoring case,
4281 * or if there is some suffix starting with - such that the attribute
4282 * value is equal to the argument ignoring that suffix of the attribute
4283 * value and ignoring case.
4284 */
4285void
4286xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004287 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004288 const xmlChar *theLang;
4289 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004290 int ret = 0;
4291 int i;
4292
4293 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004294 CAST_TO_STRING;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004295 CHECK_TYPE(XPATH_STRING);
4296 val = valuePop(ctxt);
4297 lang = val->stringval;
4298 theLang = xmlNodeGetLang(ctxt->context->node);
4299 if ((theLang != NULL) && (lang != NULL)) {
4300 for (i = 0;lang[i] != 0;i++)
4301 if (toupper(lang[i]) != toupper(theLang[i]))
4302 goto not_equal;
4303 ret = 1;
4304 }
4305not_equal:
4306 xmlXPathFreeObject(val);
4307 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004308}
4309
4310/**
4311 * xmlXPathNumberFunction:
4312 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004313 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004314 *
4315 * Implement the number() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004316 * number number(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004317 */
4318void
4319xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4320 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004321 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004322
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004323 if (nargs == 0) {
4324 if (ctxt->context->node == NULL) {
4325 valuePush(ctxt, xmlXPathNewFloat(0.0));
4326 } else {
4327 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4328
4329 res = xmlXPathStringEvalNumber(content);
4330 valuePush(ctxt, xmlXPathNewFloat(res));
4331 xmlFree(content);
4332 }
4333 return;
4334 }
4335
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004336 CHECK_ARITY(1);
4337 cur = valuePop(ctxt);
4338 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00004339 case XPATH_UNDEFINED:
4340#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004341 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00004342#endif
4343 valuePush(ctxt, xmlXPathNewFloat(0.0));
4344 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00004345 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004346 case XPATH_NODESET:
4347 valuePush(ctxt, cur);
4348 xmlXPathStringFunction(ctxt, 1);
4349 cur = valuePop(ctxt);
4350 case XPATH_STRING:
4351 res = xmlXPathStringEvalNumber(cur->stringval);
4352 valuePush(ctxt, xmlXPathNewFloat(res));
4353 xmlXPathFreeObject(cur);
4354 return;
4355 case XPATH_BOOLEAN:
4356 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
4357 else valuePush(ctxt, xmlXPathNewFloat(0.0));
4358 xmlXPathFreeObject(cur);
4359 return;
4360 case XPATH_NUMBER:
4361 valuePush(ctxt, cur);
4362 return;
Daniel Veillard740abf52000-10-02 23:04:54 +00004363 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00004364 case XPATH_POINT:
4365 case XPATH_RANGE:
4366 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00004367 TODO
4368 valuePush(ctxt, xmlXPathNewFloat(0.0));
4369 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004370 }
4371 STRANGE
4372}
4373
4374/**
4375 * xmlXPathSumFunction:
4376 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004377 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004378 *
4379 * Implement the sum() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004380 * number sum(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004381 * The sum function returns the sum of the values of the nodes in
4382 * the argument node-set.
4383 */
4384void
4385xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004386 xmlXPathObjectPtr cur;
4387 int i;
4388
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004389 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00004390 if ((ctxt->value == NULL) ||
4391 ((ctxt->value->type != XPATH_NODESET) &&
4392 (ctxt->value->type != XPATH_XSLT_TREE)))
4393 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004394 cur = valuePop(ctxt);
4395
4396 if (cur->nodesetval->nodeNr == 0) {
4397 valuePush(ctxt, xmlXPathNewFloat(0.0));
4398 } else {
4399 valuePush(ctxt,
4400 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
Daniel Veillard767662d2000-10-27 17:04:52 +00004401 xmlXPathNumberFunction(ctxt, 1);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004402 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4403 valuePush(ctxt,
4404 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4405 xmlXPathAddValues(ctxt);
4406 }
4407 }
4408 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004409}
4410
4411/**
4412 * xmlXPathFloorFunction:
4413 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004414 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004415 *
4416 * Implement the floor() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004417 * number floor(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004418 * The floor function returns the largest (closest to positive infinity)
4419 * number that is not greater than the argument and that is an integer.
4420 */
4421void
4422xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4423 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004424 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004425 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004426#if 0
4427 ctxt->value->floatval = floor(ctxt->value->floatval);
4428#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004429 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004430 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004431#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004432}
4433
4434/**
4435 * xmlXPathCeilingFunction:
4436 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004437 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004438 *
4439 * Implement the ceiling() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004440 * number ceiling(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004441 * The ceiling function returns the smallest (closest to negative infinity)
4442 * number that is not less than the argument and that is an integer.
4443 */
4444void
4445xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004446 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004447
4448 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004449 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004450 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004451
4452#if 0
4453 ctxt->value->floatval = ceil(ctxt->value->floatval);
4454#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004455 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004456 if (f != ctxt->value->floatval)
4457 ctxt->value->floatval = f + 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004458#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004459}
4460
4461/**
4462 * xmlXPathRoundFunction:
4463 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004464 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004465 *
4466 * Implement the round() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004467 * number round(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004468 * The round function returns the number that is closest to the
4469 * argument and that is an integer. If there are two such numbers,
4470 * then the one that is even is returned.
4471 */
4472void
4473xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004474 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004475
4476 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004477 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004478 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004479
4480 if ((ctxt->value->floatval == xmlXPathNAN) ||
4481 (ctxt->value->floatval == xmlXPathPINF) ||
4482 (ctxt->value->floatval == xmlXPathNINF) ||
4483 (ctxt->value->floatval == 0.0))
4484 return;
4485
4486#if 0
4487 f = floor(ctxt->value->floatval);
4488#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004489 f = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004490#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004491 if (ctxt->value->floatval < f + 0.5)
4492 ctxt->value->floatval = f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004493 else
4494 ctxt->value->floatval = f + 1;
4495}
4496
4497/************************************************************************
4498 * *
4499 * The Parser *
4500 * *
4501 ************************************************************************/
4502
4503/*
4504 * a couple of forward declarations since we use a recursive call based
4505 * implementation.
4506 */
4507void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
4508void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
4509void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004510#ifdef VMS
4511void xmlXPathEvalRelLocationPath(xmlXPathParserContextPtr ctxt);
4512#define xmlXPathEvalRelativeLocationPath xmlXPathEvalRelLocationPath
4513#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004514void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004515#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004516
4517/**
4518 * xmlXPathParseNCName:
4519 * @ctxt: the XPath Parser context
4520 *
4521 * parse an XML namespace non qualified name.
4522 *
4523 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
4524 *
4525 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
4526 * CombiningChar | Extender
4527 *
4528 * Returns the namespace name or NULL
4529 */
4530
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004531xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004532xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004533 const xmlChar *q;
4534 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004535
4536 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4537 q = NEXT;
4538
4539 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4540 (CUR == '.') || (CUR == '-') ||
4541 (CUR == '_') ||
4542 (IS_COMBINING(CUR)) ||
4543 (IS_EXTENDER(CUR)))
4544 NEXT;
4545
4546 ret = xmlStrndup(q, CUR_PTR - q);
4547
4548 return(ret);
4549}
4550
4551/**
4552 * xmlXPathParseQName:
4553 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004554 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004555 *
4556 * parse an XML qualified name
4557 *
4558 * [NS 5] QName ::= (Prefix ':')? LocalPart
4559 *
4560 * [NS 6] Prefix ::= NCName
4561 *
4562 * [NS 7] LocalPart ::= NCName
4563 *
4564 * Returns the function returns the local part, and prefix is updated
4565 * to get the Prefix if any.
4566 */
4567
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004568xmlChar *
4569xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
4570 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004571
4572 *prefix = NULL;
4573 ret = xmlXPathParseNCName(ctxt);
4574 if (CUR == ':') {
4575 *prefix = ret;
4576 NEXT;
4577 ret = xmlXPathParseNCName(ctxt);
4578 }
4579 return(ret);
4580}
4581
4582/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00004583 * xmlXPathParseName:
Daniel Veillardf6eea272001-01-18 12:17:12 +00004584 * @ctxt: the XPath Parser context
Daniel Veillard2d38f042000-10-11 10:54:10 +00004585 *
4586 * parse an XML name
4587 *
4588 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4589 * CombiningChar | Extender
4590 *
4591 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4592 *
4593 * Returns the namespace name or NULL
4594 */
4595
4596xmlChar *
4597xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
4598 const xmlChar *q;
4599 xmlChar *ret = NULL;
4600
4601 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4602 q = NEXT;
4603
4604 /* TODO Make this UTF8 compliant !!! */
4605 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4606 (CUR == '.') || (CUR == '-') ||
4607 (CUR == '_') || (CUR == ':') ||
4608 (IS_COMBINING(CUR)) ||
4609 (IS_EXTENDER(CUR)))
4610 NEXT;
4611
4612 ret = xmlStrndup(q, CUR_PTR - q);
4613
4614 return(ret);
4615}
4616
4617/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004618 * xmlXPathStringEvalNumber:
4619 * @str: A string to scan
4620 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004621 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004622 * | '.' Digits
4623 * [31] Digits ::= [0-9]+
4624 *
4625 * Parse and evaluate a Number in the string
Daniel Veillard767662d2000-10-27 17:04:52 +00004626 * In complement of the Number expression, this function also handles
4627 * negative values : '-' Number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004628 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004629 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004630 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004631double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004632xmlXPathStringEvalNumber(const xmlChar *str) {
4633 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004634 double ret = 0.0;
4635 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004636 int ok = 0;
Daniel Veillard767662d2000-10-27 17:04:52 +00004637 int isneg = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004638
4639 while (*cur == ' ') cur++;
Daniel Veillard767662d2000-10-27 17:04:52 +00004640 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004641 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004642 }
Daniel Veillard767662d2000-10-27 17:04:52 +00004643 if (*cur == '-') {
4644 isneg = 1;
4645 cur++;
4646 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004647 while ((*cur >= '0') && (*cur <= '9')) {
4648 ret = ret * 10 + (*cur - '0');
4649 ok = 1;
4650 cur++;
4651 }
4652 if (*cur == '.') {
4653 cur++;
4654 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004655 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004656 }
4657 while ((*cur >= '0') && (*cur <= '9')) {
4658 mult /= 10;
4659 ret = ret + (*cur - '0') * mult;
4660 cur++;
4661 }
4662 }
4663 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004664 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard767662d2000-10-27 17:04:52 +00004665 if (isneg) ret = -ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004666 return(ret);
4667}
4668
4669/**
4670 * xmlXPathEvalNumber:
4671 * @ctxt: the XPath Parser context
4672 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004673 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004674 * | '.' Digits
4675 * [31] Digits ::= [0-9]+
4676 *
4677 * Parse and evaluate a Number, then push it on the stack
4678 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004679 */
4680void
4681xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004682 double ret = 0.0;
4683 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004684 int ok = 0;
4685
4686 CHECK_ERROR;
4687 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004688 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004689 }
4690 while ((CUR >= '0') && (CUR <= '9')) {
4691 ret = ret * 10 + (CUR - '0');
4692 ok = 1;
4693 NEXT;
4694 }
4695 if (CUR == '.') {
4696 NEXT;
4697 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004698 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004699 }
4700 while ((CUR >= '0') && (CUR <= '9')) {
4701 mult /= 10;
4702 ret = ret + (CUR - '0') * mult;
4703 NEXT;
4704 }
4705 }
4706 valuePush(ctxt, xmlXPathNewFloat(ret));
4707}
4708
4709/**
4710 * xmlXPathEvalLiteral:
4711 * @ctxt: the XPath Parser context
4712 *
4713 * Parse a Literal and push it on the stack.
4714 *
4715 * [29] Literal ::= '"' [^"]* '"'
4716 * | "'" [^']* "'"
4717 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004718 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004719 */
4720void
4721xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004722 const xmlChar *q;
4723 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004724
4725 if (CUR == '"') {
4726 NEXT;
4727 q = CUR_PTR;
4728 while ((IS_CHAR(CUR)) && (CUR != '"'))
4729 NEXT;
4730 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004731 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004732 } else {
4733 ret = xmlStrndup(q, CUR_PTR - q);
4734 NEXT;
4735 }
4736 } else if (CUR == '\'') {
4737 NEXT;
4738 q = CUR_PTR;
4739 while ((IS_CHAR(CUR)) && (CUR != '\''))
4740 NEXT;
4741 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004742 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004743 } else {
4744 ret = xmlStrndup(q, CUR_PTR - q);
4745 NEXT;
4746 }
4747 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004748 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004749 }
4750 if (ret == NULL) return;
4751 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004752 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004753}
4754
4755/**
4756 * xmlXPathEvalVariableReference:
4757 * @ctxt: the XPath Parser context
4758 *
4759 * Parse a VariableReference, evaluate it and push it on the stack.
4760 *
4761 * The variable bindings consist of a mapping from variable names
4762 * to variable values. The value of a variable is an object, which
4763 * of any of the types that are possible for the value of an expression,
4764 * and may also be of additional types not specified here.
4765 *
4766 * Early evaluation is possible since:
4767 * The variable bindings [...] used to evaluate a subexpression are
4768 * always the same as those used to evaluate the containing expression.
4769 *
4770 * [36] VariableReference ::= '$' QName
4771 */
4772void
4773xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004774 xmlChar *name;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004775 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004776 xmlXPathObjectPtr value;
4777
Daniel Veillard55b91f22000-10-05 16:30:11 +00004778 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004779 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004780 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004781 }
Daniel Veillard5a2b6972001-01-20 21:15:50 +00004782 NEXT;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004783 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004784 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004785 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004786 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004787 if (prefix == NULL) {
4788 value = xmlXPathVariableLookup(ctxt->context, name);
4789 } else {
4790 TODO;
4791 value = NULL;
4792 }
4793 xmlFree(name);
4794 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004795 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004796 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004797 }
4798 valuePush(ctxt, value);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004799 SKIP_BLANKS;
4800}
4801
4802/**
4803 * xmlXPathIsNodeType:
4804 * @ctxt: the XPath Parser context
4805 * @name: a name string
4806 *
4807 * Is the name given a NodeType one.
4808 *
4809 * [38] NodeType ::= 'comment'
4810 * | 'text'
4811 * | 'processing-instruction'
4812 * | 'node'
4813 *
4814 * Returns 1 if true 0 otherwise
4815 */
4816int
4817xmlXPathIsNodeType(const xmlChar *name) {
4818 if (name == NULL)
4819 return(0);
4820
4821 if (xmlStrEqual(name, BAD_CAST "comment"))
4822 return(1);
4823 if (xmlStrEqual(name, BAD_CAST "text"))
4824 return(1);
4825 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4826 return(1);
4827 if (xmlStrEqual(name, BAD_CAST "node"))
4828 return(1);
4829 return(0);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004830}
4831
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004832/**
4833 * xmlXPathEvalFunctionCall:
4834 * @ctxt: the XPath Parser context
4835 *
4836 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4837 * [17] Argument ::= Expr
4838 *
4839 * Parse and evaluate a function call, the evaluation of all arguments are
4840 * pushed on the stack
4841 */
4842void
4843xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004844 xmlChar *name;
4845 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004846 xmlXPathFunction func;
4847 int nbargs = 0;
4848
4849 name = xmlXPathParseQName(ctxt, &prefix);
4850 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004851 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004852 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004853 SKIP_BLANKS;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004854 if (prefix == NULL) {
4855 func = xmlXPathFunctionLookup(ctxt->context, name);
4856 } else {
4857 TODO;
4858 func = NULL;
4859 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004860 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004861 xmlFree(name);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004862 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004863 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004864 }
4865#ifdef DEBUG_EXPR
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004866 if (prefix == NULL)
4867 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
4868 name);
4869 else
4870 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
4871 prefix, name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004872#endif
4873
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004874 xmlFree(name);
4875 if (prefix != NULL) xmlFree(prefix);
4876
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004877 if (CUR != '(') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004878 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004879 }
4880 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004881 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004882
4883 while (CUR != ')') {
4884 xmlXPathEvalExpr(ctxt);
4885 nbargs++;
4886 if (CUR == ')') break;
4887 if (CUR != ',') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004888 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004889 }
4890 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004891 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004892 }
4893 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004894 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004895 func(ctxt, nbargs);
4896}
4897
4898/**
4899 * xmlXPathEvalPrimaryExpr:
4900 * @ctxt: the XPath Parser context
4901 *
4902 * [15] PrimaryExpr ::= VariableReference
4903 * | '(' Expr ')'
4904 * | Literal
4905 * | Number
4906 * | FunctionCall
4907 *
4908 * Parse and evaluate a primary expression, then push the result on the stack
4909 */
4910void
4911xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004912 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004913 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4914 else if (CUR == '(') {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004915 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004916 SKIP_BLANKS;
Daniel Veillard55b91f22000-10-05 16:30:11 +00004917 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004918 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004919 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004920 }
4921 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004922 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004923 } else if (IS_DIGIT(CUR)) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004924 xmlXPathEvalNumber(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004925 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004926 xmlXPathEvalLiteral(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004927 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004928 xmlXPathEvalFunctionCall(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004929 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004930 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004931}
4932
4933/**
4934 * xmlXPathEvalFilterExpr:
4935 * @ctxt: the XPath Parser context
4936 *
4937 * [20] FilterExpr ::= PrimaryExpr
4938 * | FilterExpr Predicate
4939 *
4940 * Parse and evaluate a filter expression, then push the result on the stack
4941 * Square brackets are used to filter expressions in the same way that
4942 * they are used in location paths. It is an error if the expression to
4943 * be filtered does not evaluate to a node-set. The context node list
4944 * used for evaluating the expression in square brackets is the node-set
4945 * to be filtered listed in document order.
4946 */
4947
4948void
4949xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004950 xmlXPathEvalPrimaryExpr(ctxt);
4951 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004952 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004953
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004954 while (CUR == '[') {
Daniel Veillardf62ceff2000-11-24 23:36:01 +00004955 if ((ctxt->value == NULL) ||
4956 ((ctxt->value->type != XPATH_NODESET) &&
4957 (ctxt->value->type != XPATH_LOCATIONSET)))
4958 XP_ERROR(XPATH_INVALID_TYPE)
4959
4960 if (ctxt->value->type == XPATH_NODESET)
4961 xmlXPathEvalPredicate(ctxt);
4962 else
4963 xmlXPtrEvalRangePredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004964 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004965 }
4966
4967
4968}
4969
4970/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00004971 * xmlXPathScanName:
4972 * @ctxt: the XPath Parser context
4973 *
4974 * Trickery: parse an XML name but without consuming the input flow
Daniel Veillard55b91f22000-10-05 16:30:11 +00004975 * Needed to avoid insanity in the parser state.
Daniel Veillardb96e6431999-08-29 21:02:19 +00004976 *
4977 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4978 * CombiningChar | Extender
4979 *
4980 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4981 *
4982 * [6] Names ::= Name (S Name)*
4983 *
4984 * Returns the Name parsed or NULL
4985 */
4986
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004987xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004988xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004989 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00004990 int len = 0;
4991
Daniel Veillard00fdf371999-10-08 09:40:39 +00004992 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004993 if (!IS_LETTER(CUR) && (CUR != '_') &&
4994 (CUR != ':')) {
4995 return(NULL);
4996 }
4997
4998 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4999 (NXT(len) == '.') || (NXT(len) == '-') ||
5000 (NXT(len) == '_') || (NXT(len) == ':') ||
5001 (IS_COMBINING(NXT(len))) ||
5002 (IS_EXTENDER(NXT(len)))) {
5003 buf[len] = NXT(len);
5004 len++;
5005 if (len >= XML_MAX_NAMELEN) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005006 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardb96e6431999-08-29 21:02:19 +00005007 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5008 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5009 (NXT(len) == '.') || (NXT(len) == '-') ||
5010 (NXT(len) == '_') || (NXT(len) == ':') ||
5011 (IS_COMBINING(NXT(len))) ||
5012 (IS_EXTENDER(NXT(len))))
5013 len++;
5014 break;
5015 }
5016 }
5017 return(xmlStrndup(buf, len));
5018}
5019
5020/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005021 * xmlXPathEvalPathExpr:
5022 * @ctxt: the XPath Parser context
5023 *
5024 * [19] PathExpr ::= LocationPath
5025 * | FilterExpr
5026 * | FilterExpr '/' RelativeLocationPath
5027 * | FilterExpr '//' RelativeLocationPath
5028 *
5029 * Parse and evaluate a path expression, then push the result on the stack
5030 * The / operator and // operators combine an arbitrary expression
5031 * and a relative location path. It is an error if the expression
5032 * does not evaluate to a node-set.
5033 * The / operator does composition in the same way as when / is
5034 * used in a location path. As in location paths, // is short for
5035 * /descendant-or-self::node()/.
5036 */
5037
5038void
5039xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005040 int lc = 1; /* Should we branch to LocationPath ? */
5041 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5042
Daniel Veillard00fdf371999-10-08 09:40:39 +00005043 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005044 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5045 (CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005046 lc = 0;
5047 } else if (CUR == '/') {
5048 /* relative or absolute location path */
5049 lc = 1;
5050 } else if (CUR == '@') {
5051 /* relative abbreviated attribute location path */
5052 lc = 1;
5053 } else if (CUR == '.') {
5054 /* relative abbreviated attribute location path */
5055 lc = 1;
5056 } else {
5057 /*
5058 * Problem is finding if we have a name here whether it's:
5059 * - a nodetype
5060 * - a function call in which case it's followed by '('
5061 * - an axis in which case it's followed by ':'
5062 * - a element name
5063 * We do an a priori analysis here rather than having to
5064 * maintain parsed token content through the recursive function
5065 * calls. This looks uglier but makes the code quite easier to
5066 * read/write/debug.
5067 */
5068 SKIP_BLANKS;
5069 name = xmlXPathScanName(ctxt);
5070 if (name != NULL) {
5071 int len =xmlStrlen(name);
5072 int blank = 0;
5073
5074 while (NXT(len) != 0) {
5075 if (NXT(len) == '/') {
5076 /* element name */
5077#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005078 xmlGenericError(xmlGenericErrorContext,
5079 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005080#endif
5081 lc = 1;
5082 break;
5083 } else if (IS_BLANK(NXT(len))) {
5084 /* skip to next */
5085 blank = 1;
5086 } else if (NXT(len) == ':') {
5087#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005088 xmlGenericError(xmlGenericErrorContext,
5089 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005090#endif
5091 lc = 1;
5092 break;
5093 } else if ((NXT(len) == '(')) {
5094 /* Note Type or Function */
5095 if (xmlXPathIsNodeType(name)) {
5096#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005097 xmlGenericError(xmlGenericErrorContext,
5098 "PathExpr: Type search\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005099#endif
5100 lc = 1;
5101 } else {
5102#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005103 xmlGenericError(xmlGenericErrorContext,
5104 "PathExpr: function call\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005105#endif
5106 lc = 0;
5107 }
5108 break;
5109 } else if ((NXT(len) == '[')) {
5110 /* element name */
5111#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005112 xmlGenericError(xmlGenericErrorContext,
5113 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005114#endif
5115 lc = 1;
5116 break;
Daniel Veillard389e6b72001-01-15 19:41:13 +00005117 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5118 (NXT(len) == '=')) {
5119 lc = 1;
5120 break;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005121 } else {
Daniel Veillardf6eea272001-01-18 12:17:12 +00005122 lc = 1;
5123 break;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005124 }
5125 len++;
5126 }
5127 if (NXT(len) == 0) {
5128#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005129 xmlGenericError(xmlGenericErrorContext,
5130 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005131#endif
5132 /* element name */
5133 lc = 1;
5134 }
5135 xmlFree(name);
5136 } else {
5137 /* make sure all cases are covered explicitely */
5138 XP_ERROR(XPATH_EXPR_ERROR);
5139 }
5140 }
5141
5142 if (lc) {
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00005143 if (CUR == '/')
5144 xmlXPathRoot(ctxt);
Daniel Veillard5a2b6972001-01-20 21:15:50 +00005145 else {
5146 /* TAG:9999 */
5147 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5148 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005149 xmlXPathEvalLocationPath(ctxt);
5150 } else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005151 xmlXPathEvalFilterExpr(ctxt);
5152 CHECK_ERROR;
5153 if ((CUR == '/') && (NXT(1) == '/')) {
5154 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005155 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005156 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00005157 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005158 ctxt->context->node = NULL;
5159 xmlXPathEvalRelativeLocationPath(ctxt);
5160 } else if (CUR == '/') {
5161 xmlXPathEvalRelativeLocationPath(ctxt);
5162 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005163 }
5164 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005165}
5166
5167/**
5168 * xmlXPathEvalUnionExpr:
5169 * @ctxt: the XPath Parser context
5170 *
5171 * [18] UnionExpr ::= PathExpr
5172 * | UnionExpr '|' PathExpr
5173 *
5174 * Parse and evaluate an union expression, then push the result on the stack
5175 */
5176
5177void
5178xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
5179 xmlXPathEvalPathExpr(ctxt);
5180 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005181 SKIP_BLANKS;
Daniel Veillard08108982001-01-03 15:24:58 +00005182 while (CUR == '|') {
5183 xmlXPathObjectPtr obj1,obj2, tmp;
Daniel Veillard740abf52000-10-02 23:04:54 +00005184
5185 CHECK_TYPE(XPATH_NODESET);
5186 obj1 = valuePop(ctxt);
Daniel Veillard08108982001-01-03 15:24:58 +00005187 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5188 valuePush(ctxt, tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005189
Daniel Veillard00fdf371999-10-08 09:40:39 +00005190 NEXT;
5191 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005192 xmlXPathEvalPathExpr(ctxt);
5193
Daniel Veillard740abf52000-10-02 23:04:54 +00005194 CHECK_TYPE(XPATH_NODESET);
5195 obj2 = valuePop(ctxt);
5196 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
5197 obj2->nodesetval);
Daniel Veillard08108982001-01-03 15:24:58 +00005198 if (ctxt->value == tmp) {
5199 tmp = valuePop(ctxt);
5200 xmlXPathFreeObject(tmp);
5201 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005202 valuePush(ctxt, obj1);
Daniel Veillard740abf52000-10-02 23:04:54 +00005203 xmlXPathFreeObject(obj2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005204 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005205 }
5206}
5207
5208/**
5209 * xmlXPathEvalUnaryExpr:
5210 * @ctxt: the XPath Parser context
5211 *
5212 * [27] UnaryExpr ::= UnionExpr
5213 * | '-' UnaryExpr
5214 *
5215 * Parse and evaluate an unary expression, then push the result on the stack
5216 */
5217
5218void
5219xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
5220 int minus = 0;
5221
Daniel Veillard00fdf371999-10-08 09:40:39 +00005222 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005223 if (CUR == '-') {
5224 minus = 1;
5225 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005226 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005227 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005228 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005229 CHECK_ERROR;
5230 if (minus) {
5231 xmlXPathValueFlipSign(ctxt);
5232 }
5233}
5234
5235/**
5236 * xmlXPathEvalMultiplicativeExpr:
5237 * @ctxt: the XPath Parser context
5238 *
5239 * [26] MultiplicativeExpr ::= UnaryExpr
5240 * | MultiplicativeExpr MultiplyOperator UnaryExpr
5241 * | MultiplicativeExpr 'div' UnaryExpr
5242 * | MultiplicativeExpr 'mod' UnaryExpr
5243 * [34] MultiplyOperator ::= '*'
5244 *
5245 * Parse and evaluate an Additive expression, then push the result on the stack
5246 */
5247
5248void
5249xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
5250 xmlXPathEvalUnaryExpr(ctxt);
5251 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005252 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005253 while ((CUR == '*') ||
5254 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
5255 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
5256 int op = -1;
5257
5258 if (CUR == '*') {
5259 op = 0;
5260 NEXT;
5261 } else if (CUR == 'd') {
5262 op = 1;
5263 SKIP(3);
5264 } else if (CUR == 'm') {
5265 op = 2;
5266 SKIP(3);
5267 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005268 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005269 xmlXPathEvalUnaryExpr(ctxt);
5270 CHECK_ERROR;
5271 switch (op) {
5272 case 0:
5273 xmlXPathMultValues(ctxt);
5274 break;
5275 case 1:
5276 xmlXPathDivValues(ctxt);
5277 break;
5278 case 2:
5279 xmlXPathModValues(ctxt);
5280 break;
5281 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005282 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005283 }
5284}
5285
5286/**
5287 * xmlXPathEvalAdditiveExpr:
5288 * @ctxt: the XPath Parser context
5289 *
5290 * [25] AdditiveExpr ::= MultiplicativeExpr
5291 * | AdditiveExpr '+' MultiplicativeExpr
5292 * | AdditiveExpr '-' MultiplicativeExpr
5293 *
5294 * Parse and evaluate an Additive expression, then push the result on the stack
5295 */
5296
5297void
5298xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
5299 xmlXPathEvalMultiplicativeExpr(ctxt);
5300 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005301 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005302 while ((CUR == '+') || (CUR == '-')) {
5303 int plus;
5304
5305 if (CUR == '+') plus = 1;
5306 else plus = 0;
5307 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005308 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005309 xmlXPathEvalMultiplicativeExpr(ctxt);
5310 CHECK_ERROR;
5311 if (plus) xmlXPathAddValues(ctxt);
5312 else xmlXPathSubValues(ctxt);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005313 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005314 }
5315}
5316
5317/**
5318 * xmlXPathEvalRelationalExpr:
5319 * @ctxt: the XPath Parser context
5320 *
5321 * [24] RelationalExpr ::= AdditiveExpr
5322 * | RelationalExpr '<' AdditiveExpr
5323 * | RelationalExpr '>' AdditiveExpr
5324 * | RelationalExpr '<=' AdditiveExpr
5325 * | RelationalExpr '>=' AdditiveExpr
5326 *
5327 * A <= B > C is allowed ? Answer from James, yes with
5328 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
5329 * which is basically what got implemented.
5330 *
5331 * Parse and evaluate a Relational expression, then push the result
5332 * on the stack
5333 */
5334
5335void
5336xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
5337 xmlXPathEvalAdditiveExpr(ctxt);
5338 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005339 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005340 while ((CUR == '<') ||
5341 (CUR == '>') ||
5342 ((CUR == '<') && (NXT(1) == '=')) ||
5343 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00005344 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005345
5346 if (CUR == '<') inf = 1;
5347 else inf = 0;
5348 if (NXT(1) == '=') strict = 0;
5349 else strict = 1;
5350 NEXT;
5351 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005352 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005353 xmlXPathEvalAdditiveExpr(ctxt);
5354 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00005355 ret = xmlXPathCompareValues(ctxt, inf, strict);
5356 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard55b91f22000-10-05 16:30:11 +00005357 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005358 }
5359}
5360
5361/**
5362 * xmlXPathEvalEqualityExpr:
5363 * @ctxt: the XPath Parser context
5364 *
5365 * [23] EqualityExpr ::= RelationalExpr
5366 * | EqualityExpr '=' RelationalExpr
5367 * | EqualityExpr '!=' RelationalExpr
5368 *
5369 * A != B != C is allowed ? Answer from James, yes with
5370 * (RelationalExpr = RelationalExpr) = RelationalExpr
5371 * (RelationalExpr != RelationalExpr) != RelationalExpr
5372 * which is basically what got implemented.
5373 *
5374 * Parse and evaluate an Equality expression, then push the result on the stack
5375 *
5376 */
5377void
5378xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
5379 xmlXPathEvalRelationalExpr(ctxt);
5380 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005381 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005382 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00005383 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005384 int eq, equal;
5385
5386 if (CUR == '=') eq = 1;
5387 else eq = 0;
5388 NEXT;
5389 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005390 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005391 xmlXPathEvalRelationalExpr(ctxt);
5392 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00005393 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005394 if (eq) res = xmlXPathNewBoolean(equal);
5395 else res = xmlXPathNewBoolean(!equal);
5396 valuePush(ctxt, res);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005397 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005398 }
5399}
5400
5401/**
5402 * xmlXPathEvalAndExpr:
5403 * @ctxt: the XPath Parser context
5404 *
5405 * [22] AndExpr ::= EqualityExpr
5406 * | AndExpr 'and' EqualityExpr
5407 *
5408 * Parse and evaluate an AND expression, then push the result on the stack
5409 *
5410 */
5411void
5412xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
5413 xmlXPathEvalEqualityExpr(ctxt);
5414 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005415 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00005416 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005417 xmlXPathObjectPtr arg1, arg2;
5418
5419 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005420 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005421 xmlXPathEvalEqualityExpr(ctxt);
5422 CHECK_ERROR;
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005423 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005424 arg2 = valuePop(ctxt);
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005425 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005426 arg1 = valuePop(ctxt);
5427 arg1->boolval &= arg2->boolval;
5428 valuePush(ctxt, arg1);
5429 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005430 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005431 }
5432}
5433
5434/**
5435 * xmlXPathEvalExpr:
5436 * @ctxt: the XPath Parser context
5437 *
5438 * [14] Expr ::= OrExpr
5439 * [21] OrExpr ::= AndExpr
5440 * | OrExpr 'or' AndExpr
5441 *
5442 * Parse and evaluate an expression, then push the result on the stack
5443 *
5444 */
5445void
5446xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
5447 xmlXPathEvalAndExpr(ctxt);
5448 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005449 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005450 while ((CUR == 'o') && (NXT(1) == 'r')) {
5451 xmlXPathObjectPtr arg1, arg2;
5452
5453 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005454 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005455 xmlXPathEvalAndExpr(ctxt);
5456 CHECK_ERROR;
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005457 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005458 arg2 = valuePop(ctxt);
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005459 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005460 arg1 = valuePop(ctxt);
5461 arg1->boolval |= arg2->boolval;
5462 valuePush(ctxt, arg1);
5463 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005464 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005465 }
5466}
5467
5468/**
5469 * xmlXPathEvaluatePredicateResult:
5470 * @ctxt: the XPath Parser context
5471 * @res: the Predicate Expression evaluation result
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005472 *
5473 * Evaluate a predicate result for the current node.
5474 * A PredicateExpr is evaluated by evaluating the Expr and converting
5475 * the result to a boolean. If the result is a number, the result will
5476 * be converted to true if the number is equal to the position of the
5477 * context node in the context node list (as returned by the position
5478 * function) and will be converted to false otherwise; if the result
5479 * is not a number, then the result will be converted as if by a call
5480 * to the boolean function.
Daniel Veillard2c833b62001-02-03 08:52:06 +00005481 *
5482 * Return 1 if predicate is true, 0 otherwise
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005483 */
5484int
5485xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005486 xmlXPathObjectPtr res) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005487 if (res == NULL) return(0);
5488 switch (res->type) {
5489 case XPATH_BOOLEAN:
5490 return(res->boolval);
5491 case XPATH_NUMBER:
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005492 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005493 case XPATH_NODESET:
Daniel Veillarde99a4762001-02-01 04:34:35 +00005494 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005495 return(res->nodesetval->nodeNr != 0);
5496 case XPATH_STRING:
5497 return((res->stringval != NULL) &&
5498 (xmlStrlen(res->stringval) != 0));
5499 default:
5500 STRANGE
5501 }
5502 return(0);
5503}
5504
5505/**
5506 * xmlXPathEvalPredicate:
5507 * @ctxt: the XPath Parser context
5508 *
5509 * [8] Predicate ::= '[' PredicateExpr ']'
5510 * [9] PredicateExpr ::= Expr
5511 *
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005512 * ---------------------
5513 * For each node in the node-set to be filtered, the PredicateExpr is
5514 * evaluated with that node as the context node, with the number of nodes
5515 * in the node-set as the context size, and with the proximity position
5516 * of the node in the node-set with respect to the axis as the context
5517 * position; if PredicateExpr evaluates to true for that node, the node
5518 * is included in the new node-set; otherwise, it is not included.
5519 * ---------------------
5520 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005521 * Parse and evaluate a predicate for all the elements of the
5522 * current node list. Then refine the list by removing all
5523 * nodes where the predicate is false.
5524 */
5525void
5526xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005527 const xmlChar *cur;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005528 xmlXPathObjectPtr res;
Daniel Veillard740abf52000-10-02 23:04:54 +00005529 xmlXPathObjectPtr obj, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005530 xmlNodeSetPtr newset = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005531 xmlNodeSetPtr oldset;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005532 int i;
5533
Daniel Veillard00fdf371999-10-08 09:40:39 +00005534 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005535 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005536 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005537 }
5538 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005539 SKIP_BLANKS;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005540
5541 /*
5542 * Extract the old set, and then evaluate the result of the
5543 * expression for all the element in the set. use it to grow
5544 * up a new set.
5545 */
Daniel Veillard740abf52000-10-02 23:04:54 +00005546 CHECK_TYPE(XPATH_NODESET);
5547 obj = valuePop(ctxt);
5548 oldset = obj->nodesetval;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005549 ctxt->context->node = NULL;
5550
5551 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005552 ctxt->context->contextSize = 0;
5553 ctxt->context->proximityPosition = 0;
Daniel Veillardff9c3302000-10-13 16:38:25 +00005554 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005555 res = valuePop(ctxt);
5556 if (res != NULL)
5557 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005558 valuePush(ctxt, obj);
Daniel Veillardff9c3302000-10-13 16:38:25 +00005559 CHECK_ERROR;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005560 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005561 /*
5562 * Save the expression pointer since we will have to evaluate
5563 * it multiple times. Initialize the new set.
5564 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005565 cur = ctxt->cur;
5566 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00005567
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005568 for (i = 0; i < oldset->nodeNr; i++) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005569 ctxt->cur = cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00005570
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005571 /*
5572 * Run the evaluation with a node list made of a single item
5573 * in the nodeset.
5574 */
5575 ctxt->context->node = oldset->nodeTab[i];
Daniel Veillard740abf52000-10-02 23:04:54 +00005576 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5577 valuePush(ctxt, tmp);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005578 ctxt->context->contextSize = oldset->nodeNr;
5579 ctxt->context->proximityPosition = i + 1;
Daniel Veillardbe803962000-06-28 23:40:59 +00005580
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005581 xmlXPathEvalExpr(ctxt);
5582 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005583
5584 /*
5585 * The result of the evaluation need to be tested to
5586 * decided whether the filter succeeded or not
5587 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005588 res = valuePop(ctxt);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005589 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
5590 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
5591 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005592
5593 /*
5594 * Cleanup
5595 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005596 if (res != NULL)
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005597 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005598 if (ctxt->value == tmp) {
5599 res = valuePop(ctxt);
5600 xmlXPathFreeObject(res);
5601 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005602
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005603 ctxt->context->node = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005604 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005605
5606 /*
5607 * The result is used as the new evaluation set.
5608 */
Daniel Veillard740abf52000-10-02 23:04:54 +00005609 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005610 ctxt->context->node = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005611 ctxt->context->contextSize = -1;
5612 ctxt->context->proximityPosition = -1;
Daniel Veillard740abf52000-10-02 23:04:54 +00005613 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005614 }
5615 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005616 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005617 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005618
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005619 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005620 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005621#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005622 xmlGenericError(xmlGenericErrorContext, "After predicate : ");
5623 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5624 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005625#endif
5626}
5627
5628/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00005629 * xmlXPathEvalNodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005630 * @ctxt: the XPath Parser context
Daniel Veillard55b91f22000-10-05 16:30:11 +00005631 * @test: pointer to a xmlXPathTestVal
5632 * @type: pointer to a xmlXPathTypeVal
5633 * @prefix: placeholder for a possible name prefix
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005634 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005635 * [7] NodeTest ::= NameTest
5636 * | NodeType '(' ')'
5637 * | 'processing-instruction' '(' Literal ')'
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005638 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005639 * [37] NameTest ::= '*'
5640 * | NCName ':' '*'
5641 * | QName
5642 * [38] NodeType ::= 'comment'
5643 * | 'text'
5644 * | 'processing-instruction'
5645 * | 'node'
5646 *
5647 * Returns the name found and update @test, @type and @prefix appropriately
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005648 */
Daniel Veillard55b91f22000-10-05 16:30:11 +00005649xmlChar *
5650xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005651 xmlXPathTypeVal *type, const xmlChar **prefix, xmlChar *name) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005652 int blanks;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005653
Daniel Veillard55b91f22000-10-05 16:30:11 +00005654 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
5655 STRANGE;
5656 return(NULL);
5657 }
5658 *type = 0;
5659 *test = 0;
5660 *prefix = NULL;
5661 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005662
Daniel Veillard55b91f22000-10-05 16:30:11 +00005663 if ((name == NULL) && (CUR == '*')) {
5664 /*
5665 * All elements
5666 */
5667 NEXT;
5668 *test = NODE_TEST_ALL;
5669 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005670 }
5671
Daniel Veillard55b91f22000-10-05 16:30:11 +00005672 if (name == NULL)
5673 name = xmlXPathParseNCName(ctxt);
5674 if (name == NULL) {
5675 XP_ERROR0(XPATH_EXPR_ERROR);
5676 }
5677
5678 blanks = IS_BLANK(CUR);
5679 SKIP_BLANKS;
5680 if (CUR == '(') {
5681 NEXT;
5682 /*
5683 * NodeType or PI search
5684 */
5685 if (xmlStrEqual(name, BAD_CAST "comment"))
5686 *type = NODE_TYPE_COMMENT;
5687 else if (xmlStrEqual(name, BAD_CAST "node"))
5688 *type = NODE_TYPE_NODE;
5689 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5690 *type = NODE_TYPE_PI;
5691 else if (xmlStrEqual(name, BAD_CAST "text"))
5692 *type = NODE_TYPE_TEXT;
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005693 else {
5694 if (name != NULL)
5695 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005696 XP_ERROR0(XPATH_EXPR_ERROR);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005697 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005698
5699 *test = NODE_TEST_TYPE;
5700
5701 SKIP_BLANKS;
5702 if (*type == NODE_TYPE_PI) {
5703 /*
5704 * Specific case: search a PI by name.
5705 */
5706 xmlXPathObjectPtr cur;
5707
5708 if (name != NULL)
5709 xmlFree(name);
5710
5711 xmlXPathEvalLiteral(ctxt);
5712 CHECK_ERROR 0;
5713 xmlXPathStringFunction(ctxt, 1);
5714 CHECK_ERROR0;
5715 cur = valuePop(ctxt);
5716 name = xmlStrdup(cur->stringval);
5717 xmlXPathFreeObject(cur);
5718 SKIP_BLANKS;
5719 }
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005720 if (CUR != ')') {
5721 if (name != NULL)
5722 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005723 XP_ERROR0(XPATH_UNCLOSED_ERROR);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005724 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005725 NEXT;
5726 return(name);
5727 }
5728 *test = NODE_TEST_NAME;
5729 if ((!blanks) && (CUR == ':')) {
5730 NEXT;
5731
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005732 /*
5733 * get the namespace name for this prefix
5734 */
5735 *prefix = xmlXPathNsLookup(ctxt->context, name);
5736 if (name != NULL)
5737 xmlFree(name);
5738 if (*prefix == NULL) {
5739 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
5740 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005741
5742 if (CUR == '*') {
5743 /*
5744 * All elements
5745 */
5746 NEXT;
5747 *test = NODE_TEST_ALL;
5748 return(NULL);
5749 }
5750
5751 name = xmlXPathParseNCName(ctxt);
5752 if (name == NULL) {
5753 XP_ERROR0(XPATH_EXPR_ERROR);
5754 }
5755 }
5756 return(name);
5757}
5758
5759/**
5760 * xmlXPathIsAxisName:
5761 * @name: a preparsed name token
5762 *
5763 * [6] AxisName ::= 'ancestor'
5764 * | 'ancestor-or-self'
5765 * | 'attribute'
5766 * | 'child'
5767 * | 'descendant'
5768 * | 'descendant-or-self'
5769 * | 'following'
5770 * | 'following-sibling'
5771 * | 'namespace'
5772 * | 'parent'
5773 * | 'preceding'
5774 * | 'preceding-sibling'
5775 * | 'self'
5776 *
5777 * Returns the axis or 0
5778 */
5779xmlXPathAxisVal
5780xmlXPathIsAxisName(const xmlChar *name) {
5781 xmlXPathAxisVal ret = 0;
5782 switch (name[0]) {
5783 case 'a':
5784 if (xmlStrEqual(name, BAD_CAST "ancestor"))
5785 ret = AXIS_ANCESTOR;
5786 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
5787 ret = AXIS_ANCESTOR_OR_SELF;
5788 if (xmlStrEqual(name, BAD_CAST "attribute"))
5789 ret = AXIS_ATTRIBUTE;
5790 break;
5791 case 'c':
5792 if (xmlStrEqual(name, BAD_CAST "child"))
5793 ret = AXIS_CHILD;
5794 break;
5795 case 'd':
5796 if (xmlStrEqual(name, BAD_CAST "descendant"))
5797 ret = AXIS_DESCENDANT;
5798 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
5799 ret = AXIS_DESCENDANT_OR_SELF;
5800 break;
5801 case 'f':
5802 if (xmlStrEqual(name, BAD_CAST "following"))
5803 ret = AXIS_FOLLOWING;
5804 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
5805 ret = AXIS_FOLLOWING_SIBLING;
5806 break;
5807 case 'n':
5808 if (xmlStrEqual(name, BAD_CAST "namespace"))
5809 ret = AXIS_NAMESPACE;
5810 break;
5811 case 'p':
5812 if (xmlStrEqual(name, BAD_CAST "parent"))
5813 ret = AXIS_PARENT;
5814 if (xmlStrEqual(name, BAD_CAST "preceding"))
5815 ret = AXIS_PRECEDING;
5816 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
5817 ret = AXIS_PRECEDING_SIBLING;
5818 break;
5819 case 's':
5820 if (xmlStrEqual(name, BAD_CAST "self"))
5821 ret = AXIS_SELF;
5822 break;
5823 }
5824 return(ret);
5825}
5826
5827/**
5828 * xmlXPathEvalAxisSpecifier:
5829 * @ctxt: the XPath Parser context
5830 *
5831 *
5832 * Returns the axis found
5833 */
5834xmlXPathAxisVal
5835xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
5836 xmlXPathAxisVal ret = AXIS_CHILD;
5837 int blank = 0;
5838 xmlChar *name;
5839
5840 if (CUR == '@') {
5841 NEXT;
5842 return(AXIS_ATTRIBUTE);
5843 } else {
5844 name = xmlXPathParseNCName(ctxt);
5845 if (name == NULL) {
5846 XP_ERROR0(XPATH_EXPR_ERROR);
5847 }
5848 if (IS_BLANK(CUR))
5849 blank = 1;
5850 SKIP_BLANKS;
5851 if ((CUR == ':') && (NXT(1) == ':')) {
5852 ret = xmlXPathIsAxisName(name);
5853 } else if ((blank) && (CUR == ':'))
5854 XP_ERROR0(XPATH_EXPR_ERROR);
5855
5856 xmlFree(name);
5857 }
5858 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005859}
5860
5861/**
5862 * xmlXPathEvalStep:
5863 * @ctxt: the XPath Parser context
5864 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005865 * [4] Step ::= AxisSpecifier NodeTest Predicate*
5866 * | AbbreviatedStep
Daniel Veillardac260302000-10-04 13:33:43 +00005867 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005868 * [12] AbbreviatedStep ::= '.' | '..'
5869 *
5870 * [5] AxisSpecifier ::= AxisName '::'
5871 * | AbbreviatedAxisSpecifier
5872 *
5873 * [13] AbbreviatedAxisSpecifier ::= '@'?
Daniel Veillardac260302000-10-04 13:33:43 +00005874 *
5875 * Modified for XPtr range support as:
5876 *
5877 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5878 * | AbbreviatedStep
5879 * | 'range-to' '(' Expr ')' Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005880 *
5881 * Evaluate one step in a Location Path
5882 * A location step of . is short for self::node(). This is
5883 * particularly useful in conjunction with //. For example, the
5884 * location path .//para is short for
5885 * self::node()/descendant-or-self::node()/child::para
5886 * and so will select all para descendant elements of the context
5887 * node.
5888 * Similarly, a location step of .. is short for parent::node().
5889 * For example, ../title is short for parent::node()/child::title
5890 * and so will select the title children of the parent of the context
5891 * node.
5892 */
5893void
5894xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005895 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005896 if ((CUR == '.') && (NXT(1) == '.')) {
5897 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005898 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005899 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
Daniel Veillard767662d2000-10-27 17:04:52 +00005900 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005901 } else if (CUR == '.') {
5902 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005903 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005904 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005905 xmlChar *name = NULL;
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005906 const xmlChar *prefix = NULL;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005907 xmlXPathTestVal test;
5908 xmlXPathAxisVal axis;
5909 xmlXPathTypeVal type;
5910
5911 /*
5912 * The modification needed for XPointer change to the production
5913 */
Daniel Veillardac260302000-10-04 13:33:43 +00005914#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard55b91f22000-10-05 16:30:11 +00005915 if (ctxt->context->xptr) {
5916 name = xmlXPathParseNCName(ctxt);
5917 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
5918 xmlFree(name);
5919 SKIP_BLANKS;
5920 if (CUR != '(') {
5921 XP_ERROR(XPATH_EXPR_ERROR);
5922 }
5923 NEXT;
5924 SKIP_BLANKS;
Daniel Veillardac260302000-10-04 13:33:43 +00005925
Daniel Veillard55b91f22000-10-05 16:30:11 +00005926 xmlXPtrRangeToFunction(ctxt, 1);
Daniel Veillardac260302000-10-04 13:33:43 +00005927 CHECK_ERROR;
5928
Daniel Veillard55b91f22000-10-05 16:30:11 +00005929 SKIP_BLANKS;
5930 if (CUR != ')') {
5931 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardac260302000-10-04 13:33:43 +00005932 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005933 NEXT;
5934 goto eval_predicates;
Daniel Veillardac260302000-10-04 13:33:43 +00005935 }
Daniel Veillardac260302000-10-04 13:33:43 +00005936 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005937#endif
5938 if (name == NULL)
5939 name = xmlXPathParseNCName(ctxt);
5940 if (name != NULL) {
5941 axis = xmlXPathIsAxisName(name);
5942 if (axis != 0) {
5943 SKIP_BLANKS;
5944 if ((CUR == ':') && (NXT(1) == ':')) {
5945 SKIP(2);
5946 xmlFree(name);
5947 name = NULL;
5948 } else {
5949 /* an element name can conflict with an axis one :-\ */
5950 axis = AXIS_CHILD;
5951 }
5952 } else {
5953 axis = AXIS_CHILD;
5954 }
5955 } else if (CUR == '@') {
5956 NEXT;
5957 axis = AXIS_ATTRIBUTE;
5958 } else {
5959 axis = AXIS_CHILD;
5960 }
5961
5962 CHECK_ERROR;
5963
5964 name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
5965 if (test == 0)
5966 return;
5967
5968#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005969 xmlGenericError(xmlGenericErrorContext,
5970 "Basis : computing new set\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005971#endif
5972 xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
5973#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005974 xmlGenericError(xmlGenericErrorContext, "Basis : ");
5975 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005976#endif
5977 if (name != NULL)
5978 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005979
5980eval_predicates:
Daniel Veillard00fdf371999-10-08 09:40:39 +00005981 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005982 while (CUR == '[') {
5983 xmlXPathEvalPredicate(ctxt);
5984 }
5985 }
5986#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005987 xmlGenericError(xmlGenericErrorContext, "Step : ");
5988 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5989 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005990#endif
5991}
5992
5993/**
5994 * xmlXPathEvalRelativeLocationPath:
5995 * @ctxt: the XPath Parser context
5996 *
5997 * [3] RelativeLocationPath ::= Step
5998 * | RelativeLocationPath '/' Step
5999 * | AbbreviatedRelativeLocationPath
6000 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6001 *
6002 */
6003void
Daniel Veillardce6e98d2000-11-25 09:54:49 +00006004#ifdef VMS
6005xmlXPathEvalRelLocationPath
6006#else
6007xmlXPathEvalRelativeLocationPath
6008#endif
6009(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00006010 SKIP_BLANKS;
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00006011 if ((CUR == '/') && (NXT(1) == '/')) {
6012 SKIP(2);
6013 SKIP_BLANKS;
6014 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00006015 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00006016 } else if (CUR == '/') {
6017 NEXT;
6018 SKIP_BLANKS;
6019 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006020 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006021 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006022 while (CUR == '/') {
6023 if ((CUR == '/') && (NXT(1) == '/')) {
6024 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006025 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00006026 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00006027 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006028 xmlXPathEvalStep(ctxt);
6029 } else if (CUR == '/') {
6030 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00006031 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006032 xmlXPathEvalStep(ctxt);
6033 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00006034 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006035 }
6036}
6037
6038/**
6039 * xmlXPathEvalLocationPath:
6040 * @ctxt: the XPath Parser context
6041 *
6042 * [1] LocationPath ::= RelativeLocationPath
6043 * | AbsoluteLocationPath
6044 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6045 * | AbbreviatedAbsoluteLocationPath
6046 * [10] AbbreviatedAbsoluteLocationPath ::=
6047 * '//' RelativeLocationPath
6048 *
6049 * // is short for /descendant-or-self::node()/. For example,
6050 * //para is short for /descendant-or-self::node()/child::para and
6051 * so will select any para element in the document (even a para element
6052 * that is a document element will be selected by //para since the
6053 * document element node is a child of the root node); div//para is
6054 * short for div/descendant-or-self::node()/child::para and so will
6055 * select all para descendants of div children.
6056 */
6057void
6058xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00006059 SKIP_BLANKS;
6060 if (CUR != '/') {
6061 xmlXPathEvalRelativeLocationPath(ctxt);
6062 } else {
6063 while (CUR == '/') {
6064 if ((CUR == '/') && (NXT(1) == '/')) {
6065 SKIP(2);
6066 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00006067 xmlXPathNodeCollectAndTest(ctxt,
Daniel Veillard00fdf371999-10-08 09:40:39 +00006068 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
Daniel Veillard767662d2000-10-27 17:04:52 +00006069 NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006070 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006071 } else if (CUR == '/') {
6072 NEXT;
6073 SKIP_BLANKS;
Daniel Veillard00fdf371999-10-08 09:40:39 +00006074 if (CUR != 0)
6075 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006076 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006077 }
6078 }
6079}
6080
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006081/**
6082 * xmlXPathEval:
6083 * @str: the XPath expression
Daniel Veillard740abf52000-10-02 23:04:54 +00006084 * @ctx: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006085 *
6086 * Evaluate the XPath Location Path in the given context.
6087 *
6088 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
6089 * the caller has to free the object.
6090 */
6091xmlXPathObjectPtr
Daniel Veillard740abf52000-10-02 23:04:54 +00006092xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
6093 xmlXPathParserContextPtr ctxt;
Daniel Veillard41e06512000-11-13 11:47:47 +00006094 xmlXPathObjectPtr res = NULL, tmp, init = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006095 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006096
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006097 xmlXPathInit();
6098
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00006099 CHECK_CONTEXT(ctx)
6100
Daniel Veillard740abf52000-10-02 23:04:54 +00006101 ctxt = xmlXPathNewParserContext(str, ctx);
Daniel Veillard5a2b6972001-01-20 21:15:50 +00006102 /**** TAG:9999
Daniel Veillard41e06512000-11-13 11:47:47 +00006103 if (ctx->node != NULL) {
6104 init = xmlXPathNewNodeSet(ctx->node);
6105 valuePush(ctxt, init);
6106 }
Daniel Veillard5a2b6972001-01-20 21:15:50 +00006107 ****/
Daniel Veillard55b91f22000-10-05 16:30:11 +00006108 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006109
Daniel Veillard767662d2000-10-27 17:04:52 +00006110 if (ctxt->value == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006111 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard767662d2000-10-27 17:04:52 +00006112 "xmlXPathEval: evaluation failed\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00006113 } else {
6114 res = valuePop(ctxt);
6115 }
6116
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006117 do {
Daniel Veillard740abf52000-10-02 23:04:54 +00006118 tmp = valuePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006119 if (tmp != NULL) {
Daniel Veillard41e06512000-11-13 11:47:47 +00006120 if (tmp != init)
6121 stack++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00006122 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006123 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00006124 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006125 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006126 xmlGenericError(xmlGenericErrorContext,
6127 "xmlXPathEval: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006128 stack);
6129 }
Daniel Veillard740abf52000-10-02 23:04:54 +00006130 if (ctxt->error != XPATH_EXPRESSION_OK) {
6131 xmlXPathFreeObject(res);
6132 res = NULL;
6133 }
Daniel Veillardbe803962000-06-28 23:40:59 +00006134
Daniel Veillard740abf52000-10-02 23:04:54 +00006135 xmlXPathFreeParserContext(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006136 return(res);
6137}
6138
6139/**
6140 * xmlXPathEvalExpression:
6141 * @str: the XPath expression
6142 * @ctxt: the XPath context
6143 *
6144 * Evaluate the XPath expression in the given context.
6145 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00006146 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006147 * the caller has to free the object.
6148 */
6149xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006150xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006151 xmlXPathParserContextPtr pctxt;
6152 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006153 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006154
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006155 xmlXPathInit();
6156
Daniel Veillard740abf52000-10-02 23:04:54 +00006157 CHECK_CONTEXT(ctxt)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006158
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006159 pctxt = xmlXPathNewParserContext(str, ctxt);
6160 xmlXPathEvalExpr(pctxt);
6161
6162 res = valuePop(pctxt);
6163 do {
6164 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006165 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006166 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006167 stack++;
6168 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006169 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006170 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006171 xmlGenericError(xmlGenericErrorContext,
6172 "xmlXPathEvalExpression: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006173 stack);
6174 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006175 xmlXPathFreeParserContext(pctxt);
6176 return(res);
6177}
6178
Daniel Veillardf17e09b2001-01-25 13:55:35 +00006179/**
6180 * xmlXPathRegisterAllFunctions:
6181 * @ctxt: the XPath context
6182 *
6183 * Registers all default XPath functions in this context
6184 */
Daniel Veillard52afe802000-10-22 16:56:02 +00006185void
6186xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
6187{
6188 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
6189 xmlXPathBooleanFunction);
6190 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
6191 xmlXPathCeilingFunction);
6192 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
6193 xmlXPathCountFunction);
6194 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
6195 xmlXPathConcatFunction);
6196 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
6197 xmlXPathContainsFunction);
6198 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
6199 xmlXPathIdFunction);
6200 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
6201 xmlXPathFalseFunction);
6202 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
6203 xmlXPathFloorFunction);
6204 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
6205 xmlXPathLastFunction);
6206 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
6207 xmlXPathLangFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00006208 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
6209 xmlXPathLocalNameFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006210 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
6211 xmlXPathNotFunction);
6212 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
6213 xmlXPathNameFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00006214 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
6215 xmlXPathNamespaceURIFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006216 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
6217 xmlXPathNormalizeFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006218 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
6219 xmlXPathNumberFunction);
6220 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
6221 xmlXPathPositionFunction);
6222 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
6223 xmlXPathRoundFunction);
6224 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
6225 xmlXPathStringFunction);
6226 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
6227 xmlXPathStringLengthFunction);
6228 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
6229 xmlXPathStartsWithFunction);
6230 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
6231 xmlXPathSubstringFunction);
6232 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
6233 xmlXPathSubstringBeforeFunction);
6234 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
6235 xmlXPathSubstringAfterFunction);
6236 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
6237 xmlXPathSumFunction);
6238 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
6239 xmlXPathTrueFunction);
6240 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
6241 xmlXPathTranslateFunction);
6242}
6243
Daniel Veillard361d8452000-04-03 19:48:13 +00006244#endif /* LIBXML_XPATH_ENABLED */