blob: 00ded9ce8f7e33ed27735efd48eb6046a7ea3ef6 [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/**
Daniel Veillard2c257ec2001-02-06 13:29:07 +0000673 * xmlXPathNodeSetAddUnique:
674 * @cur: the initial node set
675 * @val: a new xmlNodePtr
676 *
677 * add a new xmlNodePtr ot an existing NodeSet, optimized version
678 * when we are sure the node is not already in the set.
679 */
680void
681xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
682 if (val == NULL) return;
683
684 /*
685 * grow the nodeTab if needed
686 */
687 if (cur->nodeMax == 0) {
688 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
689 sizeof(xmlNodePtr));
690 if (cur->nodeTab == NULL) {
691 xmlGenericError(xmlGenericErrorContext,
692 "xmlXPathNodeSetAddUnique: out of memory\n");
693 return;
694 }
695 memset(cur->nodeTab, 0 ,
696 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
697 cur->nodeMax = XML_NODESET_DEFAULT;
698 } else if (cur->nodeNr == cur->nodeMax) {
699 xmlNodePtr *temp;
700
701 cur->nodeMax *= 2;
702 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
703 sizeof(xmlNodePtr));
704 if (temp == NULL) {
705 xmlGenericError(xmlGenericErrorContext,
706 "xmlXPathNodeSetAddUnique: out of memory\n");
707 return;
708 }
709 cur->nodeTab = temp;
710 }
711 cur->nodeTab[cur->nodeNr++] = val;
712}
713
714/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000715 * xmlXPathNodeSetMerge:
Daniel Veillard2d38f042000-10-11 10:54:10 +0000716 * @val1: the first NodeSet or NULL
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000717 * @val2: the second NodeSet
718 *
719 * Merges two nodesets, all nodes from @val2 are added to @val1
Daniel Veillard2d38f042000-10-11 10:54:10 +0000720 * if @val1 is NULL, a new set is created and copied from @val2
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000721 *
722 * Returns val1 once extended or NULL in case of error.
723 */
724xmlNodeSetPtr
725xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000726 int i, j, initNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000727
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000728 if (val2 == NULL) return(val1);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000729 if (val1 == NULL) {
730 val1 = xmlXPathNodeSetCreate(NULL);
731 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000732
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000733 initNr = val1->nodeNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000734
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000735 for (i = 0;i < val2->nodeNr;i++) {
736 /*
737 * check against doublons
738 */
739 for (j = 0; j < initNr; j++)
740 if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
741
742 /*
743 * grow the nodeTab if needed
744 */
745 if (val1->nodeMax == 0) {
746 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
747 sizeof(xmlNodePtr));
748 if (val1->nodeTab == NULL) {
749 xmlGenericError(xmlGenericErrorContext,
750 "xmlXPathNodeSetMerge: out of memory\n");
751 return(NULL);
752 }
753 memset(val1->nodeTab, 0 ,
754 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
755 val1->nodeMax = XML_NODESET_DEFAULT;
756 } else if (val1->nodeNr == val1->nodeMax) {
757 xmlNodePtr *temp;
758
759 val1->nodeMax *= 2;
760 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
761 sizeof(xmlNodePtr));
762 if (temp == NULL) {
763 xmlGenericError(xmlGenericErrorContext,
764 "xmlXPathNodeSetMerge: out of memory\n");
765 return(NULL);
766 }
767 val1->nodeTab = temp;
768 }
769 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
770 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000771
772 return(val1);
773}
774
775/**
776 * xmlXPathNodeSetDel:
777 * @cur: the initial node set
778 * @val: an xmlNodePtr
779 *
780 * Removes an xmlNodePtr from an existing NodeSet
781 */
782void
783xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
784 int i;
785
786 if (cur == NULL) return;
787 if (val == NULL) return;
788
789 /*
790 * check against doublons
791 */
792 for (i = 0;i < cur->nodeNr;i++)
793 if (cur->nodeTab[i] == val) break;
794
795 if (i >= cur->nodeNr) {
796#ifdef DEBUG
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000797 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000798 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
799 val->name);
800#endif
801 return;
802 }
803 cur->nodeNr--;
804 for (;i < cur->nodeNr;i++)
805 cur->nodeTab[i] = cur->nodeTab[i + 1];
806 cur->nodeTab[cur->nodeNr] = NULL;
807}
808
809/**
810 * xmlXPathNodeSetRemove:
811 * @cur: the initial node set
812 * @val: the index to remove
813 *
814 * Removes an entry from an existing NodeSet list.
815 */
816void
817xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
818 if (cur == NULL) return;
819 if (val >= cur->nodeNr) return;
820 cur->nodeNr--;
821 for (;val < cur->nodeNr;val++)
822 cur->nodeTab[val] = cur->nodeTab[val + 1];
823 cur->nodeTab[cur->nodeNr] = NULL;
824}
825
826/**
827 * xmlXPathFreeNodeSet:
828 * @obj: the xmlNodeSetPtr to free
829 *
830 * Free the NodeSet compound (not the actual nodes !).
831 */
832void
833xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
834 if (obj == NULL) return;
835 if (obj->nodeTab != NULL) {
836#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000837 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000838#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000839 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000840 }
841#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000842 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000843#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000844 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000845}
846
Daniel Veillard8a7642f2001-01-22 10:45:16 +0000847/**
848 * xmlXPathFreeValueTree:
849 * @obj: the xmlNodeSetPtr to free
850 *
851 * Free the NodeSet compound and the actual tree, this is different
852 * from xmlXPathFreeNodeSet()
853 */
854void
855xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
856 int i;
857
858 if (obj == NULL) return;
859 for (i = 0;i < obj->nodeNr;i++)
860 if (obj->nodeTab[i] != NULL)
861 xmlFreeNode(obj->nodeTab[i]);
862
863 if (obj->nodeTab != NULL) {
864#ifdef DEBUG
865 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
866#endif
867 xmlFree(obj->nodeTab);
868 }
869#ifdef DEBUG
870 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
871#endif
872 xmlFree(obj);
873}
874
Daniel Veillardb96e6431999-08-29 21:02:19 +0000875#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000876/**
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000877 * xmlGenericErrorContextNodeSet:
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000878 * @output: a FILE * for the output
879 * @obj: the xmlNodeSetPtr to free
880 *
881 * Quick display of a NodeSet
882 */
883void
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000884xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000885 int i;
886
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000887 if (output == NULL) output = xmlGenericErrorContext;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000888 if (obj == NULL) {
889 fprintf(output, "NodeSet == NULL !\n");
890 return;
891 }
892 if (obj->nodeNr == 0) {
893 fprintf(output, "NodeSet is empty\n");
894 return;
895 }
896 if (obj->nodeTab == NULL) {
897 fprintf(output, " nodeTab == NULL !\n");
898 return;
899 }
900 for (i = 0; i < obj->nodeNr; i++) {
901 if (obj->nodeTab[i] == NULL) {
902 fprintf(output, " NULL !\n");
903 return;
904 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000905 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
906 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000907 fprintf(output, " /");
908 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000909 fprintf(output, " noname!");
910 else fprintf(output, " %s", obj->nodeTab[i]->name);
911 }
912 fprintf(output, "\n");
913}
914#endif
915
Daniel Veillard7e99c632000-10-06 12:59:53 +0000916/**
917 * xmlXPathNewNodeSet:
918 * @val: the NodePtr value
919 *
920 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
921 * it with the single Node @val
922 *
923 * Returns the newly created object.
924 */
925xmlXPathObjectPtr
926xmlXPathNewNodeSet(xmlNodePtr val) {
927 xmlXPathObjectPtr ret;
928
929 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
930 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000931 xmlGenericError(xmlGenericErrorContext,
932 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000933 return(NULL);
934 }
935 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
936 ret->type = XPATH_NODESET;
937 ret->nodesetval = xmlXPathNodeSetCreate(val);
938 return(ret);
939}
940
941/**
Daniel Veillarde4566462001-01-22 09:58:39 +0000942 * xmlXPathNewValueTree:
943 * @val: the NodePtr value
944 *
945 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
946 * it with the tree root @val
947 *
948 * Returns the newly created object.
949 */
950xmlXPathObjectPtr
951xmlXPathNewValueTree(xmlNodePtr val) {
952 xmlXPathObjectPtr ret;
953
954 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
955 if (ret == NULL) {
956 xmlGenericError(xmlGenericErrorContext,
957 "xmlXPathNewNodeSet: out of memory\n");
958 return(NULL);
959 }
960 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
961 ret->type = XPATH_XSLT_TREE;
962 ret->nodesetval = xmlXPathNodeSetCreate(val);
963 return(ret);
964}
965
966/**
Daniel Veillard7e99c632000-10-06 12:59:53 +0000967 * xmlXPathNewNodeSetList:
968 * @val: an existing NodeSet
969 *
970 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
971 * it with the Nodeset @val
972 *
973 * Returns the newly created object.
974 */
975xmlXPathObjectPtr
976xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
977 xmlXPathObjectPtr ret;
978 int i;
979
980 if (val == NULL)
981 ret = NULL;
982 else if (val->nodeTab == NULL)
983 ret = xmlXPathNewNodeSet(NULL);
984 else
985 {
986 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
987 for (i = 1; i < val->nodeNr; ++i)
Daniel Veillard2c257ec2001-02-06 13:29:07 +0000988 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard7e99c632000-10-06 12:59:53 +0000989 }
990
991 return(ret);
992}
993
994/**
995 * xmlXPathWrapNodeSet:
996 * @val: the NodePtr value
997 *
998 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
999 *
1000 * Returns the newly created object.
1001 */
1002xmlXPathObjectPtr
1003xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1004 xmlXPathObjectPtr ret;
1005
1006 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1007 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001008 xmlGenericError(xmlGenericErrorContext,
1009 "xmlXPathWrapNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +00001010 return(NULL);
1011 }
1012 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1013 ret->type = XPATH_NODESET;
1014 ret->nodesetval = val;
1015 return(ret);
1016}
1017
1018/**
1019 * xmlXPathFreeNodeSetList:
1020 * @obj: an existing NodeSetList object
1021 *
1022 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1023 * the list contrary to xmlXPathFreeObject().
1024 */
1025void
1026xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1027 if (obj == NULL) return;
1028#ifdef DEBUG
1029 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
1030#endif
1031 xmlFree(obj);
1032}
1033
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001034/************************************************************************
1035 * *
Daniel Veillard2d38f042000-10-11 10:54:10 +00001036 * Routines to handle extra functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001037 * *
1038 ************************************************************************/
1039
1040/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001041 * xmlXPathRegisterFunc:
1042 * @ctxt: the XPath context
1043 * @name: the function name
1044 * @f: the function implementation or NULL
1045 *
1046 * Register a new function. If @f is NULL it unregisters the function
1047 *
1048 * Returns 0 in case of success, -1 in case of error
1049 */
1050int
1051xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1052 xmlXPathFunction f) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001053 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1054}
1055
1056/**
1057 * xmlXPathRegisterFuncNS:
1058 * @ctxt: the XPath context
1059 * @name: the function name
1060 * @ns_uri: the function namespace URI
1061 * @f: the function implementation or NULL
1062 *
1063 * Register a new function. If @f is NULL it unregisters the function
1064 *
1065 * Returns 0 in case of success, -1 in case of error
1066 */
1067int
1068xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1069 const xmlChar *ns_uri, xmlXPathFunction f) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001070 if (ctxt == NULL)
1071 return(-1);
1072 if (name == NULL)
1073 return(-1);
1074
Daniel Veillard52afe802000-10-22 16:56:02 +00001075 if (ctxt->funcHash == NULL)
1076 ctxt->funcHash = xmlHashCreate(0);
1077 if (ctxt->funcHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +00001078 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001079 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001080}
1081
1082/**
1083 * xmlXPathFunctionLookup:
1084 * @ctxt: the XPath context
1085 * @name: the function name
1086 *
1087 * Search in the Function array of the context for the given
1088 * function.
1089 *
1090 * Returns the xmlXPathFunction or NULL if not found
1091 */
1092xmlXPathFunction
1093xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001094 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1095}
1096
1097/**
1098 * xmlXPathFunctionLookupNS:
1099 * @ctxt: the XPath context
1100 * @name: the function name
1101 * @ns_uri: the function namespace URI
1102 *
1103 * Search in the Function array of the context for the given
1104 * function.
1105 *
1106 * Returns the xmlXPathFunction or NULL if not found
1107 */
1108xmlXPathFunction
1109xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1110 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001111 if (ctxt == NULL)
1112 return(NULL);
Daniel Veillard52afe802000-10-22 16:56:02 +00001113 if (ctxt->funcHash == NULL)
1114 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001115 if (name == NULL)
1116 return(NULL);
1117
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001118 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001119}
1120
1121/**
1122 * xmlXPathRegisteredFuncsCleanup:
1123 * @ctxt: the XPath context
1124 *
1125 * Cleanup the XPath context data associated to registered functions
1126 */
1127void
1128xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001129 if (ctxt == NULL)
1130 return;
1131
Daniel Veillard52afe802000-10-22 16:56:02 +00001132 xmlHashFree(ctxt->funcHash, NULL);
1133 ctxt->funcHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001134}
1135
1136/************************************************************************
1137 * *
1138 * Routines to handle Variable *
1139 * *
1140 ************************************************************************/
1141
1142/**
1143 * xmlXPathRegisterVariable:
1144 * @ctxt: the XPath context
1145 * @name: the variable name
1146 * @value: the variable value or NULL
1147 *
1148 * Register a new variable value. If @value is NULL it unregisters
1149 * the variable
1150 *
1151 * Returns 0 in case of success, -1 in case of error
1152 */
1153int
1154xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1155 xmlXPathObjectPtr value) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001156 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1157}
1158
1159/**
1160 * xmlXPathRegisterVariableNS:
1161 * @ctxt: the XPath context
1162 * @name: the variable name
1163 * @ns_uri: the variable namespace URI
1164 * @value: the variable value or NULL
1165 *
1166 * Register a new variable value. If @value is NULL it unregisters
1167 * the variable
1168 *
1169 * Returns 0 in case of success, -1 in case of error
1170 */
1171int
1172xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1173 const xmlChar *ns_uri,
1174 xmlXPathObjectPtr value) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001175 if (ctxt == NULL)
1176 return(-1);
1177 if (name == NULL)
1178 return(-1);
1179
Daniel Veillard126f2792000-10-24 17:10:12 +00001180 if (ctxt->varHash == NULL)
1181 ctxt->varHash = xmlHashCreate(0);
1182 if (ctxt->varHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +00001183 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001184 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1185 (void *) value,
1186 (xmlHashDeallocator)xmlXPathFreeObject));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001187}
1188
1189/**
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001190 * xmlXPathRegisterVariableLookup:
1191 * @ctxt: the XPath context
1192 * @f: the lookup function
1193 * @data: the lookup data
1194 *
1195 * register an external mechanism to do variable lookup
1196 */
1197void
1198xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1199 xmlXPathVariableLookupFunc f, void *data) {
1200 if (ctxt == NULL)
1201 return;
1202 ctxt->varLookupFunc = (void *) f;
1203 ctxt->varLookupData = data;
1204}
1205
1206/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001207 * xmlXPathVariableLookup:
1208 * @ctxt: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001209 * @name: the variable name
1210 *
1211 * Search in the Variable array of the context for the given
1212 * variable value.
1213 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001214 * Returns the value or NULL if not found
1215 */
1216xmlXPathObjectPtr
Daniel Veillard2d38f042000-10-11 10:54:10 +00001217xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001218 if (ctxt == NULL)
1219 return(NULL);
1220
1221 if (ctxt->varLookupFunc != NULL) {
1222 xmlXPathObjectPtr ret;
1223
1224 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1225 (ctxt->varLookupData, name, NULL);
1226 if (ret != NULL) return(ret);
1227 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001228 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1229}
1230
1231/**
1232 * xmlXPathVariableLookupNS:
1233 * @ctxt: the XPath context
1234 * @name: the variable name
1235 * @ns_uri: the variable namespace URI
1236 *
1237 * Search in the Variable array of the context for the given
1238 * variable value.
1239 *
1240 * Returns the value or NULL if not found
1241 */
1242xmlXPathObjectPtr
1243xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1244 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001245 if (ctxt == NULL)
1246 return(NULL);
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001247
1248 if (ctxt->varLookupFunc != NULL) {
1249 xmlXPathObjectPtr ret;
1250
1251 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1252 (ctxt->varLookupData, name, ns_uri);
1253 if (ret != NULL) return(ret);
1254 }
1255
Daniel Veillard126f2792000-10-24 17:10:12 +00001256 if (ctxt->varHash == NULL)
1257 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001258 if (name == NULL)
1259 return(NULL);
1260
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001261 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001262}
1263
Daniel Veillard2d38f042000-10-11 10:54:10 +00001264/**
1265 * xmlXPathRegisteredVariablesCleanup:
1266 * @ctxt: the XPath context
1267 *
1268 * Cleanup the XPath context data associated to registered variables
1269 */
1270void
1271xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001272 if (ctxt == NULL)
1273 return;
1274
Daniel Veillard126f2792000-10-24 17:10:12 +00001275 xmlHashFree(ctxt->varHash, NULL);
1276 ctxt->varHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001277}
1278
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001279/**
1280 * xmlXPathRegisterNs:
1281 * @ctxt: the XPath context
1282 * @prefix: the namespace prefix
1283 * @ns_uri: the namespace name
1284 *
1285 * Register a new namespace. If @ns_uri is NULL it unregisters
1286 * the namespace
1287 *
1288 * Returns 0 in case of success, -1 in case of error
1289 */
1290int
1291xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1292 const xmlChar *ns_uri) {
1293 if (ctxt == NULL)
1294 return(-1);
1295 if (prefix == NULL)
1296 return(-1);
1297
1298 if (ctxt->nsHash == NULL)
1299 ctxt->nsHash = xmlHashCreate(10);
1300 if (ctxt->nsHash == NULL)
1301 return(-1);
1302 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1303 (xmlHashDeallocator)xmlFree));
1304}
1305
1306/**
1307 * xmlXPathNsLookup:
1308 * @ctxt: the XPath context
1309 * @prefix: the namespace prefix value
1310 *
1311 * Search in the namespace declaration array of the context for the given
1312 * namespace name associated to the given prefix
1313 *
1314 * Returns the value or NULL if not found
1315 */
1316const xmlChar *
1317xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1318 if (ctxt == NULL)
1319 return(NULL);
1320 if (prefix == NULL)
1321 return(NULL);
1322 if (ctxt->nsHash == NULL)
1323 return(NULL);
1324
1325 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1326}
1327
1328/**
1329 * xmlXPathRegisteredVariablesCleanup:
1330 * @ctxt: the XPath context
1331 *
1332 * Cleanup the XPath context data associated to registered variables
1333 */
1334void
1335xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1336 if (ctxt == NULL)
1337 return;
1338
1339 xmlHashFree(ctxt->nsHash, NULL);
1340 ctxt->nsHash = NULL;
1341}
1342
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001343/************************************************************************
1344 * *
1345 * Routines to handle Values *
1346 * *
1347 ************************************************************************/
1348
1349/* Allocations are terrible, one need to optimize all this !!! */
1350
1351/**
1352 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001353 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001354 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001355 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001356 *
1357 * Returns the newly created object.
1358 */
1359xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001360xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001361 xmlXPathObjectPtr ret;
1362
Daniel Veillard6454aec1999-09-02 22:04:43 +00001363 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001364 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001365 xmlGenericError(xmlGenericErrorContext,
1366 "xmlXPathNewFloat: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001367 return(NULL);
1368 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001369 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001370 ret->type = XPATH_NUMBER;
1371 ret->floatval = val;
1372 return(ret);
1373}
1374
1375/**
1376 * xmlXPathNewBoolean:
1377 * @val: the boolean value
1378 *
1379 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1380 *
1381 * Returns the newly created object.
1382 */
1383xmlXPathObjectPtr
1384xmlXPathNewBoolean(int val) {
1385 xmlXPathObjectPtr ret;
1386
Daniel Veillard6454aec1999-09-02 22:04:43 +00001387 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001388 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001389 xmlGenericError(xmlGenericErrorContext,
1390 "xmlXPathNewBoolean: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001391 return(NULL);
1392 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001393 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001394 ret->type = XPATH_BOOLEAN;
1395 ret->boolval = (val != 0);
1396 return(ret);
1397}
1398
1399/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001400 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001401 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001402 *
1403 * Create a new xmlXPathObjectPtr of type string and of value @val
1404 *
1405 * Returns the newly created object.
1406 */
1407xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001408xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001409 xmlXPathObjectPtr ret;
1410
Daniel Veillard6454aec1999-09-02 22:04:43 +00001411 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001412 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001413 xmlGenericError(xmlGenericErrorContext,
1414 "xmlXPathNewString: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001415 return(NULL);
1416 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001417 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001418 ret->type = XPATH_STRING;
Daniel Veillard5a2b6972001-01-20 21:15:50 +00001419 if (val != NULL)
1420 ret->stringval = xmlStrdup(val);
1421 else
1422 ret->stringval = xmlStrdup((const xmlChar *)"");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001423 return(ret);
1424}
1425
1426/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001427 * xmlXPathNewCString:
1428 * @val: the char * value
1429 *
1430 * Create a new xmlXPathObjectPtr of type string and of value @val
1431 *
1432 * Returns the newly created object.
1433 */
1434xmlXPathObjectPtr
1435xmlXPathNewCString(const char *val) {
1436 xmlXPathObjectPtr ret;
1437
Daniel Veillard6454aec1999-09-02 22:04:43 +00001438 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001439 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001440 xmlGenericError(xmlGenericErrorContext,
1441 "xmlXPathNewCString: out of memory\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001442 return(NULL);
1443 }
1444 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1445 ret->type = XPATH_STRING;
1446 ret->stringval = xmlStrdup(BAD_CAST val);
1447 return(ret);
1448}
1449
1450/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001451 * xmlXPathObjectCopy:
1452 * @val: the original object
1453 *
1454 * allocate a new copy of a given object
1455 *
1456 * Returns the newly created object.
1457 */
1458xmlXPathObjectPtr
1459xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1460 xmlXPathObjectPtr ret;
1461
1462 if (val == NULL)
1463 return(NULL);
1464
1465 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1466 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001467 xmlGenericError(xmlGenericErrorContext,
1468 "xmlXPathObjectCopy: out of memory\n");
Daniel Veillard2d38f042000-10-11 10:54:10 +00001469 return(NULL);
1470 }
1471 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1472 switch (val->type) {
1473 case XPATH_BOOLEAN:
1474 case XPATH_NUMBER:
Daniel Veillard2d38f042000-10-11 10:54:10 +00001475 case XPATH_POINT:
1476 case XPATH_RANGE:
1477 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00001478 case XPATH_STRING:
1479 ret->stringval = xmlStrdup(val->stringval);
Daniel Veillarde99a4762001-02-01 04:34:35 +00001480 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00001481 case XPATH_XSLT_TREE:
Daniel Veillard8a7642f2001-01-22 10:45:16 +00001482 if ((val->nodesetval != NULL) &&
1483 (val->nodesetval->nodeTab != NULL))
1484 ret->nodesetval = xmlXPathNodeSetCreate(
1485 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
1486 else
1487 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
1488 break;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001489 case XPATH_NODESET:
1490 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1491 break;
1492 case XPATH_LOCATIONSET:
1493#ifdef LIBXML_XPTR_ENABLED
1494 {
1495 xmlLocationSetPtr loc = val->user;
1496 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1497 break;
1498 }
1499#endif
1500 case XPATH_UNDEFINED:
1501 case XPATH_USERS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001502 xmlGenericError(xmlGenericErrorContext,
1503 "xmlXPathObjectCopy: unsupported type %d\n",
Daniel Veillard2d38f042000-10-11 10:54:10 +00001504 val->type);
Daniel Veillarde4566462001-01-22 09:58:39 +00001505 break;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001506 }
1507 return(ret);
1508}
1509
1510/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001511 * xmlXPathFreeObject:
1512 * @obj: the object to free
1513 *
1514 * Free up an xmlXPathObjectPtr object.
1515 */
1516void
1517xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1518 if (obj == NULL) return;
Daniel Veillardac260302000-10-04 13:33:43 +00001519 if (obj->type == XPATH_NODESET) {
1520 if (obj->nodesetval != NULL)
1521 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001522#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard7e99c632000-10-06 12:59:53 +00001523 } else if (obj->type == XPATH_LOCATIONSET) {
1524 if (obj->user != NULL)
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00001525 xmlXPtrFreeLocationSet(obj->user);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001526#endif
Daniel Veillardac260302000-10-04 13:33:43 +00001527 } else if (obj->type == XPATH_STRING) {
1528 if (obj->stringval != NULL)
1529 xmlFree(obj->stringval);
Daniel Veillarde4566462001-01-22 09:58:39 +00001530 } else if (obj->type == XPATH_XSLT_TREE) {
1531 if (obj->nodesetval != NULL)
Daniel Veillard8a7642f2001-01-22 10:45:16 +00001532 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillardac260302000-10-04 13:33:43 +00001533 }
1534
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001535#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001536 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001537#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001538 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001539}
1540
1541/************************************************************************
1542 * *
1543 * Routines to handle XPath contexts *
1544 * *
1545 ************************************************************************/
1546
1547/**
1548 * xmlXPathNewContext:
1549 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001550 *
1551 * Create a new xmlXPathContext
1552 *
1553 * Returns the xmlXPathContext just allocated.
1554 */
1555xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001556xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001557 xmlXPathContextPtr ret;
1558
Daniel Veillard6454aec1999-09-02 22:04:43 +00001559 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001560 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001561 xmlGenericError(xmlGenericErrorContext,
1562 "xmlXPathNewContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001563 return(NULL);
1564 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001565 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001566 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001567 ret->node = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001568
Daniel Veillard126f2792000-10-24 17:10:12 +00001569 ret->varHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001570
1571 ret->nb_types = 0;
1572 ret->max_types = 0;
1573 ret->types = NULL;
1574
Daniel Veillard52afe802000-10-22 16:56:02 +00001575 ret->funcHash = xmlHashCreate(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001576
1577 ret->nb_axis = 0;
1578 ret->max_axis = 0;
1579 ret->axis = NULL;
1580
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001581 ret->nsHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001582 ret->user = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001583
1584 ret->contextSize = -1;
1585 ret->proximityPosition = -1;
Daniel Veillard52afe802000-10-22 16:56:02 +00001586
1587 xmlXPathRegisterAllFunctions(ret);
1588
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001589 return(ret);
1590}
1591
1592/**
1593 * xmlXPathFreeContext:
1594 * @ctxt: the context to free
1595 *
1596 * Free up an xmlXPathContext
1597 */
1598void
1599xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001600 xmlXPathRegisteredNsCleanup(ctxt);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001601 xmlXPathRegisteredFuncsCleanup(ctxt);
1602 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001603#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001604 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001605#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001606 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001607}
1608
1609/************************************************************************
1610 * *
1611 * Routines to handle XPath parser contexts *
1612 * *
1613 ************************************************************************/
1614
Daniel Veillard740abf52000-10-02 23:04:54 +00001615#define CHECK_CTXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001616 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001617 xmlGenericError(xmlGenericErrorContext, \
1618 "%s:%d Internal error: ctxt == NULL\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001619 __FILE__, __LINE__); \
1620 } \
1621
1622
Daniel Veillard740abf52000-10-02 23:04:54 +00001623#define CHECK_CONTEXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001624 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001625 xmlGenericError(xmlGenericErrorContext, \
1626 "%s:%d Internal error: no context\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001627 __FILE__, __LINE__); \
1628 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001629 else if (ctxt->doc == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001630 xmlGenericError(xmlGenericErrorContext, \
1631 "%s:%d Internal error: no document\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001632 __FILE__, __LINE__); \
1633 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001634 else if (ctxt->doc->children == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001635 xmlGenericError(xmlGenericErrorContext, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001636 "%s:%d Internal error: document without root\n", \
1637 __FILE__, __LINE__); \
1638 } \
1639
1640
1641/**
1642 * xmlXPathNewParserContext:
1643 * @str: the XPath expression
1644 * @ctxt: the XPath context
1645 *
1646 * Create a new xmlXPathParserContext
1647 *
1648 * Returns the xmlXPathParserContext just allocated.
1649 */
1650xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001651xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001652 xmlXPathParserContextPtr ret;
1653
Daniel Veillard6454aec1999-09-02 22:04:43 +00001654 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001655 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001656 xmlGenericError(xmlGenericErrorContext,
1657 "xmlXPathNewParserContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001658 return(NULL);
1659 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001660 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001661 ret->cur = ret->base = str;
1662 ret->context = ctxt;
1663
1664 /* Allocate the value stack */
1665 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001666 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001667 ret->valueNr = 0;
1668 ret->valueMax = 10;
1669 ret->value = NULL;
1670 return(ret);
1671}
1672
1673/**
1674 * xmlXPathFreeParserContext:
1675 * @ctxt: the context to free
1676 *
1677 * Free up an xmlXPathParserContext
1678 */
1679void
1680xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1681 if (ctxt->valueTab != NULL) {
1682#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001683 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001684#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001685 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001686 }
1687#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001688 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001689#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001690 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001691}
1692
1693/************************************************************************
1694 * *
1695 * The implicit core function library *
1696 * *
1697 ************************************************************************/
1698
1699/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001700 * Auto-pop and cast to a number
1701 */
1702void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1703
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001704
1705#define POP_FLOAT \
1706 arg = valuePop(ctxt); \
1707 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001708 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001709 } \
1710 if (arg->type != XPATH_NUMBER) { \
1711 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001712 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001713 arg = valuePop(ctxt); \
1714 }
1715
1716/**
Daniel Veillard389e6b72001-01-15 19:41:13 +00001717 * xmlXPathCompareNodeSetFloat:
1718 * @ctxt: the XPath Parser context
1719 * @inf: less than (1) or greater than (0)
1720 * @strict: is the comparison strict
1721 * @arg: the node set
1722 * @f: the value
1723 *
1724 * Implement the compare operation between a nodeset and a number
1725 * @ns < @val (1, 1, ...
1726 * @ns <= @val (1, 0, ...
1727 * @ns > @val (0, 1, ...
1728 * @ns >= @val (0, 0, ...
1729 *
1730 * If one object to be compared is a node-set and the other is a number,
1731 * then the comparison will be true if and only if there is a node in the
1732 * node-set such that the result of performing the comparison on the number
1733 * to be compared and on the result of converting the string-value of that
1734 * node to a number using the number function is true.
1735 *
1736 * Returns 0 or 1 depending on the results of the test.
1737 */
1738int
1739xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
1740 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
1741 int i, ret = 0;
1742 xmlNodeSetPtr ns;
1743 xmlChar *str2;
1744
Daniel Veillarde99a4762001-02-01 04:34:35 +00001745 if ((f == NULL) || (arg == NULL) ||
1746 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00001747 xmlXPathFreeObject(arg);
1748 xmlXPathFreeObject(f);
1749 return(0);
1750 }
1751 ns = arg->nodesetval;
1752 for (i = 0;i < ns->nodeNr;i++) {
1753 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1754 if (str2 != NULL) {
1755 valuePush(ctxt,
1756 xmlXPathNewString(str2));
1757 xmlFree(str2);
1758 xmlXPathNumberFunction(ctxt, 1);
1759 valuePush(ctxt, xmlXPathObjectCopy(f));
1760 ret = xmlXPathCompareValues(ctxt, inf, strict);
1761 if (ret)
1762 break;
1763 }
1764 }
1765 xmlXPathFreeObject(arg);
1766 xmlXPathFreeObject(f);
1767 return(ret);
1768}
1769
1770/**
1771 * xmlXPathCompareNodeSetString:
1772 * @ctxt: the XPath Parser context
1773 * @inf: less than (1) or greater than (0)
1774 * @strict: is the comparison strict
1775 * @arg: the node set
1776 * @s: the value
1777 *
1778 * Implement the compare operation between a nodeset and a string
1779 * @ns < @val (1, 1, ...
1780 * @ns <= @val (1, 0, ...
1781 * @ns > @val (0, 1, ...
1782 * @ns >= @val (0, 0, ...
1783 *
1784 * If one object to be compared is a node-set and the other is a string,
1785 * then the comparison will be true if and only if there is a node in
1786 * the node-set such that the result of performing the comparison on the
1787 * string-value of the node and the other string is true.
1788 *
1789 * Returns 0 or 1 depending on the results of the test.
1790 */
1791int
1792xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
1793 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
1794 int i, ret = 0;
1795 xmlNodeSetPtr ns;
1796 xmlChar *str2;
1797
Daniel Veillarde99a4762001-02-01 04:34:35 +00001798 if ((s == NULL) || (arg == NULL) ||
1799 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00001800 xmlXPathFreeObject(arg);
1801 xmlXPathFreeObject(s);
1802 return(0);
1803 }
1804 ns = arg->nodesetval;
1805 for (i = 0;i < ns->nodeNr;i++) {
1806 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1807 if (str2 != NULL) {
1808 valuePush(ctxt,
1809 xmlXPathNewString(str2));
1810 xmlFree(str2);
1811 valuePush(ctxt, xmlXPathObjectCopy(s));
1812 ret = xmlXPathCompareValues(ctxt, inf, strict);
1813 if (ret)
1814 break;
1815 }
1816 }
1817 xmlXPathFreeObject(arg);
1818 xmlXPathFreeObject(s);
1819 return(ret);
1820}
1821
1822/**
1823 * xmlXPathCompareNodeSets:
1824 * @ctxt: the XPath Parser context
1825 * @op: less than (-1), equal (0) or greater than (1)
1826 * @strict: is the comparison strict
1827 * @ns1: the fist node set
1828 * @ns2: the second node set
1829 *
1830 * Implement the compare operation on nodesets:
1831 *
1832 * If both objects to be compared are node-sets, then the comparison will be true if
1833 * and only if there is a node in the first node-set and a node in the second node-set
1834 * such that the result of performing the comparison on the string-values of the two
1835 * nodes is true.
1836 */
1837int
1838xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
1839 xmlXPathObjectPtr ns1, xmlXPathObjectPtr ns2) {
1840 TODO
1841 return(0);
1842}
1843
1844/**
1845 * xmlXPathCompareNodeSetValue:
1846 * @ctxt: the XPath Parser context
1847 * @inf: less than (1) or greater than (0)
1848 * @strict: is the comparison strict
1849 * @arg: the node set
1850 * @val: the value
1851 *
1852 * Implement the compare operation between a nodeset and a value
1853 * @ns < @val (1, 1, ...
1854 * @ns <= @val (1, 0, ...
1855 * @ns > @val (0, 1, ...
1856 * @ns >= @val (0, 0, ...
1857 *
1858 * If one object to be compared is a node-set and the other is a boolean, then the
1859 * comparison will be true if and only if the result of performing the comparison
1860 * on the boolean and on the result of converting the node-set to a boolean using
1861 * the boolean function is true.
1862 *
1863 * Returns 0 or 1 depending on the results of the test.
1864 */
1865int
1866xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
1867 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
Daniel Veillarde99a4762001-02-01 04:34:35 +00001868 if ((val == NULL) || (arg == NULL) ||
1869 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard389e6b72001-01-15 19:41:13 +00001870 return(0);
1871
1872 switch(val->type) {
1873 case XPATH_NUMBER:
1874 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
1875 case XPATH_NODESET:
Daniel Veillarde99a4762001-02-01 04:34:35 +00001876 case XPATH_XSLT_TREE:
Daniel Veillard389e6b72001-01-15 19:41:13 +00001877 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
1878 case XPATH_STRING:
1879 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
1880 case XPATH_BOOLEAN:
1881 valuePush(ctxt, arg);
1882 xmlXPathBooleanFunction(ctxt, 1);
1883 valuePush(ctxt, val);
1884 return(xmlXPathCompareValues(ctxt, inf, strict));
1885 default:
1886 TODO
1887 return(0);
1888 }
1889 return(0);
1890}
1891
1892/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001893 * xmlXPathEqualNodeSetString
1894 * @arg: the nodeset object argument
1895 * @str: the string to compare to.
1896 *
1897 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1898 * If one object to be compared is a node-set and the other is a string,
1899 * then the comparison will be true if and only if there is a node in
1900 * the node-set such that the result of performing the comparison on the
1901 * string-value of the node and the other string is true.
1902 *
1903 * Returns 0 or 1 depending on the results of the test.
1904 */
1905int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001906xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001907 int i;
1908 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001909 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001910
Daniel Veillarde99a4762001-02-01 04:34:35 +00001911 if ((str == NULL) || (arg == NULL) ||
1912 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001913 return(0);
1914 ns = arg->nodesetval;
1915 for (i = 0;i < ns->nodeNr;i++) {
1916 str2 = xmlNodeGetContent(ns->nodeTab[i]);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001917 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001918 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001919 return(1);
1920 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001921 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001922 }
1923 return(0);
1924}
1925
1926/**
1927 * xmlXPathEqualNodeSetFloat
1928 * @arg: the nodeset object argument
1929 * @f: the float to compare to
1930 *
1931 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1932 * If one object to be compared is a node-set and the other is a number,
1933 * then the comparison will be true if and only if there is a node in
1934 * the node-set such that the result of performing the comparison on the
1935 * number to be compared and on the result of converting the string-value
1936 * of that node to a number using the number function is true.
1937 *
1938 * Returns 0 or 1 depending on the results of the test.
1939 */
1940int
1941xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001942 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001943
Daniel Veillarde99a4762001-02-01 04:34:35 +00001944 if ((arg == NULL) ||
1945 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001946 return(0);
1947
1948 if (isnan(f))
1949 sprintf(buf, "NaN");
1950 else if (isinf(f) > 0)
1951 sprintf(buf, "+Infinity");
1952 else if (isinf(f) < 0)
1953 sprintf(buf, "-Infinity");
1954 else
1955 sprintf(buf, "%0g", f);
1956
Daniel Veillardb96e6431999-08-29 21:02:19 +00001957 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001958}
1959
1960
1961/**
1962 * xmlXPathEqualNodeSets
1963 * @arg1: first nodeset object argument
1964 * @arg2: second nodeset object argument
1965 *
1966 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1967 * If both objects to be compared are node-sets, then the comparison
1968 * will be true if and only if there is a node in the first node-set and
1969 * a node in the second node-set such that the result of performing the
1970 * comparison on the string-values of the two nodes is true.
1971 *
1972 * (needless to say, this is a costly operation)
1973 *
1974 * Returns 0 or 1 depending on the results of the test.
1975 */
1976int
1977xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1978 int i;
1979 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001980 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001981
Daniel Veillarde99a4762001-02-01 04:34:35 +00001982 if ((arg1 == NULL) ||
1983 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001984 return(0);
Daniel Veillarde99a4762001-02-01 04:34:35 +00001985 if ((arg2 == NULL) ||
1986 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001987 return(0);
1988
1989 ns = arg1->nodesetval;
1990 for (i = 0;i < ns->nodeNr;i++) {
1991 str = xmlNodeGetContent(ns->nodeTab[i]);
1992 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001993 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001994 return(1);
1995 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001996 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001997 }
1998 return(0);
1999}
2000
2001/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002002 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002003 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002004 *
2005 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2006 *
2007 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002008 */
2009int
Daniel Veillard991e63d1999-08-15 23:32:28 +00002010xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2011 xmlXPathObjectPtr arg1, arg2;
2012 int ret = 0;
2013
2014 arg1 = valuePop(ctxt);
2015 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002016 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002017
2018 arg2 = valuePop(ctxt);
2019 if (arg2 == NULL) {
2020 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002021 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002022 }
2023
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002024 if (arg1 == arg2) {
2025#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002026 xmlGenericError(xmlGenericErrorContext,
2027 "Equal: by pointer\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002028#endif
2029 return(1);
2030 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00002031
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002032 switch (arg1->type) {
2033 case XPATH_UNDEFINED:
2034#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;
Daniel Veillarde4566462001-01-22 09:58:39 +00002039 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002040 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002041 switch (arg2->type) {
2042 case XPATH_UNDEFINED:
2043#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002044 xmlGenericError(xmlGenericErrorContext,
2045 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00002046#endif
2047 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00002048 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002049 case XPATH_NODESET:
2050 ret = xmlXPathEqualNodeSets(arg1, arg2);
2051 break;
2052 case XPATH_BOOLEAN:
2053 if ((arg1->nodesetval == NULL) ||
2054 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2055 else
2056 ret = 1;
2057 ret = (ret == arg2->boolval);
2058 break;
2059 case XPATH_NUMBER:
2060 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2061 break;
2062 case XPATH_STRING:
2063 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2064 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002065 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002066 case XPATH_POINT:
2067 case XPATH_RANGE:
2068 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002069 TODO
2070 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002071 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002072 break;
2073 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002074 switch (arg2->type) {
2075 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002076#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002077 xmlGenericError(xmlGenericErrorContext,
2078 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002079#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00002080 break;
2081 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002082 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002083 if ((arg2->nodesetval == NULL) ||
2084 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2085 else
2086 ret = 1;
2087 break;
2088 case XPATH_BOOLEAN:
2089#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002090 xmlGenericError(xmlGenericErrorContext,
2091 "Equal: %d boolean %d \n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00002092 arg1->boolval, arg2->boolval);
2093#endif
2094 ret = (arg1->boolval == arg2->boolval);
2095 break;
2096 case XPATH_NUMBER:
2097 if (arg2->floatval) ret = 1;
2098 else ret = 0;
2099 ret = (arg1->boolval == ret);
2100 break;
2101 case XPATH_STRING:
2102 if ((arg2->stringval == NULL) ||
2103 (arg2->stringval[0] == 0)) ret = 0;
2104 else
2105 ret = 1;
2106 ret = (arg1->boolval == ret);
2107 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002108 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002109 case XPATH_POINT:
2110 case XPATH_RANGE:
2111 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002112 TODO
2113 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002114 }
2115 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002116 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002117 switch (arg2->type) {
2118 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002119#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002120 xmlGenericError(xmlGenericErrorContext,
2121 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002122#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00002123 break;
2124 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002125 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002126 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2127 break;
2128 case XPATH_BOOLEAN:
2129 if (arg1->floatval) ret = 1;
2130 else ret = 0;
2131 ret = (arg2->boolval == ret);
2132 break;
2133 case XPATH_STRING:
2134 valuePush(ctxt, arg2);
2135 xmlXPathNumberFunction(ctxt, 1);
2136 arg2 = valuePop(ctxt);
2137 /* no break on purpose */
2138 case XPATH_NUMBER:
2139 ret = (arg1->floatval == arg2->floatval);
2140 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002141 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002142 case XPATH_POINT:
2143 case XPATH_RANGE:
2144 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002145 TODO
2146 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002147 }
2148 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002149 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002150 switch (arg2->type) {
2151 case XPATH_UNDEFINED:
2152#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002153 xmlGenericError(xmlGenericErrorContext,
2154 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00002155#endif
2156 break;
2157 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002158 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002159 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2160 break;
2161 case XPATH_BOOLEAN:
2162 if ((arg1->stringval == NULL) ||
2163 (arg1->stringval[0] == 0)) ret = 0;
2164 else
2165 ret = 1;
2166 ret = (arg2->boolval == ret);
2167 break;
2168 case XPATH_STRING:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002169 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002170 break;
2171 case XPATH_NUMBER:
2172 valuePush(ctxt, arg1);
2173 xmlXPathNumberFunction(ctxt, 1);
2174 arg1 = valuePop(ctxt);
2175 ret = (arg1->floatval == arg2->floatval);
2176 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002177 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002178 case XPATH_POINT:
2179 case XPATH_RANGE:
2180 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002181 TODO
2182 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002183 }
2184 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002185 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002186 case XPATH_POINT:
2187 case XPATH_RANGE:
2188 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002189 TODO
2190 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002191 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00002192 xmlXPathFreeObject(arg1);
2193 xmlXPathFreeObject(arg2);
2194 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002195}
2196
Daniel Veillard389e6b72001-01-15 19:41:13 +00002197
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002198/**
2199 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002200 * @ctxt: the XPath Parser context
Daniel Veillard389e6b72001-01-15 19:41:13 +00002201 * @inf: less than (1) or greater than (0)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002202 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002203 *
2204 * Implement the compare operation on XPath objects:
2205 * @arg1 < @arg2 (1, 1, ...
2206 * @arg1 <= @arg2 (1, 0, ...
2207 * @arg1 > @arg2 (0, 1, ...
2208 * @arg1 >= @arg2 (0, 0, ...
2209 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00002210 * When neither object to be compared is a node-set and the operator is
2211 * <=, <, >=, >, then the objects are compared by converted both objects
2212 * to numbers and comparing the numbers according to IEEE 754. The <
2213 * comparison will be true if and only if the first number is less than the
2214 * second number. The <= comparison will be true if and only if the first
2215 * number is less than or equal to the second number. The > comparison
2216 * will be true if and only if the first number is greater than the second
2217 * number. The >= comparison will be true if and only if the first number
2218 * is greater than or equal to the second number.
Daniel Veillard389e6b72001-01-15 19:41:13 +00002219 *
2220 * Returns 1 if the comparaison succeeded, 0 if it failed
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002221 */
2222int
Daniel Veillard991e63d1999-08-15 23:32:28 +00002223xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
2224 int ret = 0;
2225 xmlXPathObjectPtr arg1, arg2;
2226
2227 arg2 = valuePop(ctxt);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002228 if (arg2 == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002229 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002230 }
2231
2232 arg1 = valuePop(ctxt);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002233 if (arg1 == NULL) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00002234 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002235 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002236 }
2237
Daniel Veillard389e6b72001-01-15 19:41:13 +00002238 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
2239 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
2240 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
2241 } else {
2242 if (arg1->type == XPATH_NODESET) {
2243 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, arg1, arg2);
2244 } else {
2245 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, !strict, arg2, arg2);
2246 }
2247 }
2248 return(ret);
2249 }
2250
Daniel Veillard991e63d1999-08-15 23:32:28 +00002251 if (arg1->type != XPATH_NUMBER) {
2252 valuePush(ctxt, arg1);
2253 xmlXPathNumberFunction(ctxt, 1);
2254 arg1 = valuePop(ctxt);
2255 }
2256 if (arg1->type != XPATH_NUMBER) {
2257 xmlXPathFreeObject(arg1);
2258 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002259 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002260 }
2261 if (arg2->type != XPATH_NUMBER) {
2262 valuePush(ctxt, arg2);
2263 xmlXPathNumberFunction(ctxt, 1);
2264 arg2 = valuePop(ctxt);
2265 }
2266 if (arg2->type != XPATH_NUMBER) {
2267 xmlXPathFreeObject(arg1);
2268 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002269 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002270 }
2271 /*
2272 * Add tests for infinity and nan
2273 * => feedback on 3.4 for Inf and NaN
2274 */
2275 if (inf && strict)
2276 ret = (arg1->floatval < arg2->floatval);
2277 else if (inf && !strict)
2278 ret = (arg1->floatval <= arg2->floatval);
2279 else if (!inf && strict)
2280 ret = (arg1->floatval > arg2->floatval);
2281 else if (!inf && !strict)
2282 ret = (arg1->floatval >= arg2->floatval);
2283 xmlXPathFreeObject(arg1);
2284 xmlXPathFreeObject(arg2);
2285 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002286}
2287
2288/**
2289 * xmlXPathValueFlipSign:
2290 * @ctxt: the XPath Parser context
2291 *
2292 * Implement the unary - operation on an XPath object
2293 * The numeric operators convert their operands to numbers as if
2294 * by calling the number function.
2295 */
2296void
2297xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
2298 xmlXPathObjectPtr arg;
2299
2300 POP_FLOAT
2301 arg->floatval = -arg->floatval;
2302 valuePush(ctxt, arg);
2303}
2304
2305/**
2306 * xmlXPathAddValues:
2307 * @ctxt: the XPath Parser context
2308 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002309 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002310 * The numeric operators convert their operands to numbers as if
2311 * by calling the number function.
2312 */
2313void
2314xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
2315 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002316 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002317
2318 POP_FLOAT
2319 val = arg->floatval;
2320 xmlXPathFreeObject(arg);
2321
2322 POP_FLOAT
2323 arg->floatval += val;
2324 valuePush(ctxt, arg);
2325}
2326
2327/**
2328 * xmlXPathSubValues:
2329 * @ctxt: the XPath Parser context
2330 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002331 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002332 * The numeric operators convert their operands to numbers as if
2333 * by calling the number function.
2334 */
2335void
2336xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
2337 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002338 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002339
2340 POP_FLOAT
2341 val = arg->floatval;
2342 xmlXPathFreeObject(arg);
2343
2344 POP_FLOAT
2345 arg->floatval -= val;
2346 valuePush(ctxt, arg);
2347}
2348
2349/**
2350 * xmlXPathMultValues:
2351 * @ctxt: the XPath Parser context
2352 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002353 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002354 * The numeric operators convert their operands to numbers as if
2355 * by calling the number function.
2356 */
2357void
2358xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
2359 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002360 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002361
2362 POP_FLOAT
2363 val = arg->floatval;
2364 xmlXPathFreeObject(arg);
2365
2366 POP_FLOAT
2367 arg->floatval *= val;
2368 valuePush(ctxt, arg);
2369}
2370
2371/**
2372 * xmlXPathDivValues:
2373 * @ctxt: the XPath Parser context
2374 *
Daniel Veillard2b325a02001-01-31 20:46:31 +00002375 * Implement the div operation on XPath objects @arg1 / @arg2:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002376 * The numeric operators convert their operands to numbers as if
2377 * by calling the number function.
2378 */
2379void
2380xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
2381 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002382 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002383
2384 POP_FLOAT
2385 val = arg->floatval;
2386 xmlXPathFreeObject(arg);
2387
2388 POP_FLOAT
2389 arg->floatval /= val;
2390 valuePush(ctxt, arg);
2391}
2392
2393/**
2394 * xmlXPathModValues:
2395 * @ctxt: the XPath Parser context
2396 *
Daniel Veillard2b325a02001-01-31 20:46:31 +00002397 * Implement the mod operation on XPath objects: @arg1 / @arg2
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002398 * The numeric operators convert their operands to numbers as if
2399 * by calling the number function.
2400 */
2401void
2402xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
2403 xmlXPathObjectPtr arg;
Daniel Veillard2b325a02001-01-31 20:46:31 +00002404 int arg1, arg2;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002405
2406 POP_FLOAT
Daniel Veillard2b325a02001-01-31 20:46:31 +00002407 arg2 = (int) arg->floatval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002408 xmlXPathFreeObject(arg);
2409
2410 POP_FLOAT
Daniel Veillard2b325a02001-01-31 20:46:31 +00002411 arg1 = (int) arg->floatval;
2412 arg->floatval = arg1 % arg2;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002413 valuePush(ctxt, arg);
2414}
2415
2416/************************************************************************
2417 * *
2418 * The traversal functions *
2419 * *
2420 ************************************************************************/
2421
Daniel Veillard740abf52000-10-02 23:04:54 +00002422typedef enum {
2423 AXIS_ANCESTOR = 1,
2424 AXIS_ANCESTOR_OR_SELF,
2425 AXIS_ATTRIBUTE,
2426 AXIS_CHILD,
2427 AXIS_DESCENDANT,
2428 AXIS_DESCENDANT_OR_SELF,
2429 AXIS_FOLLOWING,
2430 AXIS_FOLLOWING_SIBLING,
2431 AXIS_NAMESPACE,
2432 AXIS_PARENT,
2433 AXIS_PRECEDING,
2434 AXIS_PRECEDING_SIBLING,
2435 AXIS_SELF
2436} xmlXPathAxisVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002437
2438/*
2439 * A traversal function enumerates nodes along an axis.
2440 * Initially it must be called with NULL, and it indicates
2441 * termination on the axis by returning NULL.
2442 */
2443typedef xmlNodePtr (*xmlXPathTraversalFunction)
2444 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
2445
2446/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002447 * xmlXPathNextSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002448 * @ctxt: the XPath Parser context
2449 * @cur: the current node in the traversal
2450 *
2451 * Traversal function for the "self" direction
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002452 * The self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00002453 *
2454 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002455 */
2456xmlNodePtr
2457xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2458 if (cur == NULL)
2459 return(ctxt->context->node);
2460 return(NULL);
2461}
2462
2463/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002464 * xmlXPathNextChild:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002465 * @ctxt: the XPath Parser context
2466 * @cur: the current node in the traversal
2467 *
2468 * Traversal function for the "child" direction
2469 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002470 *
2471 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002472 */
2473xmlNodePtr
2474xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002475 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002476 if (ctxt->context->node == NULL) return(NULL);
2477 switch (ctxt->context->node->type) {
2478 case XML_ELEMENT_NODE:
2479 case XML_TEXT_NODE:
2480 case XML_CDATA_SECTION_NODE:
2481 case XML_ENTITY_REF_NODE:
2482 case XML_ENTITY_NODE:
2483 case XML_PI_NODE:
2484 case XML_COMMENT_NODE:
2485 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002486 case XML_DTD_NODE:
2487 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002488 case XML_DOCUMENT_NODE:
2489 case XML_DOCUMENT_TYPE_NODE:
2490 case XML_DOCUMENT_FRAG_NODE:
2491 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002492#ifdef LIBXML_SGML_ENABLED
2493 case XML_SGML_DOCUMENT_NODE:
2494#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002495 return(((xmlDocPtr) ctxt->context->node)->children);
2496 case XML_ELEMENT_DECL:
2497 case XML_ATTRIBUTE_DECL:
2498 case XML_ENTITY_DECL:
2499 case XML_ATTRIBUTE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002500 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002501 case XML_XINCLUDE_START:
2502 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002503 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002504 }
2505 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002506 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002507 if ((cur->type == XML_DOCUMENT_NODE) ||
2508 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002509 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002510 return(cur->next);
2511}
2512
2513/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002514 * xmlXPathNextDescendant:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002515 * @ctxt: the XPath Parser context
2516 * @cur: the current node in the traversal
2517 *
2518 * Traversal function for the "descendant" direction
2519 * the descendant axis contains the descendants of the context node in document
2520 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002521 *
2522 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002523 */
2524xmlNodePtr
2525xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002526 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002527 if (ctxt->context->node == NULL)
2528 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002529 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2530 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002531 return(NULL);
2532
Daniel Veillardb05deb71999-08-10 19:04:08 +00002533 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00002534 return(ctxt->context->doc->children);
2535 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002536 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002537
Daniel Veillardbe803962000-06-28 23:40:59 +00002538 if (cur->children != NULL)
2539 {
2540 if (cur->children->type != XML_ENTITY_DECL)
2541 return(cur->children);
2542 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002543 if (cur->next != NULL) return(cur->next);
2544
2545 do {
2546 cur = cur->parent;
2547 if (cur == NULL) return(NULL);
2548 if (cur == ctxt->context->node) return(NULL);
2549 if (cur->next != NULL) {
2550 cur = cur->next;
2551 return(cur);
2552 }
2553 } while (cur != NULL);
2554 return(cur);
2555}
2556
2557/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002558 * xmlXPathNextDescendantOrSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002559 * @ctxt: the XPath Parser context
2560 * @cur: the current node in the traversal
2561 *
2562 * Traversal function for the "descendant-or-self" direction
2563 * the descendant-or-self axis contains the context node and the descendants
2564 * of the context node in document order; thus the context node is the first
2565 * node on the axis, and the first child of the context node is the second node
2566 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002567 *
2568 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002569 */
2570xmlNodePtr
2571xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002572 if (cur == NULL) {
2573 if (ctxt->context->node == NULL)
2574 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002575 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2576 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002577 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002578 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002579 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002580
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002581 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002582}
2583
2584/**
2585 * xmlXPathNextParent:
2586 * @ctxt: the XPath Parser context
2587 * @cur: the current node in the traversal
2588 *
2589 * Traversal function for the "parent" direction
2590 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002591 *
2592 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002593 */
2594xmlNodePtr
2595xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2596 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002597 * the parent of an attribute or namespace node is the element
2598 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002599 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002600 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002601 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002602 if (ctxt->context->node == NULL) return(NULL);
2603 switch (ctxt->context->node->type) {
2604 case XML_ELEMENT_NODE:
2605 case XML_TEXT_NODE:
2606 case XML_CDATA_SECTION_NODE:
2607 case XML_ENTITY_REF_NODE:
2608 case XML_ENTITY_NODE:
2609 case XML_PI_NODE:
2610 case XML_COMMENT_NODE:
2611 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002612 case XML_DTD_NODE:
2613 case XML_ELEMENT_DECL:
2614 case XML_ATTRIBUTE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002615 case XML_XINCLUDE_START:
2616 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002617 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002618 if (ctxt->context->node->parent == NULL)
2619 return((xmlNodePtr) ctxt->context->doc);
2620 return(ctxt->context->node->parent);
2621 case XML_ATTRIBUTE_NODE: {
2622 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2623
Daniel Veillardcf461992000-03-14 18:30:20 +00002624 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002625 }
2626 case XML_DOCUMENT_NODE:
2627 case XML_DOCUMENT_TYPE_NODE:
2628 case XML_DOCUMENT_FRAG_NODE:
2629 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002630#ifdef LIBXML_SGML_ENABLED
2631 case XML_SGML_DOCUMENT_NODE:
2632#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002633 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002634 case XML_NAMESPACE_DECL:
2635 /*
2636 * TODO !!! may require extending struct _xmlNs with
2637 * parent field
2638 * C.f. Infoset case...
2639 */
2640 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002641 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002642 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002643 return(NULL);
2644}
2645
2646/**
2647 * xmlXPathNextAncestor:
2648 * @ctxt: the XPath Parser context
2649 * @cur: the current node in the traversal
2650 *
2651 * Traversal function for the "ancestor" direction
2652 * the ancestor axis contains the ancestors of the context node; the ancestors
2653 * of the context node consist of the parent of context node and the parent's
2654 * parent and so on; the nodes are ordered in reverse document order; thus the
2655 * parent is the first node on the axis, and the parent's parent is the second
2656 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002657 *
2658 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002659 */
2660xmlNodePtr
2661xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2662 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002663 * the parent of an attribute or namespace node is the element
2664 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002665 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002666 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002667 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002668 if (ctxt->context->node == NULL) return(NULL);
2669 switch (ctxt->context->node->type) {
2670 case XML_ELEMENT_NODE:
2671 case XML_TEXT_NODE:
2672 case XML_CDATA_SECTION_NODE:
2673 case XML_ENTITY_REF_NODE:
2674 case XML_ENTITY_NODE:
2675 case XML_PI_NODE:
2676 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002677 case XML_DTD_NODE:
2678 case XML_ELEMENT_DECL:
2679 case XML_ATTRIBUTE_DECL:
2680 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002681 case XML_NOTATION_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002682 case XML_XINCLUDE_START:
2683 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002684 if (ctxt->context->node->parent == NULL)
2685 return((xmlNodePtr) ctxt->context->doc);
2686 return(ctxt->context->node->parent);
2687 case XML_ATTRIBUTE_NODE: {
2688 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2689
Daniel Veillardcf461992000-03-14 18:30:20 +00002690 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002691 }
2692 case XML_DOCUMENT_NODE:
2693 case XML_DOCUMENT_TYPE_NODE:
2694 case XML_DOCUMENT_FRAG_NODE:
2695 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002696#ifdef LIBXML_SGML_ENABLED
2697 case XML_SGML_DOCUMENT_NODE:
2698#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002699 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002700 case XML_NAMESPACE_DECL:
2701 /*
2702 * TODO !!! may require extending struct _xmlNs with
2703 * parent field
2704 * C.f. Infoset case...
2705 */
2706 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002707 }
2708 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002709 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002710 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002711 return((xmlNodePtr) ctxt->context->doc);
2712 if (cur == (xmlNodePtr) ctxt->context->doc)
2713 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002714 switch (cur->type) {
2715 case XML_ELEMENT_NODE:
2716 case XML_TEXT_NODE:
2717 case XML_CDATA_SECTION_NODE:
2718 case XML_ENTITY_REF_NODE:
2719 case XML_ENTITY_NODE:
2720 case XML_PI_NODE:
2721 case XML_COMMENT_NODE:
2722 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002723 case XML_DTD_NODE:
2724 case XML_ELEMENT_DECL:
2725 case XML_ATTRIBUTE_DECL:
2726 case XML_ENTITY_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002727 case XML_XINCLUDE_START:
2728 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002729 return(cur->parent);
2730 case XML_ATTRIBUTE_NODE: {
2731 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2732
Daniel Veillardcf461992000-03-14 18:30:20 +00002733 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002734 }
2735 case XML_DOCUMENT_NODE:
2736 case XML_DOCUMENT_TYPE_NODE:
2737 case XML_DOCUMENT_FRAG_NODE:
2738 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002739#ifdef LIBXML_SGML_ENABLED
2740 case XML_SGML_DOCUMENT_NODE:
2741#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002742 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002743 case XML_NAMESPACE_DECL:
2744 /*
2745 * TODO !!! may require extending struct _xmlNs with
2746 * parent field
2747 * C.f. Infoset case...
2748 */
2749 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002750 }
2751 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002752}
2753
2754/**
2755 * xmlXPathNextAncestorOrSelf:
2756 * @ctxt: the XPath Parser context
2757 * @cur: the current node in the traversal
2758 *
2759 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00002760 * he ancestor-or-self axis contains the context node and ancestors of
2761 * the context node in reverse document order; thus the context node is
2762 * the first node on the axis, and the context node's parent the second;
2763 * parent here is defined the same as with the parent axis.
2764 *
2765 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002766 */
2767xmlNodePtr
2768xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002769 if (cur == NULL)
2770 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002771 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002772}
2773
2774/**
2775 * xmlXPathNextFollowingSibling:
2776 * @ctxt: the XPath Parser context
2777 * @cur: the current node in the traversal
2778 *
2779 * Traversal function for the "following-sibling" direction
2780 * The following-sibling axis contains the following siblings of the context
2781 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002782 *
2783 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002784 */
2785xmlNodePtr
2786xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002787 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2788 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2789 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002790 if (cur == (xmlNodePtr) ctxt->context->doc)
2791 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002792 if (cur == NULL)
2793 return(ctxt->context->node->next);
2794 return(cur->next);
2795}
2796
2797/**
2798 * xmlXPathNextPrecedingSibling:
2799 * @ctxt: the XPath Parser context
2800 * @cur: the current node in the traversal
2801 *
2802 * Traversal function for the "preceding-sibling" direction
2803 * The preceding-sibling axis contains the preceding siblings of the context
2804 * node in reverse document order; the first preceding sibling is first on the
2805 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002806 *
2807 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002808 */
2809xmlNodePtr
2810xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002811 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2812 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2813 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002814 if (cur == (xmlNodePtr) ctxt->context->doc)
2815 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002816 if (cur == NULL)
2817 return(ctxt->context->node->prev);
2818 return(cur->prev);
2819}
2820
2821/**
2822 * xmlXPathNextFollowing:
2823 * @ctxt: the XPath Parser context
2824 * @cur: the current node in the traversal
2825 *
2826 * Traversal function for the "following" direction
2827 * The following axis contains all nodes in the same document as the context
2828 * node that are after the context node in document order, excluding any
2829 * descendants and excluding attribute nodes and namespace nodes; the nodes
2830 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00002831 *
2832 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002833 */
2834xmlNodePtr
2835xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002836 if (cur != NULL && cur->children != NULL)
2837 return cur->children ;
Daniel Veillardac260302000-10-04 13:33:43 +00002838 if (cur == NULL) cur = ctxt->context->node;
2839 if (cur == NULL) return(NULL) ; /* ERROR */
2840 if (cur->next != NULL) return(cur->next) ;
Daniel Veillard740abf52000-10-02 23:04:54 +00002841 do {
2842 cur = cur->parent;
2843 if (cur == NULL) return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002844 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002845 if (cur->next != NULL) return(cur->next);
Daniel Veillard740abf52000-10-02 23:04:54 +00002846 } while (cur != NULL);
2847 return(cur);
2848}
2849
2850/*
Daniel Veillardac260302000-10-04 13:33:43 +00002851 * xmlXPathIsAncestor:
2852 * @ancestor: the ancestor node
2853 * @node: the current node
2854 *
2855 * Check that @ancestor is a @node's ancestor
2856 *
Daniel Veillard740abf52000-10-02 23:04:54 +00002857 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2858 */
2859static int
Daniel Veillardac260302000-10-04 13:33:43 +00002860xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002861 if ((ancestor == NULL) || (node == NULL)) return(0);
2862 /* nodes need to be in the same document */
2863 if (ancestor->doc != node->doc) return(0);
2864 /* avoid searching if ancestor or node is the root node */
2865 if (ancestor == (xmlNodePtr) node->doc) return(1);
2866 if (node == (xmlNodePtr) ancestor->doc) return(0);
2867 while (node->parent != NULL) {
2868 if (node->parent == ancestor)
2869 return(1);
2870 node = node->parent;
Daniel Veillard740abf52000-10-02 23:04:54 +00002871 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002872 return(0);
Daniel Veillard740abf52000-10-02 23:04:54 +00002873}
2874
2875/**
2876 * xmlXPathNextPreceding:
2877 * @ctxt: the XPath Parser context
2878 * @cur: the current node in the traversal
2879 *
2880 * Traversal function for the "preceding" direction
2881 * the preceding axis contains all nodes in the same document as the context
2882 * node that are before the context node in document order, excluding any
2883 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2884 * ordered in reverse document order
2885 *
2886 * Returns the next element following that axis
2887 */
2888xmlNodePtr
2889xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2890 if (cur == NULL)
2891 cur = ctxt->context->node ;
2892 do {
2893 if (cur->prev != NULL) {
2894 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2895 ;
2896 return(cur) ;
2897 }
2898
2899 cur = cur->parent;
2900 if (cur == NULL) return(NULL);
2901 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002902 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillard740abf52000-10-02 23:04:54 +00002903 return(cur);
2904}
2905
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002906/**
2907 * xmlXPathNextNamespace:
2908 * @ctxt: the XPath Parser context
2909 * @cur: the current attribute in the traversal
2910 *
2911 * Traversal function for the "namespace" direction
2912 * the namespace axis contains the namespace nodes of the context node;
2913 * the order of nodes on this axis is implementation-defined; the axis will
2914 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00002915 *
2916 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002917 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002918xmlNodePtr
2919xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2920 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002921 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2922 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002923 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002924 ctxt->context->namespaces =
2925 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2926 if (ctxt->context->namespaces == NULL) return(NULL);
2927 ctxt->context->nsNr = 0;
2928 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002929 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002930}
2931
2932/**
2933 * xmlXPathNextAttribute:
2934 * @ctxt: the XPath Parser context
2935 * @cur: the current attribute in the traversal
2936 *
2937 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00002938 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00002939 *
2940 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002941 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002942xmlNodePtr
2943xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2944 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002945 if (cur == NULL) {
2946 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2947 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002948 return((xmlNodePtr)ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002949 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002950 return((xmlNodePtr)cur->next);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002951}
2952
2953/************************************************************************
2954 * *
2955 * NodeTest Functions *
2956 * *
2957 ************************************************************************/
2958
Daniel Veillard740abf52000-10-02 23:04:54 +00002959typedef enum {
2960 NODE_TEST_NONE = 0,
2961 NODE_TEST_TYPE = 1,
2962 NODE_TEST_PI = 2,
2963 NODE_TEST_ALL = 3,
2964 NODE_TEST_NS = 4,
2965 NODE_TEST_NAME = 5
2966} xmlXPathTestVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002967
Daniel Veillard740abf52000-10-02 23:04:54 +00002968typedef enum {
Daniel Veillard2f913b72001-01-31 13:23:49 +00002969 NODE_TYPE_NODE = 0,
Daniel Veillard55b91f22000-10-05 16:30:11 +00002970 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
2971 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard2f913b72001-01-31 13:23:49 +00002972 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard740abf52000-10-02 23:04:54 +00002973} xmlXPathTypeVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002974
2975#define IS_FUNCTION 200
2976
2977/**
2978 * xmlXPathNodeCollectAndTest:
2979 * @ctxt: the XPath Parser context
Daniel Veillard740abf52000-10-02 23:04:54 +00002980 * @axis: the XPath axis
2981 * @test: the XPath test
2982 * @type: the XPath type
2983 * @prefix: the namesapce prefix if any
2984 * @name: the name used in the search if any
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002985 *
2986 * This is the function implementing a step: based on the current list
2987 * of nodes, it builds up a new list, looking at all nodes under that
2988 * axis and selecting them.
2989 *
2990 * Returns the new NodeSet resulting from the search.
2991 */
Daniel Veillard740abf52000-10-02 23:04:54 +00002992void
2993xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2994 xmlXPathTestVal test, xmlXPathTypeVal type,
2995 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002996#ifdef DEBUG_STEP
2997 int n = 0, t = 0;
2998#endif
2999 int i;
3000 xmlNodeSetPtr ret;
3001 xmlXPathTraversalFunction next = NULL;
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003002 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003003 xmlNodePtr cur = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00003004 xmlXPathObjectPtr obj;
3005 xmlNodeSetPtr nodelist;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003006
Daniel Veillard740abf52000-10-02 23:04:54 +00003007 CHECK_TYPE(XPATH_NODESET);
3008 obj = valuePop(ctxt);
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003009 addNode = xmlXPathNodeSetAdd;
Daniel Veillard740abf52000-10-02 23:04:54 +00003010
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003011#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003012 xmlGenericError(xmlGenericErrorContext,
3013 "new step : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003014#endif
3015 switch (axis) {
3016 case AXIS_ANCESTOR:
3017#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003018 xmlGenericError(xmlGenericErrorContext,
3019 "axis 'ancestors' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003020#endif
3021 next = xmlXPathNextAncestor; break;
3022 case AXIS_ANCESTOR_OR_SELF:
3023#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003024 xmlGenericError(xmlGenericErrorContext,
3025 "axis 'ancestors-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003026#endif
3027 next = xmlXPathNextAncestorOrSelf; break;
3028 case AXIS_ATTRIBUTE:
3029#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003030 xmlGenericError(xmlGenericErrorContext,
3031 "axis 'attributes' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003032#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003033 next = xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003034 break;
3035 case AXIS_CHILD:
3036#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003037 xmlGenericError(xmlGenericErrorContext,
3038 "axis 'child' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003039#endif
3040 next = xmlXPathNextChild; break;
3041 case AXIS_DESCENDANT:
3042#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003043 xmlGenericError(xmlGenericErrorContext,
3044 "axis 'descendant' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003045#endif
3046 next = xmlXPathNextDescendant; break;
3047 case AXIS_DESCENDANT_OR_SELF:
3048#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003049 xmlGenericError(xmlGenericErrorContext,
3050 "axis 'descendant-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003051#endif
3052 next = xmlXPathNextDescendantOrSelf; break;
3053 case AXIS_FOLLOWING:
3054#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003055 xmlGenericError(xmlGenericErrorContext,
3056 "axis 'following' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003057#endif
3058 next = xmlXPathNextFollowing; break;
3059 case AXIS_FOLLOWING_SIBLING:
3060#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003061 xmlGenericError(xmlGenericErrorContext,
3062 "axis 'following-siblings' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003063#endif
3064 next = xmlXPathNextFollowingSibling; break;
3065 case AXIS_NAMESPACE:
3066#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003067 xmlGenericError(xmlGenericErrorContext,
3068 "axis 'namespace' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003069#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003070 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003071 break;
3072 case AXIS_PARENT:
3073#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003074 xmlGenericError(xmlGenericErrorContext,
3075 "axis 'parent' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003076#endif
3077 next = xmlXPathNextParent; break;
3078 case AXIS_PRECEDING:
3079#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003080 xmlGenericError(xmlGenericErrorContext,
3081 "axis 'preceding' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003082#endif
3083 next = xmlXPathNextPreceding; break;
3084 case AXIS_PRECEDING_SIBLING:
3085#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003086 xmlGenericError(xmlGenericErrorContext,
3087 "axis 'preceding-sibling' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003088#endif
3089 next = xmlXPathNextPrecedingSibling; break;
3090 case AXIS_SELF:
3091#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003092 xmlGenericError(xmlGenericErrorContext,
3093 "axis 'self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003094#endif
3095 next = xmlXPathNextSelf; break;
3096 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003097 if (next == NULL)
3098 return;
3099
3100 nodelist = obj->nodesetval;
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003101 if ((nodelist != NULL) &&
3102 (nodelist->nodeNr <= 1))
3103 addNode = xmlXPathNodeSetAddUnique;
3104 else
3105 addNode = xmlXPathNodeSetAdd;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003106 ret = xmlXPathNodeSetCreate(NULL);
3107#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003108 xmlGenericError(xmlGenericErrorContext,
3109 " context contains %d nodes\n",
Daniel Veillard740abf52000-10-02 23:04:54 +00003110 nodelist->nodeNr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003111 switch (test) {
Daniel Veillard2f913b72001-01-31 13:23:49 +00003112 case NODE_TEST_NODE:
3113 xmlGenericError(xmlGenericErrorContext,
3114 " searching all nodes\n");
3115 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003116 case NODE_TEST_NONE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003117 xmlGenericError(xmlGenericErrorContext,
3118 " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003119 break;
3120 case NODE_TEST_TYPE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003121 xmlGenericError(xmlGenericErrorContext,
3122 " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003123 break;
3124 case NODE_TEST_PI:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003125 xmlGenericError(xmlGenericErrorContext,
3126 " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003127 break;
3128 case NODE_TEST_ALL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003129 xmlGenericError(xmlGenericErrorContext,
3130 " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003131 break;
3132 case NODE_TEST_NS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003133 xmlGenericError(xmlGenericErrorContext,
3134 " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003135 prefix);
3136 break;
3137 case NODE_TEST_NAME:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003138 xmlGenericError(xmlGenericErrorContext,
3139 " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003140 if (prefix != NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003141 xmlGenericError(xmlGenericErrorContext,
3142 " with namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003143 prefix);
3144 break;
3145 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003146 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003147#endif
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00003148 /*
3149 * 2.3 Node Tests
3150 * - For the attribute axis, the principal node type is attribute.
3151 * - For the namespace axis, the principal node type is namespace.
3152 * - For other axes, the principal node type is element.
3153 *
3154 * A node test * is true for any node of the
3155 * principal node type. For example, child::* willi
3156 * select all element children of the context node
3157 */
Daniel Veillard740abf52000-10-02 23:04:54 +00003158 for (i = 0;i < nodelist->nodeNr; i++) {
3159 ctxt->context->node = nodelist->nodeTab[i];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003160
3161 cur = NULL;
3162 do {
3163 cur = next(ctxt, cur);
3164 if (cur == NULL) break;
3165#ifdef DEBUG_STEP
3166 t++;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003167 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003168#endif
3169 switch (test) {
3170 case NODE_TEST_NONE:
3171 STRANGE
Daniel Veillard740abf52000-10-02 23:04:54 +00003172 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003173 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003174 if ((cur->type == type) ||
Daniel Veillard2f913b72001-01-31 13:23:49 +00003175 ((type == NODE_TYPE_NODE) &&
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003176 ((cur->type == XML_DOCUMENT_NODE) ||
Daniel Veillard2f913b72001-01-31 13:23:49 +00003177 (cur->type == XML_HTML_DOCUMENT_NODE) ||
3178 (cur->type == XML_ELEMENT_NODE) ||
3179 (cur->type == XML_PI_NODE) ||
3180 (cur->type == XML_COMMENT_NODE) ||
3181 (cur->type == XML_CDATA_SECTION_NODE) ||
3182 (cur->type == XML_TEXT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003183#ifdef DEBUG_STEP
3184 n++;
3185#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003186 addNode(ret, cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003187 }
3188 break;
3189 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003190 if (cur->type == XML_PI_NODE) {
3191 if ((name != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003192 (!xmlStrEqual(name, cur->name)))
Daniel Veillardb96e6431999-08-29 21:02:19 +00003193 break;
3194#ifdef DEBUG_STEP
3195 n++;
3196#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003197 addNode(ret, cur);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003198 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003199 break;
3200 case NODE_TEST_ALL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003201 if (axis == AXIS_ATTRIBUTE) {
3202 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003203#ifdef DEBUG_STEP
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003204 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003205#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003206 addNode(ret, cur);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003207 }
3208 } else if (axis == AXIS_NAMESPACE) {
3209 if (cur->type == XML_NAMESPACE_DECL) {
3210#ifdef DEBUG_STEP
3211 n++;
3212#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003213 addNode(ret, cur);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003214 }
3215 } else {
3216 if ((cur->type == XML_ELEMENT_NODE) ||
3217 (cur->type == XML_DOCUMENT_NODE) ||
3218 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003219 if (prefix == NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003220#ifdef DEBUG_STEP
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003221 n++;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003222#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003223 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003224 } else if ((cur->ns != NULL) &&
3225 (xmlStrEqual(prefix,
3226 cur->ns->href))) {
3227#ifdef DEBUG_STEP
3228 n++;
3229#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003230 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003231 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003232 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003233 }
3234 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003235 case NODE_TEST_NS: {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003236 TODO;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003237 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003238 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003239 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003240 switch (cur->type) {
3241 case XML_ELEMENT_NODE:
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003242 if (xmlStrEqual(name, cur->name)) {
3243 if (prefix == NULL) {
3244 if ((cur->ns == NULL) ||
3245 (cur->ns->prefix == NULL)) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003246#ifdef DEBUG_STEP
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003247 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003248#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003249 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003250 }
3251 } else {
3252 if ((cur->ns != NULL) &&
3253 (xmlStrEqual(prefix,
3254 cur->ns->href))) {
3255#ifdef DEBUG_STEP
3256 n++;
3257#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003258 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003259 }
3260 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003261 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003262 break;
3263 case XML_ATTRIBUTE_NODE: {
3264 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003265 if (xmlStrEqual(name, attr->name)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003266#ifdef DEBUG_STEP
Daniel Veillard740abf52000-10-02 23:04:54 +00003267 n++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003268#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003269 addNode(ret, cur);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003270 }
3271 break;
3272 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003273 case XML_NAMESPACE_DECL: {
3274 TODO;
3275 break;
3276 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003277 default:
3278 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003279 }
3280 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003281 }
3282 } while (cur != NULL);
3283 }
3284#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003285 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003286 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
3287#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00003288 xmlXPathFreeObject(obj);
3289 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003290}
3291
3292
3293/************************************************************************
3294 * *
3295 * Implicit tree core function library *
3296 * *
3297 ************************************************************************/
3298
3299/**
3300 * xmlXPathRoot:
3301 * @ctxt: the XPath Parser context
3302 *
3303 * Initialize the context to the root of the document
3304 */
3305void
3306xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003307 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Daniel Veillard740abf52000-10-02 23:04:54 +00003308 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003309}
3310
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003311/************************************************************************
3312 * *
3313 * The explicit core function library *
3314 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3315 * *
3316 ************************************************************************/
3317
3318
3319/**
3320 * xmlXPathLastFunction:
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 last() XPath function
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003325 * number last()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003326 * The last function returns the number of nodes in the context node list.
3327 */
3328void
3329xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3330 CHECK_ARITY(0);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003331 if (ctxt->context->contextSize > 0) {
3332 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3333#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003334 xmlGenericError(xmlGenericErrorContext,
3335 "last() : %d\n", ctxt->context->contextSize);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003336#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003337 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003338 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003339 }
3340}
3341
3342/**
3343 * xmlXPathPositionFunction:
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 position() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003348 * number position()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003349 * The position function returns the position of the context node in the
3350 * context node list. The first position is 1, and so the last positionr
3351 * will be equal to last().
3352 */
3353void
3354xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003355 CHECK_ARITY(0);
Daniel Veillardff9c3302000-10-13 16:38:25 +00003356 if (ctxt->context->proximityPosition >= 0) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003357 valuePush(ctxt,
Daniel Veillardff9c3302000-10-13 16:38:25 +00003358 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003359#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003360 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003361 ctxt->context->proximityPosition);
3362#endif
3363 } else {
3364 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003365 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003366}
3367
3368/**
3369 * xmlXPathCountFunction:
3370 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003371 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003372 *
3373 * Implement the count() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003374 * number count(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003375 */
3376void
3377xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3378 xmlXPathObjectPtr cur;
3379
3380 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003381 if ((ctxt->value == NULL) ||
3382 ((ctxt->value->type != XPATH_NODESET) &&
3383 (ctxt->value->type != XPATH_XSLT_TREE)))
3384 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003385 cur = valuePop(ctxt);
3386
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003387 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003388 xmlXPathFreeObject(cur);
3389}
3390
3391/**
3392 * xmlXPathIdFunction:
3393 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003394 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003395 *
3396 * Implement the id() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003397 * node-set id(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003398 * The id function selects elements by their unique ID
3399 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3400 * then the result is the union of the result of applying id to the
3401 * string value of each of the nodes in the argument node-set. When the
3402 * argument to id is of any other type, the argument is converted to a
3403 * string as if by a call to the string function; the string is split
3404 * into a whitespace-separated list of tokens (whitespace is any sequence
3405 * of characters matching the production S); the result is a node-set
3406 * containing the elements in the same document as the context node that
3407 * have a unique ID equal to any of the tokens in the list.
3408 */
3409void
3410xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003411 const xmlChar *tokens;
3412 const xmlChar *cur;
3413 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003414 xmlAttrPtr attr;
3415 xmlNodePtr elem = NULL;
3416 xmlXPathObjectPtr ret, obj;
3417
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003418 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003419 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003420 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003421 if (obj->type == XPATH_NODESET) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003422 xmlXPathObjectPtr newobj;
3423 int i;
3424
3425 ret = xmlXPathNewNodeSet(NULL);
3426
3427 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3428 valuePush(ctxt,
3429 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3430 xmlXPathStringFunction(ctxt, 1);
3431 xmlXPathIdFunction(ctxt, 1);
3432 newobj = valuePop(ctxt);
3433 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3434 newobj->nodesetval);
3435 xmlXPathFreeObject(newobj);
3436 }
3437
3438 xmlXPathFreeObject(obj);
3439 valuePush(ctxt, ret);
3440 return;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003441 }
3442 if (obj->type != XPATH_STRING) {
3443 valuePush(ctxt, obj);
3444 xmlXPathStringFunction(ctxt, 1);
3445 obj = valuePop(ctxt);
3446 if (obj->type != XPATH_STRING) {
3447 xmlXPathFreeObject(obj);
3448 return;
3449 }
3450 }
3451 tokens = obj->stringval;
3452
3453 ret = xmlXPathNewNodeSet(NULL);
3454 valuePush(ctxt, ret);
3455 if (tokens == NULL) {
3456 xmlXPathFreeObject(obj);
3457 return;
3458 }
3459
3460 cur = tokens;
3461
3462 while (IS_BLANK(*cur)) cur++;
3463 while (*cur != 0) {
3464 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3465 (*cur == '.') || (*cur == '-') ||
3466 (*cur == '_') || (*cur == ':') ||
3467 (IS_COMBINING(*cur)) ||
3468 (IS_EXTENDER(*cur)))
3469 cur++;
3470
3471 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3472
3473 ID = xmlStrndup(tokens, cur - tokens);
3474 attr = xmlGetID(ctxt->context->doc, ID);
3475 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003476 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003477 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3478 }
3479 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003480 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003481
3482 while (IS_BLANK(*cur)) cur++;
3483 tokens = cur;
3484 }
3485 xmlXPathFreeObject(obj);
3486 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003487}
3488
3489/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003490 * xmlXPathLocalNameFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003491 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003492 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003493 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003494 * Implement the local-name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003495 * string local-name(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003496 * The local-name function returns a string containing the local part
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003497 * of the name of the node in the argument node-set that is first in
3498 * document order. If the node-set is empty or the first node has no
3499 * name, an empty string is returned. If the argument is omitted it
3500 * defaults to the context node.
3501 */
3502void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003503xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003504 xmlXPathObjectPtr cur;
3505
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003506 if (nargs == 0) {
3507 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3508 nargs = 1;
3509 }
3510
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003511 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003512 if ((ctxt->value == NULL) ||
3513 ((ctxt->value->type != XPATH_NODESET) &&
3514 (ctxt->value->type != XPATH_XSLT_TREE)))
3515 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003516 cur = valuePop(ctxt);
3517
3518 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003519 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003520 } else {
3521 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003522 switch (cur->nodesetval->nodeTab[i]->type) {
3523 case XML_ELEMENT_NODE:
3524 case XML_ATTRIBUTE_NODE:
3525 case XML_PI_NODE:
3526 valuePush(ctxt,
3527 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
3528 break;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003529 case XML_NAMESPACE_DECL:
3530 valuePush(ctxt, xmlXPathNewString(
3531 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
3532 break;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003533 default:
3534 valuePush(ctxt, xmlXPathNewCString(""));
3535 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003536 }
3537 xmlXPathFreeObject(cur);
3538}
3539
3540/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003541 * xmlXPathNamespaceURIFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003542 * @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 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003545 * Implement the namespace-uri() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003546 * string namespace-uri(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003547 * The namespace-uri function returns a string containing the
3548 * namespace URI of the expanded name of the node in the argument
3549 * node-set that is first in document order. If the node-set is empty,
3550 * the first node has no name, or the expanded name has no namespace
3551 * URI, an empty string is returned. If the argument is omitted it
3552 * defaults to the context node.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003553 */
3554void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003555xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003556 xmlXPathObjectPtr cur;
3557
Daniel Veillardb96e6431999-08-29 21:02:19 +00003558 if (nargs == 0) {
3559 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3560 nargs = 1;
3561 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003562 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003563 if ((ctxt->value == NULL) ||
3564 ((ctxt->value->type != XPATH_NODESET) &&
3565 (ctxt->value->type != XPATH_XSLT_TREE)))
3566 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003567 cur = valuePop(ctxt);
3568
3569 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003570 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003571 } else {
3572 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003573 switch (cur->nodesetval->nodeTab[i]->type) {
3574 case XML_ELEMENT_NODE:
3575 case XML_ATTRIBUTE_NODE:
3576 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3577 valuePush(ctxt, xmlXPathNewCString(""));
3578 else
3579 valuePush(ctxt, xmlXPathNewString(
3580 cur->nodesetval->nodeTab[i]->ns->href));
3581 break;
3582 default:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003583 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003584 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003585 }
3586 xmlXPathFreeObject(cur);
3587}
3588
3589/**
3590 * xmlXPathNameFunction:
3591 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003592 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003593 *
3594 * Implement the name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003595 * string name(node-set?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003596 * The name function returns a string containing a QName representing
3597 * the name of the node in the argument node-set that is first in documenti
3598 * order. The QName must represent the name with respect to the namespace
3599 * declarations in effect on the node whose name is being represented.
3600 * Typically, this will be the form in which the name occurred in the XML
3601 * source. This need not be the case if there are namespace declarations
3602 * in effect on the node that associate multiple prefixes with the same
3603 * namespace. However, an implementation may include information about
3604 * the original prefix in its representation of nodes; in this case, an
3605 * implementation can ensure that the returned string is always the same
3606 * as the QName used in the XML source. If the argument it omitted it
3607 * defaults to the context node.
3608 * Libxml keep the original prefix so the "real qualified name" used is
3609 * returned.
3610 */
3611void
3612xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3613 xmlXPathObjectPtr cur;
3614
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003615 if (nargs == 0) {
3616 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3617 nargs = 1;
3618 }
3619
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003620 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003621 if ((ctxt->value == NULL) ||
3622 ((ctxt->value->type != XPATH_NODESET) &&
3623 (ctxt->value->type != XPATH_XSLT_TREE)))
3624 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003625 cur = valuePop(ctxt);
3626
3627 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003628 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003629 } else {
3630 int i = 0; /* Should be first in document order !!!!! */
3631
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003632 switch (cur->nodesetval->nodeTab[i]->type) {
3633 case XML_ELEMENT_NODE:
3634 case XML_ATTRIBUTE_NODE:
3635 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3636 valuePush(ctxt, xmlXPathNewString(
3637 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003638
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003639 else {
3640 char name[2000];
Daniel Veillard39c7d712000-09-10 16:14:55 +00003641#ifdef HAVE_SNPRINTF
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003642 snprintf(name, sizeof(name), "%s:%s",
3643 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3644 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003645#else
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003646 sprintf(name, "%s:%s",
3647 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3648 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003649#endif
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003650 name[sizeof(name) - 1] = 0;
3651 valuePush(ctxt, xmlXPathNewCString(name));
3652 }
3653 break;
3654 default:
3655 valuePush(ctxt,
3656 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3657 xmlXPathLocalNameFunction(ctxt, 1);
3658 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003659 }
3660 xmlXPathFreeObject(cur);
3661}
3662
3663/**
3664 * xmlXPathStringFunction:
3665 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003666 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003667 *
3668 * Implement the string() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003669 * string string(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003670 * he string function converts an object to a string as follows:
3671 * - A node-set is converted to a string by returning the value of
3672 * the node in the node-set that is first in document order.
3673 * If the node-set is empty, an empty string is returned.
3674 * - A number is converted to a string as follows
3675 * + NaN is converted to the string NaN
3676 * + positive zero is converted to the string 0
3677 * + negative zero is converted to the string 0
3678 * + positive infinity is converted to the string Infinity
3679 * + negative infinity is converted to the string -Infinity
3680 * + if the number is an integer, the number is represented in
3681 * decimal form as a Number with no decimal point and no leading
3682 * zeros, preceded by a minus sign (-) if the number is negative
3683 * + otherwise, the number is represented in decimal form as a
3684 * Number including a decimal point with at least one digit
3685 * before the decimal point and at least one digit after the
3686 * decimal point, preceded by a minus sign (-) if the number
3687 * is negative; there must be no leading zeros before the decimal
3688 * point apart possibly from the one required digit immediatelyi
3689 * before the decimal point; beyond the one required digit
3690 * after the decimal point there must be as many, but only as
3691 * many, more digits as are needed to uniquely distinguish the
3692 * number from all other IEEE 754 numeric values.
3693 * - The boolean false value is converted to the string false.
3694 * The boolean true value is converted to the string true.
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003695 *
3696 * If the argument is omitted, it defaults to a node-set with the
3697 * context node as its only member.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003698 */
3699void
3700xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3701 xmlXPathObjectPtr cur;
3702
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003703 if (nargs == 0) {
3704 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3705 nargs = 1;
3706 }
3707
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003708 CHECK_ARITY(1);
3709 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003710 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003711 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003712 case XPATH_UNDEFINED:
3713#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003714 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00003715#endif
3716 valuePush(ctxt, xmlXPathNewCString(""));
3717 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00003718 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003719 case XPATH_NODESET:
3720 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003721 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003722 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003723 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003724 int i = 0; /* Should be first in document order !!!!! */
3725 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
3726 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard5a2b6972001-01-20 21:15:50 +00003727 if (res != NULL)
3728 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003729 }
3730 xmlXPathFreeObject(cur);
3731 return;
3732 case XPATH_STRING:
3733 valuePush(ctxt, cur);
3734 return;
3735 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003736 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
3737 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003738 xmlXPathFreeObject(cur);
3739 return;
3740 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003741 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003742
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003743 if (isnan(cur->floatval))
3744 sprintf(buf, "NaN");
3745 else if (isinf(cur->floatval) > 0)
3746 sprintf(buf, "+Infinity");
3747 else if (isinf(cur->floatval) < 0)
3748 sprintf(buf, "-Infinity");
3749 else
3750 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003751 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003752 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003753 return;
3754 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003755 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003756 case XPATH_POINT:
3757 case XPATH_RANGE:
3758 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003759 TODO
3760 valuePush(ctxt, xmlXPathNewCString(""));
3761 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003762 }
3763 STRANGE
3764}
3765
3766/**
3767 * xmlXPathStringLengthFunction:
3768 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003769 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003770 *
3771 * Implement the string-length() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003772 * number string-length(string?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003773 * The string-length returns the number of characters in the string
3774 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3775 * the context node converted to a string, in other words the value
3776 * of the context node.
3777 */
3778void
3779xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3780 xmlXPathObjectPtr cur;
3781
3782 if (nargs == 0) {
3783 if (ctxt->context->node == NULL) {
3784 valuePush(ctxt, xmlXPathNewFloat(0));
3785 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003786 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003787
3788 content = xmlNodeGetContent(ctxt->context->node);
3789 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003790 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003791 }
3792 return;
3793 }
3794 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003795 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003796 CHECK_TYPE(XPATH_STRING);
3797 cur = valuePop(ctxt);
3798 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3799 xmlXPathFreeObject(cur);
3800}
3801
3802/**
3803 * xmlXPathConcatFunction:
3804 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003805 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003806 *
3807 * Implement the concat() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003808 * string concat(string, string, string*)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003809 * The concat function returns the concatenation of its arguments.
3810 */
3811void
3812xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003813 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003814 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003815
3816 if (nargs < 2) {
3817 CHECK_ARITY(2);
3818 }
3819
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003820 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003821 cur = valuePop(ctxt);
3822 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3823 xmlXPathFreeObject(cur);
3824 return;
3825 }
3826 nargs--;
3827
3828 while (nargs > 0) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003829 CAST_TO_STRING;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003830 newobj = valuePop(ctxt);
3831 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3832 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003833 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003834 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003835 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003836 tmp = xmlStrcat(newobj->stringval, cur->stringval);
3837 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003838 cur->stringval = tmp;
3839
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003840 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003841 nargs--;
3842 }
3843 valuePush(ctxt, cur);
3844}
3845
3846/**
3847 * xmlXPathContainsFunction:
3848 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003849 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003850 *
3851 * Implement the contains() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003852 * boolean contains(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003853 * The contains function returns true if the first argument string
3854 * contains the second argument string, and otherwise returns false.
3855 */
3856void
3857xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3858 xmlXPathObjectPtr hay, needle;
3859
3860 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003861 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003862 CHECK_TYPE(XPATH_STRING);
3863 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003864 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003865 hay = valuePop(ctxt);
3866 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3867 xmlXPathFreeObject(hay);
3868 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003869 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003870 }
3871 if (xmlStrstr(hay->stringval, needle->stringval))
3872 valuePush(ctxt, xmlXPathNewBoolean(1));
3873 else
3874 valuePush(ctxt, xmlXPathNewBoolean(0));
3875 xmlXPathFreeObject(hay);
3876 xmlXPathFreeObject(needle);
3877}
3878
3879/**
3880 * xmlXPathStartsWithFunction:
3881 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003882 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003883 *
3884 * Implement the starts-with() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003885 * boolean starts-with(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003886 * The starts-with function returns true if the first argument string
3887 * starts with the second argument string, and otherwise returns false.
3888 */
3889void
3890xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3891 xmlXPathObjectPtr hay, needle;
3892 int n;
3893
3894 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003895 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003896 CHECK_TYPE(XPATH_STRING);
3897 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003898 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003899 hay = valuePop(ctxt);
3900 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3901 xmlXPathFreeObject(hay);
3902 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003903 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003904 }
3905 n = xmlStrlen(needle->stringval);
3906 if (xmlStrncmp(hay->stringval, needle->stringval, n))
3907 valuePush(ctxt, xmlXPathNewBoolean(0));
3908 else
3909 valuePush(ctxt, xmlXPathNewBoolean(1));
3910 xmlXPathFreeObject(hay);
3911 xmlXPathFreeObject(needle);
3912}
3913
3914/**
3915 * xmlXPathSubstringFunction:
3916 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003917 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003918 *
3919 * Implement the substring() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003920 * string substring(string, number, number?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003921 * The substring function returns the substring of the first argument
3922 * starting at the position specified in the second argument with
3923 * length specified in the third argument. For example,
3924 * substring("12345",2,3) returns "234". If the third argument is not
3925 * specified, it returns the substring starting at the position specified
3926 * in the second argument and continuing to the end of the string. For
3927 * example, substring("12345",2) returns "2345". More precisely, each
3928 * character in the string (see [3.6 Strings]) is considered to have a
3929 * numeric position: the position of the first character is 1, the position
3930 * of the second character is 2 and so on. The returned substring contains
3931 * those characters for which the position of the character is greater than
3932 * or equal to the second argument and, if the third argument is specified,
3933 * less than the sum of the second and third arguments; the comparisons
3934 * and addition used for the above follow the standard IEEE 754 rules. Thus:
3935 * - substring("12345", 1.5, 2.6) returns "234"
3936 * - substring("12345", 0, 3) returns "12"
3937 * - substring("12345", 0 div 0, 3) returns ""
3938 * - substring("12345", 1, 0 div 0) returns ""
3939 * - substring("12345", -42, 1 div 0) returns "12345"
3940 * - substring("12345", -1 div 0, 1 div 0) returns ""
3941 */
3942void
3943xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3944 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003945 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003946 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003947 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003948
3949 /*
3950 * Conformance needs to be checked !!!!!
3951 */
3952 if (nargs < 2) {
3953 CHECK_ARITY(2);
3954 }
3955 if (nargs > 3) {
3956 CHECK_ARITY(3);
3957 }
3958 if (nargs == 3) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003959 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003960 CHECK_TYPE(XPATH_NUMBER);
3961 len = valuePop(ctxt);
3962 le = len->floatval;
3963 xmlXPathFreeObject(len);
3964 } else {
3965 le = 2000000000;
3966 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003967 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003968 CHECK_TYPE(XPATH_NUMBER);
3969 start = valuePop(ctxt);
3970 in = start->floatval;
3971 xmlXPathFreeObject(start);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003972 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003973 CHECK_TYPE(XPATH_STRING);
3974 str = valuePop(ctxt);
3975 le += in;
3976
3977 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003978 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003979 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003980
3981 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003982 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003983 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003984
3985 /* back to a zero based len */
3986 i--;
3987 l--;
3988
3989 /* check against the string len */
3990 if (l > 1024) {
3991 l = xmlStrlen(str->stringval);
3992 }
3993 if (i < 0) {
3994 i = 0;
3995 }
3996
3997 /* number of chars to copy */
3998 l -= i;
3999
4000 ret = xmlStrsub(str->stringval, i, l);
4001 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004002 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004003 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004004 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004005 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004006 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004007 xmlXPathFreeObject(str);
4008}
4009
4010/**
4011 * xmlXPathSubstringBeforeFunction:
4012 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004013 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004014 *
4015 * Implement the substring-before() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004016 * string substring-before(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004017 * The substring-before function returns the substring of the first
4018 * argument string that precedes the first occurrence of the second
4019 * argument string in the first argument string, or the empty string
4020 * if the first argument string does not contain the second argument
4021 * string. For example, substring-before("1999/04/01","/") returns 1999.
4022 */
4023void
4024xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004025 xmlXPathObjectPtr str;
4026 xmlXPathObjectPtr find;
4027 xmlBufferPtr target;
4028 const xmlChar *point;
4029 int offset;
4030
4031 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004032 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004033 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004034 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004035 str = valuePop(ctxt);
4036
4037 target = xmlBufferCreate();
4038 if (target) {
4039 point = xmlStrstr(str->stringval, find->stringval);
4040 if (point) {
4041 offset = (int)(point - str->stringval);
4042 xmlBufferAdd(target, str->stringval, offset);
4043 }
4044 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4045 xmlBufferFree(target);
4046 }
4047
4048 xmlXPathFreeObject(str);
4049 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004050}
4051
4052/**
4053 * xmlXPathSubstringAfterFunction:
4054 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004055 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004056 *
4057 * Implement the substring-after() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004058 * string substring-after(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004059 * The substring-after function returns the substring of the first
4060 * argument string that follows the first occurrence of the second
4061 * argument string in the first argument string, or the empty stringi
4062 * if the first argument string does not contain the second argument
4063 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4064 * and substring-after("1999/04/01","19") returns 99/04/01.
4065 */
4066void
4067xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004068 xmlXPathObjectPtr str;
4069 xmlXPathObjectPtr find;
4070 xmlBufferPtr target;
4071 const xmlChar *point;
4072 int offset;
4073
4074 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004075 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004076 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004077 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004078 str = valuePop(ctxt);
4079
4080 target = xmlBufferCreate();
4081 if (target) {
4082 point = xmlStrstr(str->stringval, find->stringval);
4083 if (point) {
4084 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4085 xmlBufferAdd(target, &str->stringval[offset],
4086 xmlStrlen(str->stringval) - offset);
4087 }
4088 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4089 xmlBufferFree(target);
4090 }
4091
4092 xmlXPathFreeObject(str);
4093 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004094}
4095
4096/**
4097 * xmlXPathNormalizeFunction:
4098 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004099 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004100 *
Daniel Veillard767662d2000-10-27 17:04:52 +00004101 * Implement the normalize-space() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004102 * string normalize-space(string?)
Daniel Veillard767662d2000-10-27 17:04:52 +00004103 * The normalize-space function returns the argument string with white
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004104 * space normalized by stripping leading and trailing whitespace
4105 * and replacing sequences of whitespace characters by a single
4106 * space. Whitespace characters are the same allowed by the S production
4107 * in XML. If the argument is omitted, it defaults to the context
4108 * node converted to a string, in other words the value of the context node.
4109 */
4110void
4111xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004112 xmlXPathObjectPtr obj = NULL;
4113 xmlChar *source = NULL;
4114 xmlBufferPtr target;
4115 xmlChar blank;
4116
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004117 if (nargs == 0) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004118 /* Use current context node */
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004119 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4120 xmlXPathStringFunction(ctxt, 1);
4121 nargs = 1;
Daniel Veillard46057e12000-09-24 18:49:59 +00004122 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004123
4124 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004125 CAST_TO_STRING;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004126 CHECK_TYPE(XPATH_STRING);
4127 obj = valuePop(ctxt);
4128 source = obj->stringval;
4129
Daniel Veillard46057e12000-09-24 18:49:59 +00004130 target = xmlBufferCreate();
4131 if (target && source) {
4132
4133 /* Skip leading whitespaces */
4134 while (IS_BLANK(*source))
4135 source++;
4136
4137 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4138 blank = 0;
4139 while (*source) {
4140 if (IS_BLANK(*source)) {
4141 blank = *source;
4142 } else {
4143 if (blank) {
4144 xmlBufferAdd(target, &blank, 1);
4145 blank = 0;
4146 }
4147 xmlBufferAdd(target, source, 1);
4148 }
4149 source++;
4150 }
4151
4152 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4153 xmlBufferFree(target);
4154 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004155 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004156}
4157
4158/**
4159 * xmlXPathTranslateFunction:
4160 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004161 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004162 *
4163 * Implement the translate() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004164 * string translate(string, string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004165 * The translate function returns the first argument string with
4166 * occurrences of characters in the second argument string replaced
4167 * by the character at the corresponding position in the third argument
4168 * string. For example, translate("bar","abc","ABC") returns the string
4169 * BAr. If there is a character in the second argument string with no
4170 * character at a corresponding position in the third argument string
4171 * (because the second argument string is longer than the third argument
4172 * string), then occurrences of that character in the first argument
4173 * string are removed. For example, translate("--aaa--","abc-","ABC")
4174 * returns "AAA". If a character occurs more than once in second
4175 * argument string, then the first occurrence determines the replacement
4176 * character. If the third argument string is longer than the second
4177 * argument string, then excess characters are ignored.
4178 */
4179void
4180xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004181 xmlXPathObjectPtr str;
4182 xmlXPathObjectPtr from;
4183 xmlXPathObjectPtr to;
4184 xmlBufferPtr target;
4185 int i, offset, max;
4186 xmlChar ch;
4187 const xmlChar *point;
4188
4189 CHECK_ARITY(3);
4190
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004191 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004192 to = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004193 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004194 from = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004195 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004196 str = valuePop(ctxt);
4197
4198 target = xmlBufferCreate();
4199 if (target) {
4200 max = xmlStrlen(to->stringval);
4201 for (i = 0; (ch = str->stringval[i]); i++) {
4202 point = xmlStrchr(from->stringval, ch);
4203 if (point) {
4204 /* Warning: This may not work with UTF-8 */
4205 offset = (int)(point - from->stringval);
4206 if (offset < max)
4207 xmlBufferAdd(target, &to->stringval[offset], 1);
4208 } else
4209 xmlBufferAdd(target, &ch, 1);
4210 }
4211 }
4212 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4213 xmlBufferFree(target);
4214 xmlXPathFreeObject(str);
4215 xmlXPathFreeObject(from);
4216 xmlXPathFreeObject(to);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004217}
4218
4219/**
4220 * xmlXPathBooleanFunction:
4221 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004222 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004223 *
4224 * Implement the boolean() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004225 * boolean boolean(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004226 * he boolean function converts its argument to a boolean as follows:
4227 * - a number is true if and only if it is neither positive or
4228 * negative zero nor NaN
4229 * - a node-set is true if and only if it is non-empty
4230 * - a string is true if and only if its length is non-zero
4231 */
4232void
4233xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4234 xmlXPathObjectPtr cur;
4235 int res = 0;
4236
4237 CHECK_ARITY(1);
4238 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004239 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004240 switch (cur->type) {
4241 case XPATH_NODESET:
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00004242 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004243 if ((cur->nodesetval == NULL) ||
4244 (cur->nodesetval->nodeNr == 0)) res = 0;
4245 else
4246 res = 1;
4247 break;
4248 case XPATH_STRING:
4249 if ((cur->stringval == NULL) ||
4250 (cur->stringval[0] == 0)) res = 0;
4251 else
4252 res = 1;
4253 break;
4254 case XPATH_BOOLEAN:
4255 valuePush(ctxt, cur);
4256 return;
4257 case XPATH_NUMBER:
4258 if (cur->floatval) res = 1;
4259 break;
4260 default:
4261 STRANGE
4262 }
4263 xmlXPathFreeObject(cur);
4264 valuePush(ctxt, xmlXPathNewBoolean(res));
4265}
4266
4267/**
4268 * xmlXPathNotFunction:
4269 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004270 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004271 *
4272 * Implement the not() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004273 * boolean not(boolean)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004274 * The not function returns true if its argument is false,
4275 * and false otherwise.
4276 */
4277void
4278xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4279 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004280 CAST_TO_BOOLEAN;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004281 CHECK_TYPE(XPATH_BOOLEAN);
4282 ctxt->value->boolval = ! ctxt->value->boolval;
4283}
4284
4285/**
4286 * xmlXPathTrueFunction:
4287 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004288 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004289 *
4290 * Implement the true() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004291 * boolean true()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004292 */
4293void
4294xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4295 CHECK_ARITY(0);
4296 valuePush(ctxt, xmlXPathNewBoolean(1));
4297}
4298
4299/**
4300 * xmlXPathFalseFunction:
4301 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004302 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004303 *
4304 * Implement the false() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004305 * boolean false()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004306 */
4307void
4308xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4309 CHECK_ARITY(0);
4310 valuePush(ctxt, xmlXPathNewBoolean(0));
4311}
4312
4313/**
4314 * xmlXPathLangFunction:
4315 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004316 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004317 *
4318 * Implement the lang() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004319 * boolean lang(string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004320 * The lang function returns true or false depending on whether the
4321 * language of the context node as specified by xml:lang attributes
4322 * is the same as or is a sublanguage of the language specified by
4323 * the argument string. The language of the context node is determined
4324 * by the value of the xml:lang attribute on the context node, or, if
4325 * the context node has no xml:lang attribute, by the value of the
4326 * xml:lang attribute on the nearest ancestor of the context node that
4327 * has an xml:lang attribute. If there is no such attribute, then lang
4328 * returns false. If there is such an attribute, then lang returns
4329 * true if the attribute value is equal to the argument ignoring case,
4330 * or if there is some suffix starting with - such that the attribute
4331 * value is equal to the argument ignoring that suffix of the attribute
4332 * value and ignoring case.
4333 */
4334void
4335xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004336 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004337 const xmlChar *theLang;
4338 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004339 int ret = 0;
4340 int i;
4341
4342 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004343 CAST_TO_STRING;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004344 CHECK_TYPE(XPATH_STRING);
4345 val = valuePop(ctxt);
4346 lang = val->stringval;
4347 theLang = xmlNodeGetLang(ctxt->context->node);
4348 if ((theLang != NULL) && (lang != NULL)) {
4349 for (i = 0;lang[i] != 0;i++)
4350 if (toupper(lang[i]) != toupper(theLang[i]))
4351 goto not_equal;
4352 ret = 1;
4353 }
4354not_equal:
4355 xmlXPathFreeObject(val);
4356 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004357}
4358
4359/**
4360 * xmlXPathNumberFunction:
4361 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004362 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004363 *
4364 * Implement the number() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004365 * number number(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004366 */
4367void
4368xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4369 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004370 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004371
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004372 if (nargs == 0) {
4373 if (ctxt->context->node == NULL) {
4374 valuePush(ctxt, xmlXPathNewFloat(0.0));
4375 } else {
4376 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4377
4378 res = xmlXPathStringEvalNumber(content);
4379 valuePush(ctxt, xmlXPathNewFloat(res));
4380 xmlFree(content);
4381 }
4382 return;
4383 }
4384
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004385 CHECK_ARITY(1);
4386 cur = valuePop(ctxt);
4387 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00004388 case XPATH_UNDEFINED:
4389#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004390 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00004391#endif
4392 valuePush(ctxt, xmlXPathNewFloat(0.0));
4393 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00004394 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004395 case XPATH_NODESET:
4396 valuePush(ctxt, cur);
4397 xmlXPathStringFunction(ctxt, 1);
4398 cur = valuePop(ctxt);
4399 case XPATH_STRING:
4400 res = xmlXPathStringEvalNumber(cur->stringval);
4401 valuePush(ctxt, xmlXPathNewFloat(res));
4402 xmlXPathFreeObject(cur);
4403 return;
4404 case XPATH_BOOLEAN:
4405 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
4406 else valuePush(ctxt, xmlXPathNewFloat(0.0));
4407 xmlXPathFreeObject(cur);
4408 return;
4409 case XPATH_NUMBER:
4410 valuePush(ctxt, cur);
4411 return;
Daniel Veillard740abf52000-10-02 23:04:54 +00004412 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00004413 case XPATH_POINT:
4414 case XPATH_RANGE:
4415 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00004416 TODO
4417 valuePush(ctxt, xmlXPathNewFloat(0.0));
4418 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004419 }
4420 STRANGE
4421}
4422
4423/**
4424 * xmlXPathSumFunction:
4425 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004426 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004427 *
4428 * Implement the sum() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004429 * number sum(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004430 * The sum function returns the sum of the values of the nodes in
4431 * the argument node-set.
4432 */
4433void
4434xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004435 xmlXPathObjectPtr cur;
4436 int i;
4437
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004438 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00004439 if ((ctxt->value == NULL) ||
4440 ((ctxt->value->type != XPATH_NODESET) &&
4441 (ctxt->value->type != XPATH_XSLT_TREE)))
4442 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004443 cur = valuePop(ctxt);
4444
4445 if (cur->nodesetval->nodeNr == 0) {
4446 valuePush(ctxt, xmlXPathNewFloat(0.0));
4447 } else {
4448 valuePush(ctxt,
4449 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
Daniel Veillard767662d2000-10-27 17:04:52 +00004450 xmlXPathNumberFunction(ctxt, 1);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004451 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4452 valuePush(ctxt,
4453 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4454 xmlXPathAddValues(ctxt);
4455 }
4456 }
4457 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004458}
4459
4460/**
4461 * xmlXPathFloorFunction:
4462 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004463 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004464 *
4465 * Implement the floor() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004466 * number floor(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004467 * The floor function returns the largest (closest to positive infinity)
4468 * number that is not greater than the argument and that is an integer.
4469 */
4470void
4471xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4472 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004473 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004474 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004475#if 0
4476 ctxt->value->floatval = floor(ctxt->value->floatval);
4477#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004478 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004479 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004480#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004481}
4482
4483/**
4484 * xmlXPathCeilingFunction:
4485 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004486 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004487 *
4488 * Implement the ceiling() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004489 * number ceiling(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004490 * The ceiling function returns the smallest (closest to negative infinity)
4491 * number that is not less than the argument and that is an integer.
4492 */
4493void
4494xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004495 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004496
4497 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004498 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004499 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004500
4501#if 0
4502 ctxt->value->floatval = ceil(ctxt->value->floatval);
4503#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004504 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004505 if (f != ctxt->value->floatval)
4506 ctxt->value->floatval = f + 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004507#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004508}
4509
4510/**
4511 * xmlXPathRoundFunction:
4512 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004513 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004514 *
4515 * Implement the round() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004516 * number round(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004517 * The round function returns the number that is closest to the
4518 * argument and that is an integer. If there are two such numbers,
4519 * then the one that is even is returned.
4520 */
4521void
4522xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004523 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004524
4525 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004526 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004527 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004528
4529 if ((ctxt->value->floatval == xmlXPathNAN) ||
4530 (ctxt->value->floatval == xmlXPathPINF) ||
4531 (ctxt->value->floatval == xmlXPathNINF) ||
4532 (ctxt->value->floatval == 0.0))
4533 return;
4534
4535#if 0
4536 f = floor(ctxt->value->floatval);
4537#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004538 f = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004539#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004540 if (ctxt->value->floatval < f + 0.5)
4541 ctxt->value->floatval = f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004542 else
4543 ctxt->value->floatval = f + 1;
4544}
4545
4546/************************************************************************
4547 * *
4548 * The Parser *
4549 * *
4550 ************************************************************************/
4551
4552/*
4553 * a couple of forward declarations since we use a recursive call based
4554 * implementation.
4555 */
4556void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
4557void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
4558void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004559#ifdef VMS
4560void xmlXPathEvalRelLocationPath(xmlXPathParserContextPtr ctxt);
4561#define xmlXPathEvalRelativeLocationPath xmlXPathEvalRelLocationPath
4562#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004563void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004564#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004565
4566/**
4567 * xmlXPathParseNCName:
4568 * @ctxt: the XPath Parser context
4569 *
4570 * parse an XML namespace non qualified name.
4571 *
4572 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
4573 *
4574 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
4575 * CombiningChar | Extender
4576 *
4577 * Returns the namespace name or NULL
4578 */
4579
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004580xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004581xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004582 const xmlChar *q;
4583 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004584
4585 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4586 q = NEXT;
4587
4588 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4589 (CUR == '.') || (CUR == '-') ||
4590 (CUR == '_') ||
4591 (IS_COMBINING(CUR)) ||
4592 (IS_EXTENDER(CUR)))
4593 NEXT;
4594
4595 ret = xmlStrndup(q, CUR_PTR - q);
4596
4597 return(ret);
4598}
4599
4600/**
4601 * xmlXPathParseQName:
4602 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004603 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004604 *
4605 * parse an XML qualified name
4606 *
4607 * [NS 5] QName ::= (Prefix ':')? LocalPart
4608 *
4609 * [NS 6] Prefix ::= NCName
4610 *
4611 * [NS 7] LocalPart ::= NCName
4612 *
4613 * Returns the function returns the local part, and prefix is updated
4614 * to get the Prefix if any.
4615 */
4616
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004617xmlChar *
4618xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
4619 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004620
4621 *prefix = NULL;
4622 ret = xmlXPathParseNCName(ctxt);
4623 if (CUR == ':') {
4624 *prefix = ret;
4625 NEXT;
4626 ret = xmlXPathParseNCName(ctxt);
4627 }
4628 return(ret);
4629}
4630
4631/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00004632 * xmlXPathParseName:
Daniel Veillardf6eea272001-01-18 12:17:12 +00004633 * @ctxt: the XPath Parser context
Daniel Veillard2d38f042000-10-11 10:54:10 +00004634 *
4635 * parse an XML name
4636 *
4637 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4638 * CombiningChar | Extender
4639 *
4640 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4641 *
4642 * Returns the namespace name or NULL
4643 */
4644
4645xmlChar *
4646xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
4647 const xmlChar *q;
4648 xmlChar *ret = NULL;
4649
4650 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4651 q = NEXT;
4652
4653 /* TODO Make this UTF8 compliant !!! */
4654 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4655 (CUR == '.') || (CUR == '-') ||
4656 (CUR == '_') || (CUR == ':') ||
4657 (IS_COMBINING(CUR)) ||
4658 (IS_EXTENDER(CUR)))
4659 NEXT;
4660
4661 ret = xmlStrndup(q, CUR_PTR - q);
4662
4663 return(ret);
4664}
4665
4666/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004667 * xmlXPathStringEvalNumber:
4668 * @str: A string to scan
4669 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004670 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004671 * | '.' Digits
4672 * [31] Digits ::= [0-9]+
4673 *
4674 * Parse and evaluate a Number in the string
Daniel Veillard767662d2000-10-27 17:04:52 +00004675 * In complement of the Number expression, this function also handles
4676 * negative values : '-' Number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004677 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004678 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004679 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004680double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004681xmlXPathStringEvalNumber(const xmlChar *str) {
4682 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004683 double ret = 0.0;
4684 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004685 int ok = 0;
Daniel Veillard767662d2000-10-27 17:04:52 +00004686 int isneg = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004687
4688 while (*cur == ' ') cur++;
Daniel Veillard767662d2000-10-27 17:04:52 +00004689 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004690 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004691 }
Daniel Veillard767662d2000-10-27 17:04:52 +00004692 if (*cur == '-') {
4693 isneg = 1;
4694 cur++;
4695 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004696 while ((*cur >= '0') && (*cur <= '9')) {
4697 ret = ret * 10 + (*cur - '0');
4698 ok = 1;
4699 cur++;
4700 }
4701 if (*cur == '.') {
4702 cur++;
4703 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004704 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004705 }
4706 while ((*cur >= '0') && (*cur <= '9')) {
4707 mult /= 10;
4708 ret = ret + (*cur - '0') * mult;
4709 cur++;
4710 }
4711 }
4712 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004713 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard767662d2000-10-27 17:04:52 +00004714 if (isneg) ret = -ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004715 return(ret);
4716}
4717
4718/**
4719 * xmlXPathEvalNumber:
4720 * @ctxt: the XPath Parser context
4721 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004722 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004723 * | '.' Digits
4724 * [31] Digits ::= [0-9]+
4725 *
4726 * Parse and evaluate a Number, then push it on the stack
4727 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004728 */
4729void
4730xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004731 double ret = 0.0;
4732 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004733 int ok = 0;
4734
4735 CHECK_ERROR;
4736 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004737 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004738 }
4739 while ((CUR >= '0') && (CUR <= '9')) {
4740 ret = ret * 10 + (CUR - '0');
4741 ok = 1;
4742 NEXT;
4743 }
4744 if (CUR == '.') {
4745 NEXT;
4746 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004747 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004748 }
4749 while ((CUR >= '0') && (CUR <= '9')) {
4750 mult /= 10;
4751 ret = ret + (CUR - '0') * mult;
4752 NEXT;
4753 }
4754 }
4755 valuePush(ctxt, xmlXPathNewFloat(ret));
4756}
4757
4758/**
4759 * xmlXPathEvalLiteral:
4760 * @ctxt: the XPath Parser context
4761 *
4762 * Parse a Literal and push it on the stack.
4763 *
4764 * [29] Literal ::= '"' [^"]* '"'
4765 * | "'" [^']* "'"
4766 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004767 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004768 */
4769void
4770xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004771 const xmlChar *q;
4772 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004773
4774 if (CUR == '"') {
4775 NEXT;
4776 q = CUR_PTR;
4777 while ((IS_CHAR(CUR)) && (CUR != '"'))
4778 NEXT;
4779 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004780 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004781 } else {
4782 ret = xmlStrndup(q, CUR_PTR - q);
4783 NEXT;
4784 }
4785 } else if (CUR == '\'') {
4786 NEXT;
4787 q = CUR_PTR;
4788 while ((IS_CHAR(CUR)) && (CUR != '\''))
4789 NEXT;
4790 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004791 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004792 } else {
4793 ret = xmlStrndup(q, CUR_PTR - q);
4794 NEXT;
4795 }
4796 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004797 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004798 }
4799 if (ret == NULL) return;
4800 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004801 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004802}
4803
4804/**
4805 * xmlXPathEvalVariableReference:
4806 * @ctxt: the XPath Parser context
4807 *
4808 * Parse a VariableReference, evaluate it and push it on the stack.
4809 *
4810 * The variable bindings consist of a mapping from variable names
4811 * to variable values. The value of a variable is an object, which
4812 * of any of the types that are possible for the value of an expression,
4813 * and may also be of additional types not specified here.
4814 *
4815 * Early evaluation is possible since:
4816 * The variable bindings [...] used to evaluate a subexpression are
4817 * always the same as those used to evaluate the containing expression.
4818 *
4819 * [36] VariableReference ::= '$' QName
4820 */
4821void
4822xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004823 xmlChar *name;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004824 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004825 xmlXPathObjectPtr value;
4826
Daniel Veillard55b91f22000-10-05 16:30:11 +00004827 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004828 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004829 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004830 }
Daniel Veillard5a2b6972001-01-20 21:15:50 +00004831 NEXT;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004832 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004833 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004834 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004835 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004836 if (prefix == NULL) {
4837 value = xmlXPathVariableLookup(ctxt->context, name);
4838 } else {
4839 TODO;
4840 value = NULL;
4841 }
4842 xmlFree(name);
4843 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004844 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004845 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004846 }
4847 valuePush(ctxt, value);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004848 SKIP_BLANKS;
4849}
4850
4851/**
4852 * xmlXPathIsNodeType:
4853 * @ctxt: the XPath Parser context
4854 * @name: a name string
4855 *
4856 * Is the name given a NodeType one.
4857 *
4858 * [38] NodeType ::= 'comment'
4859 * | 'text'
4860 * | 'processing-instruction'
4861 * | 'node'
4862 *
4863 * Returns 1 if true 0 otherwise
4864 */
4865int
4866xmlXPathIsNodeType(const xmlChar *name) {
4867 if (name == NULL)
4868 return(0);
4869
4870 if (xmlStrEqual(name, BAD_CAST "comment"))
4871 return(1);
4872 if (xmlStrEqual(name, BAD_CAST "text"))
4873 return(1);
4874 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4875 return(1);
4876 if (xmlStrEqual(name, BAD_CAST "node"))
4877 return(1);
4878 return(0);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004879}
4880
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004881/**
4882 * xmlXPathEvalFunctionCall:
4883 * @ctxt: the XPath Parser context
4884 *
4885 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4886 * [17] Argument ::= Expr
4887 *
4888 * Parse and evaluate a function call, the evaluation of all arguments are
4889 * pushed on the stack
4890 */
4891void
4892xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004893 xmlChar *name;
4894 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004895 xmlXPathFunction func;
4896 int nbargs = 0;
4897
4898 name = xmlXPathParseQName(ctxt, &prefix);
4899 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004900 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004901 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004902 SKIP_BLANKS;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004903 if (prefix == NULL) {
4904 func = xmlXPathFunctionLookup(ctxt->context, name);
4905 } else {
4906 TODO;
4907 func = NULL;
4908 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004909 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004910 xmlFree(name);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004911 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004912 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004913 }
4914#ifdef DEBUG_EXPR
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004915 if (prefix == NULL)
4916 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
4917 name);
4918 else
4919 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
4920 prefix, name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004921#endif
4922
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004923 xmlFree(name);
4924 if (prefix != NULL) xmlFree(prefix);
4925
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004926 if (CUR != '(') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004927 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004928 }
4929 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004930 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004931
4932 while (CUR != ')') {
4933 xmlXPathEvalExpr(ctxt);
4934 nbargs++;
4935 if (CUR == ')') break;
4936 if (CUR != ',') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004937 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004938 }
4939 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004940 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004941 }
4942 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004943 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004944 func(ctxt, nbargs);
4945}
4946
4947/**
4948 * xmlXPathEvalPrimaryExpr:
4949 * @ctxt: the XPath Parser context
4950 *
4951 * [15] PrimaryExpr ::= VariableReference
4952 * | '(' Expr ')'
4953 * | Literal
4954 * | Number
4955 * | FunctionCall
4956 *
4957 * Parse and evaluate a primary expression, then push the result on the stack
4958 */
4959void
4960xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00004961 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004962 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4963 else if (CUR == '(') {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004964 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004965 SKIP_BLANKS;
Daniel Veillard55b91f22000-10-05 16:30:11 +00004966 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004967 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004968 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004969 }
4970 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004971 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004972 } else if (IS_DIGIT(CUR)) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004973 xmlXPathEvalNumber(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004974 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004975 xmlXPathEvalLiteral(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004976 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00004977 xmlXPathEvalFunctionCall(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004978 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00004979 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004980}
4981
4982/**
4983 * xmlXPathEvalFilterExpr:
4984 * @ctxt: the XPath Parser context
4985 *
4986 * [20] FilterExpr ::= PrimaryExpr
4987 * | FilterExpr Predicate
4988 *
4989 * Parse and evaluate a filter expression, then push the result on the stack
4990 * Square brackets are used to filter expressions in the same way that
4991 * they are used in location paths. It is an error if the expression to
4992 * be filtered does not evaluate to a node-set. The context node list
4993 * used for evaluating the expression in square brackets is the node-set
4994 * to be filtered listed in document order.
4995 */
4996
4997void
4998xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004999 xmlXPathEvalPrimaryExpr(ctxt);
5000 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005001 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005002
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005003 while (CUR == '[') {
Daniel Veillardf62ceff2000-11-24 23:36:01 +00005004 if ((ctxt->value == NULL) ||
5005 ((ctxt->value->type != XPATH_NODESET) &&
5006 (ctxt->value->type != XPATH_LOCATIONSET)))
5007 XP_ERROR(XPATH_INVALID_TYPE)
5008
5009 if (ctxt->value->type == XPATH_NODESET)
5010 xmlXPathEvalPredicate(ctxt);
5011 else
5012 xmlXPtrEvalRangePredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005013 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005014 }
5015
5016
5017}
5018
5019/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00005020 * xmlXPathScanName:
5021 * @ctxt: the XPath Parser context
5022 *
5023 * Trickery: parse an XML name but without consuming the input flow
Daniel Veillard55b91f22000-10-05 16:30:11 +00005024 * Needed to avoid insanity in the parser state.
Daniel Veillardb96e6431999-08-29 21:02:19 +00005025 *
5026 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5027 * CombiningChar | Extender
5028 *
5029 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5030 *
5031 * [6] Names ::= Name (S Name)*
5032 *
5033 * Returns the Name parsed or NULL
5034 */
5035
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005036xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00005037xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005038 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00005039 int len = 0;
5040
Daniel Veillard00fdf371999-10-08 09:40:39 +00005041 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005042 if (!IS_LETTER(CUR) && (CUR != '_') &&
5043 (CUR != ':')) {
5044 return(NULL);
5045 }
5046
5047 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5048 (NXT(len) == '.') || (NXT(len) == '-') ||
5049 (NXT(len) == '_') || (NXT(len) == ':') ||
5050 (IS_COMBINING(NXT(len))) ||
5051 (IS_EXTENDER(NXT(len)))) {
5052 buf[len] = NXT(len);
5053 len++;
5054 if (len >= XML_MAX_NAMELEN) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005055 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardb96e6431999-08-29 21:02:19 +00005056 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5057 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5058 (NXT(len) == '.') || (NXT(len) == '-') ||
5059 (NXT(len) == '_') || (NXT(len) == ':') ||
5060 (IS_COMBINING(NXT(len))) ||
5061 (IS_EXTENDER(NXT(len))))
5062 len++;
5063 break;
5064 }
5065 }
5066 return(xmlStrndup(buf, len));
5067}
5068
5069/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005070 * xmlXPathEvalPathExpr:
5071 * @ctxt: the XPath Parser context
5072 *
5073 * [19] PathExpr ::= LocationPath
5074 * | FilterExpr
5075 * | FilterExpr '/' RelativeLocationPath
5076 * | FilterExpr '//' RelativeLocationPath
5077 *
5078 * Parse and evaluate a path expression, then push the result on the stack
5079 * The / operator and // operators combine an arbitrary expression
5080 * and a relative location path. It is an error if the expression
5081 * does not evaluate to a node-set.
5082 * The / operator does composition in the same way as when / is
5083 * used in a location path. As in location paths, // is short for
5084 * /descendant-or-self::node()/.
5085 */
5086
5087void
5088xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005089 int lc = 1; /* Should we branch to LocationPath ? */
5090 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5091
Daniel Veillard00fdf371999-10-08 09:40:39 +00005092 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005093 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5094 (CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005095 lc = 0;
5096 } else if (CUR == '/') {
5097 /* relative or absolute location path */
5098 lc = 1;
5099 } else if (CUR == '@') {
5100 /* relative abbreviated attribute location path */
5101 lc = 1;
5102 } else if (CUR == '.') {
5103 /* relative abbreviated attribute location path */
5104 lc = 1;
5105 } else {
5106 /*
5107 * Problem is finding if we have a name here whether it's:
5108 * - a nodetype
5109 * - a function call in which case it's followed by '('
5110 * - an axis in which case it's followed by ':'
5111 * - a element name
5112 * We do an a priori analysis here rather than having to
5113 * maintain parsed token content through the recursive function
5114 * calls. This looks uglier but makes the code quite easier to
5115 * read/write/debug.
5116 */
5117 SKIP_BLANKS;
5118 name = xmlXPathScanName(ctxt);
5119 if (name != NULL) {
5120 int len =xmlStrlen(name);
5121 int blank = 0;
5122
5123 while (NXT(len) != 0) {
5124 if (NXT(len) == '/') {
5125 /* element name */
5126#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005127 xmlGenericError(xmlGenericErrorContext,
5128 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005129#endif
5130 lc = 1;
5131 break;
5132 } else if (IS_BLANK(NXT(len))) {
5133 /* skip to next */
5134 blank = 1;
5135 } else if (NXT(len) == ':') {
5136#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005137 xmlGenericError(xmlGenericErrorContext,
5138 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005139#endif
5140 lc = 1;
5141 break;
5142 } else if ((NXT(len) == '(')) {
5143 /* Note Type or Function */
5144 if (xmlXPathIsNodeType(name)) {
5145#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005146 xmlGenericError(xmlGenericErrorContext,
5147 "PathExpr: Type search\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005148#endif
5149 lc = 1;
5150 } else {
5151#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005152 xmlGenericError(xmlGenericErrorContext,
5153 "PathExpr: function call\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005154#endif
5155 lc = 0;
5156 }
5157 break;
5158 } else if ((NXT(len) == '[')) {
5159 /* element name */
5160#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005161 xmlGenericError(xmlGenericErrorContext,
5162 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005163#endif
5164 lc = 1;
5165 break;
Daniel Veillard389e6b72001-01-15 19:41:13 +00005166 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5167 (NXT(len) == '=')) {
5168 lc = 1;
5169 break;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005170 } else {
Daniel Veillardf6eea272001-01-18 12:17:12 +00005171 lc = 1;
5172 break;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005173 }
5174 len++;
5175 }
5176 if (NXT(len) == 0) {
5177#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005178 xmlGenericError(xmlGenericErrorContext,
5179 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005180#endif
5181 /* element name */
5182 lc = 1;
5183 }
5184 xmlFree(name);
5185 } else {
5186 /* make sure all cases are covered explicitely */
5187 XP_ERROR(XPATH_EXPR_ERROR);
5188 }
5189 }
5190
5191 if (lc) {
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00005192 if (CUR == '/')
5193 xmlXPathRoot(ctxt);
Daniel Veillard5a2b6972001-01-20 21:15:50 +00005194 else {
5195 /* TAG:9999 */
5196 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5197 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005198 xmlXPathEvalLocationPath(ctxt);
5199 } else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005200 xmlXPathEvalFilterExpr(ctxt);
5201 CHECK_ERROR;
5202 if ((CUR == '/') && (NXT(1) == '/')) {
5203 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005204 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005205 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00005206 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005207 ctxt->context->node = NULL;
5208 xmlXPathEvalRelativeLocationPath(ctxt);
5209 } else if (CUR == '/') {
5210 xmlXPathEvalRelativeLocationPath(ctxt);
5211 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005212 }
5213 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005214}
5215
5216/**
5217 * xmlXPathEvalUnionExpr:
5218 * @ctxt: the XPath Parser context
5219 *
5220 * [18] UnionExpr ::= PathExpr
5221 * | UnionExpr '|' PathExpr
5222 *
5223 * Parse and evaluate an union expression, then push the result on the stack
5224 */
5225
5226void
5227xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
5228 xmlXPathEvalPathExpr(ctxt);
5229 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005230 SKIP_BLANKS;
Daniel Veillard08108982001-01-03 15:24:58 +00005231 while (CUR == '|') {
5232 xmlXPathObjectPtr obj1,obj2, tmp;
Daniel Veillard740abf52000-10-02 23:04:54 +00005233
5234 CHECK_TYPE(XPATH_NODESET);
5235 obj1 = valuePop(ctxt);
Daniel Veillard08108982001-01-03 15:24:58 +00005236 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5237 valuePush(ctxt, tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005238
Daniel Veillard00fdf371999-10-08 09:40:39 +00005239 NEXT;
5240 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005241 xmlXPathEvalPathExpr(ctxt);
5242
Daniel Veillard740abf52000-10-02 23:04:54 +00005243 CHECK_TYPE(XPATH_NODESET);
5244 obj2 = valuePop(ctxt);
5245 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
5246 obj2->nodesetval);
Daniel Veillard08108982001-01-03 15:24:58 +00005247 if (ctxt->value == tmp) {
5248 tmp = valuePop(ctxt);
5249 xmlXPathFreeObject(tmp);
5250 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005251 valuePush(ctxt, obj1);
Daniel Veillard740abf52000-10-02 23:04:54 +00005252 xmlXPathFreeObject(obj2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005253 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005254 }
5255}
5256
5257/**
5258 * xmlXPathEvalUnaryExpr:
5259 * @ctxt: the XPath Parser context
5260 *
5261 * [27] UnaryExpr ::= UnionExpr
5262 * | '-' UnaryExpr
5263 *
5264 * Parse and evaluate an unary expression, then push the result on the stack
5265 */
5266
5267void
5268xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
5269 int minus = 0;
5270
Daniel Veillard00fdf371999-10-08 09:40:39 +00005271 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005272 if (CUR == '-') {
5273 minus = 1;
5274 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005275 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005276 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005277 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005278 CHECK_ERROR;
5279 if (minus) {
5280 xmlXPathValueFlipSign(ctxt);
5281 }
5282}
5283
5284/**
5285 * xmlXPathEvalMultiplicativeExpr:
5286 * @ctxt: the XPath Parser context
5287 *
5288 * [26] MultiplicativeExpr ::= UnaryExpr
5289 * | MultiplicativeExpr MultiplyOperator UnaryExpr
5290 * | MultiplicativeExpr 'div' UnaryExpr
5291 * | MultiplicativeExpr 'mod' UnaryExpr
5292 * [34] MultiplyOperator ::= '*'
5293 *
5294 * Parse and evaluate an Additive expression, then push the result on the stack
5295 */
5296
5297void
5298xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
5299 xmlXPathEvalUnaryExpr(ctxt);
5300 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005301 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005302 while ((CUR == '*') ||
5303 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
5304 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
5305 int op = -1;
5306
5307 if (CUR == '*') {
5308 op = 0;
5309 NEXT;
5310 } else if (CUR == 'd') {
5311 op = 1;
5312 SKIP(3);
5313 } else if (CUR == 'm') {
5314 op = 2;
5315 SKIP(3);
5316 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005317 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005318 xmlXPathEvalUnaryExpr(ctxt);
5319 CHECK_ERROR;
5320 switch (op) {
5321 case 0:
5322 xmlXPathMultValues(ctxt);
5323 break;
5324 case 1:
5325 xmlXPathDivValues(ctxt);
5326 break;
5327 case 2:
5328 xmlXPathModValues(ctxt);
5329 break;
5330 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005331 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005332 }
5333}
5334
5335/**
5336 * xmlXPathEvalAdditiveExpr:
5337 * @ctxt: the XPath Parser context
5338 *
5339 * [25] AdditiveExpr ::= MultiplicativeExpr
5340 * | AdditiveExpr '+' MultiplicativeExpr
5341 * | AdditiveExpr '-' MultiplicativeExpr
5342 *
5343 * Parse and evaluate an Additive expression, then push the result on the stack
5344 */
5345
5346void
5347xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
5348 xmlXPathEvalMultiplicativeExpr(ctxt);
5349 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005350 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005351 while ((CUR == '+') || (CUR == '-')) {
5352 int plus;
5353
5354 if (CUR == '+') plus = 1;
5355 else plus = 0;
5356 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005357 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005358 xmlXPathEvalMultiplicativeExpr(ctxt);
5359 CHECK_ERROR;
5360 if (plus) xmlXPathAddValues(ctxt);
5361 else xmlXPathSubValues(ctxt);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005362 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005363 }
5364}
5365
5366/**
5367 * xmlXPathEvalRelationalExpr:
5368 * @ctxt: the XPath Parser context
5369 *
5370 * [24] RelationalExpr ::= AdditiveExpr
5371 * | RelationalExpr '<' AdditiveExpr
5372 * | RelationalExpr '>' AdditiveExpr
5373 * | RelationalExpr '<=' AdditiveExpr
5374 * | RelationalExpr '>=' AdditiveExpr
5375 *
5376 * A <= B > C is allowed ? Answer from James, yes with
5377 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
5378 * which is basically what got implemented.
5379 *
5380 * Parse and evaluate a Relational expression, then push the result
5381 * on the stack
5382 */
5383
5384void
5385xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
5386 xmlXPathEvalAdditiveExpr(ctxt);
5387 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005388 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005389 while ((CUR == '<') ||
5390 (CUR == '>') ||
5391 ((CUR == '<') && (NXT(1) == '=')) ||
5392 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00005393 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005394
5395 if (CUR == '<') inf = 1;
5396 else inf = 0;
5397 if (NXT(1) == '=') strict = 0;
5398 else strict = 1;
5399 NEXT;
5400 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005401 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005402 xmlXPathEvalAdditiveExpr(ctxt);
5403 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00005404 ret = xmlXPathCompareValues(ctxt, inf, strict);
5405 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard55b91f22000-10-05 16:30:11 +00005406 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005407 }
5408}
5409
5410/**
5411 * xmlXPathEvalEqualityExpr:
5412 * @ctxt: the XPath Parser context
5413 *
5414 * [23] EqualityExpr ::= RelationalExpr
5415 * | EqualityExpr '=' RelationalExpr
5416 * | EqualityExpr '!=' RelationalExpr
5417 *
5418 * A != B != C is allowed ? Answer from James, yes with
5419 * (RelationalExpr = RelationalExpr) = RelationalExpr
5420 * (RelationalExpr != RelationalExpr) != RelationalExpr
5421 * which is basically what got implemented.
5422 *
5423 * Parse and evaluate an Equality expression, then push the result on the stack
5424 *
5425 */
5426void
5427xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
5428 xmlXPathEvalRelationalExpr(ctxt);
5429 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005430 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005431 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00005432 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005433 int eq, equal;
5434
5435 if (CUR == '=') eq = 1;
5436 else eq = 0;
5437 NEXT;
5438 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005439 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005440 xmlXPathEvalRelationalExpr(ctxt);
5441 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00005442 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005443 if (eq) res = xmlXPathNewBoolean(equal);
5444 else res = xmlXPathNewBoolean(!equal);
5445 valuePush(ctxt, res);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005446 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005447 }
5448}
5449
5450/**
5451 * xmlXPathEvalAndExpr:
5452 * @ctxt: the XPath Parser context
5453 *
5454 * [22] AndExpr ::= EqualityExpr
5455 * | AndExpr 'and' EqualityExpr
5456 *
5457 * Parse and evaluate an AND expression, then push the result on the stack
5458 *
5459 */
5460void
5461xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
5462 xmlXPathEvalEqualityExpr(ctxt);
5463 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005464 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00005465 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005466 xmlXPathObjectPtr arg1, arg2;
5467
5468 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005469 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005470 xmlXPathEvalEqualityExpr(ctxt);
5471 CHECK_ERROR;
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005472 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005473 arg2 = valuePop(ctxt);
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005474 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005475 arg1 = valuePop(ctxt);
5476 arg1->boolval &= arg2->boolval;
5477 valuePush(ctxt, arg1);
5478 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005479 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005480 }
5481}
5482
5483/**
5484 * xmlXPathEvalExpr:
5485 * @ctxt: the XPath Parser context
5486 *
5487 * [14] Expr ::= OrExpr
5488 * [21] OrExpr ::= AndExpr
5489 * | OrExpr 'or' AndExpr
5490 *
5491 * Parse and evaluate an expression, then push the result on the stack
5492 *
5493 */
5494void
5495xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
5496 xmlXPathEvalAndExpr(ctxt);
5497 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005498 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005499 while ((CUR == 'o') && (NXT(1) == 'r')) {
5500 xmlXPathObjectPtr arg1, arg2;
5501
5502 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005503 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005504 xmlXPathEvalAndExpr(ctxt);
5505 CHECK_ERROR;
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005506 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005507 arg2 = valuePop(ctxt);
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005508 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005509 arg1 = valuePop(ctxt);
5510 arg1->boolval |= arg2->boolval;
5511 valuePush(ctxt, arg1);
5512 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005513 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005514 }
5515}
5516
5517/**
5518 * xmlXPathEvaluatePredicateResult:
5519 * @ctxt: the XPath Parser context
5520 * @res: the Predicate Expression evaluation result
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005521 *
5522 * Evaluate a predicate result for the current node.
5523 * A PredicateExpr is evaluated by evaluating the Expr and converting
5524 * the result to a boolean. If the result is a number, the result will
5525 * be converted to true if the number is equal to the position of the
5526 * context node in the context node list (as returned by the position
5527 * function) and will be converted to false otherwise; if the result
5528 * is not a number, then the result will be converted as if by a call
5529 * to the boolean function.
Daniel Veillard2c833b62001-02-03 08:52:06 +00005530 *
5531 * Return 1 if predicate is true, 0 otherwise
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005532 */
5533int
5534xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005535 xmlXPathObjectPtr res) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005536 if (res == NULL) return(0);
5537 switch (res->type) {
5538 case XPATH_BOOLEAN:
5539 return(res->boolval);
5540 case XPATH_NUMBER:
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005541 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005542 case XPATH_NODESET:
Daniel Veillarde99a4762001-02-01 04:34:35 +00005543 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005544 return(res->nodesetval->nodeNr != 0);
5545 case XPATH_STRING:
5546 return((res->stringval != NULL) &&
5547 (xmlStrlen(res->stringval) != 0));
5548 default:
5549 STRANGE
5550 }
5551 return(0);
5552}
5553
5554/**
5555 * xmlXPathEvalPredicate:
5556 * @ctxt: the XPath Parser context
5557 *
5558 * [8] Predicate ::= '[' PredicateExpr ']'
5559 * [9] PredicateExpr ::= Expr
5560 *
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005561 * ---------------------
5562 * For each node in the node-set to be filtered, the PredicateExpr is
5563 * evaluated with that node as the context node, with the number of nodes
5564 * in the node-set as the context size, and with the proximity position
5565 * of the node in the node-set with respect to the axis as the context
5566 * position; if PredicateExpr evaluates to true for that node, the node
5567 * is included in the new node-set; otherwise, it is not included.
5568 * ---------------------
5569 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005570 * Parse and evaluate a predicate for all the elements of the
5571 * current node list. Then refine the list by removing all
5572 * nodes where the predicate is false.
5573 */
5574void
5575xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005576 const xmlChar *cur;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005577 xmlXPathObjectPtr res;
Daniel Veillard740abf52000-10-02 23:04:54 +00005578 xmlXPathObjectPtr obj, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005579 xmlNodeSetPtr newset = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005580 xmlNodeSetPtr oldset;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005581 int i;
5582
Daniel Veillard00fdf371999-10-08 09:40:39 +00005583 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005584 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005585 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005586 }
5587 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005588 SKIP_BLANKS;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005589
5590 /*
5591 * Extract the old set, and then evaluate the result of the
5592 * expression for all the element in the set. use it to grow
5593 * up a new set.
5594 */
Daniel Veillard740abf52000-10-02 23:04:54 +00005595 CHECK_TYPE(XPATH_NODESET);
5596 obj = valuePop(ctxt);
5597 oldset = obj->nodesetval;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005598 ctxt->context->node = NULL;
5599
5600 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005601 ctxt->context->contextSize = 0;
5602 ctxt->context->proximityPosition = 0;
Daniel Veillardff9c3302000-10-13 16:38:25 +00005603 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005604 res = valuePop(ctxt);
5605 if (res != NULL)
5606 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005607 valuePush(ctxt, obj);
Daniel Veillardff9c3302000-10-13 16:38:25 +00005608 CHECK_ERROR;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005609 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005610 /*
5611 * Save the expression pointer since we will have to evaluate
5612 * it multiple times. Initialize the new set.
5613 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005614 cur = ctxt->cur;
5615 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00005616
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005617 for (i = 0; i < oldset->nodeNr; i++) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005618 ctxt->cur = cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00005619
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005620 /*
5621 * Run the evaluation with a node list made of a single item
5622 * in the nodeset.
5623 */
5624 ctxt->context->node = oldset->nodeTab[i];
Daniel Veillard740abf52000-10-02 23:04:54 +00005625 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5626 valuePush(ctxt, tmp);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005627 ctxt->context->contextSize = oldset->nodeNr;
5628 ctxt->context->proximityPosition = i + 1;
Daniel Veillardbe803962000-06-28 23:40:59 +00005629
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005630 xmlXPathEvalExpr(ctxt);
5631 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005632
5633 /*
5634 * The result of the evaluation need to be tested to
5635 * decided whether the filter succeeded or not
5636 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005637 res = valuePop(ctxt);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005638 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
5639 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
5640 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005641
5642 /*
5643 * Cleanup
5644 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005645 if (res != NULL)
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005646 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005647 if (ctxt->value == tmp) {
5648 res = valuePop(ctxt);
5649 xmlXPathFreeObject(res);
5650 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005651
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005652 ctxt->context->node = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005653 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005654
5655 /*
5656 * The result is used as the new evaluation set.
5657 */
Daniel Veillard740abf52000-10-02 23:04:54 +00005658 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005659 ctxt->context->node = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005660 ctxt->context->contextSize = -1;
5661 ctxt->context->proximityPosition = -1;
Daniel Veillard740abf52000-10-02 23:04:54 +00005662 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005663 }
5664 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005665 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005666 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005667
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005668 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005669 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005670#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005671 xmlGenericError(xmlGenericErrorContext, "After predicate : ");
5672 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5673 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005674#endif
5675}
5676
5677/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00005678 * xmlXPathEvalNodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005679 * @ctxt: the XPath Parser context
Daniel Veillard55b91f22000-10-05 16:30:11 +00005680 * @test: pointer to a xmlXPathTestVal
5681 * @type: pointer to a xmlXPathTypeVal
5682 * @prefix: placeholder for a possible name prefix
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005683 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005684 * [7] NodeTest ::= NameTest
5685 * | NodeType '(' ')'
5686 * | 'processing-instruction' '(' Literal ')'
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005687 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005688 * [37] NameTest ::= '*'
5689 * | NCName ':' '*'
5690 * | QName
5691 * [38] NodeType ::= 'comment'
5692 * | 'text'
5693 * | 'processing-instruction'
5694 * | 'node'
5695 *
5696 * Returns the name found and update @test, @type and @prefix appropriately
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005697 */
Daniel Veillard55b91f22000-10-05 16:30:11 +00005698xmlChar *
5699xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005700 xmlXPathTypeVal *type, const xmlChar **prefix, xmlChar *name) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005701 int blanks;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005702
Daniel Veillard55b91f22000-10-05 16:30:11 +00005703 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
5704 STRANGE;
5705 return(NULL);
5706 }
5707 *type = 0;
5708 *test = 0;
5709 *prefix = NULL;
5710 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005711
Daniel Veillard55b91f22000-10-05 16:30:11 +00005712 if ((name == NULL) && (CUR == '*')) {
5713 /*
5714 * All elements
5715 */
5716 NEXT;
5717 *test = NODE_TEST_ALL;
5718 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005719 }
5720
Daniel Veillard55b91f22000-10-05 16:30:11 +00005721 if (name == NULL)
5722 name = xmlXPathParseNCName(ctxt);
5723 if (name == NULL) {
5724 XP_ERROR0(XPATH_EXPR_ERROR);
5725 }
5726
5727 blanks = IS_BLANK(CUR);
5728 SKIP_BLANKS;
5729 if (CUR == '(') {
5730 NEXT;
5731 /*
5732 * NodeType or PI search
5733 */
5734 if (xmlStrEqual(name, BAD_CAST "comment"))
5735 *type = NODE_TYPE_COMMENT;
5736 else if (xmlStrEqual(name, BAD_CAST "node"))
5737 *type = NODE_TYPE_NODE;
5738 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5739 *type = NODE_TYPE_PI;
5740 else if (xmlStrEqual(name, BAD_CAST "text"))
5741 *type = NODE_TYPE_TEXT;
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005742 else {
5743 if (name != NULL)
5744 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005745 XP_ERROR0(XPATH_EXPR_ERROR);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005746 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005747
5748 *test = NODE_TEST_TYPE;
5749
5750 SKIP_BLANKS;
5751 if (*type == NODE_TYPE_PI) {
5752 /*
5753 * Specific case: search a PI by name.
5754 */
5755 xmlXPathObjectPtr cur;
5756
5757 if (name != NULL)
5758 xmlFree(name);
5759
5760 xmlXPathEvalLiteral(ctxt);
5761 CHECK_ERROR 0;
5762 xmlXPathStringFunction(ctxt, 1);
5763 CHECK_ERROR0;
5764 cur = valuePop(ctxt);
5765 name = xmlStrdup(cur->stringval);
5766 xmlXPathFreeObject(cur);
5767 SKIP_BLANKS;
5768 }
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005769 if (CUR != ')') {
5770 if (name != NULL)
5771 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005772 XP_ERROR0(XPATH_UNCLOSED_ERROR);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005773 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005774 NEXT;
5775 return(name);
5776 }
5777 *test = NODE_TEST_NAME;
5778 if ((!blanks) && (CUR == ':')) {
5779 NEXT;
5780
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005781 /*
5782 * get the namespace name for this prefix
5783 */
5784 *prefix = xmlXPathNsLookup(ctxt->context, name);
5785 if (name != NULL)
5786 xmlFree(name);
5787 if (*prefix == NULL) {
5788 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
5789 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005790
5791 if (CUR == '*') {
5792 /*
5793 * All elements
5794 */
5795 NEXT;
5796 *test = NODE_TEST_ALL;
5797 return(NULL);
5798 }
5799
5800 name = xmlXPathParseNCName(ctxt);
5801 if (name == NULL) {
5802 XP_ERROR0(XPATH_EXPR_ERROR);
5803 }
5804 }
5805 return(name);
5806}
5807
5808/**
5809 * xmlXPathIsAxisName:
5810 * @name: a preparsed name token
5811 *
5812 * [6] AxisName ::= 'ancestor'
5813 * | 'ancestor-or-self'
5814 * | 'attribute'
5815 * | 'child'
5816 * | 'descendant'
5817 * | 'descendant-or-self'
5818 * | 'following'
5819 * | 'following-sibling'
5820 * | 'namespace'
5821 * | 'parent'
5822 * | 'preceding'
5823 * | 'preceding-sibling'
5824 * | 'self'
5825 *
5826 * Returns the axis or 0
5827 */
5828xmlXPathAxisVal
5829xmlXPathIsAxisName(const xmlChar *name) {
5830 xmlXPathAxisVal ret = 0;
5831 switch (name[0]) {
5832 case 'a':
5833 if (xmlStrEqual(name, BAD_CAST "ancestor"))
5834 ret = AXIS_ANCESTOR;
5835 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
5836 ret = AXIS_ANCESTOR_OR_SELF;
5837 if (xmlStrEqual(name, BAD_CAST "attribute"))
5838 ret = AXIS_ATTRIBUTE;
5839 break;
5840 case 'c':
5841 if (xmlStrEqual(name, BAD_CAST "child"))
5842 ret = AXIS_CHILD;
5843 break;
5844 case 'd':
5845 if (xmlStrEqual(name, BAD_CAST "descendant"))
5846 ret = AXIS_DESCENDANT;
5847 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
5848 ret = AXIS_DESCENDANT_OR_SELF;
5849 break;
5850 case 'f':
5851 if (xmlStrEqual(name, BAD_CAST "following"))
5852 ret = AXIS_FOLLOWING;
5853 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
5854 ret = AXIS_FOLLOWING_SIBLING;
5855 break;
5856 case 'n':
5857 if (xmlStrEqual(name, BAD_CAST "namespace"))
5858 ret = AXIS_NAMESPACE;
5859 break;
5860 case 'p':
5861 if (xmlStrEqual(name, BAD_CAST "parent"))
5862 ret = AXIS_PARENT;
5863 if (xmlStrEqual(name, BAD_CAST "preceding"))
5864 ret = AXIS_PRECEDING;
5865 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
5866 ret = AXIS_PRECEDING_SIBLING;
5867 break;
5868 case 's':
5869 if (xmlStrEqual(name, BAD_CAST "self"))
5870 ret = AXIS_SELF;
5871 break;
5872 }
5873 return(ret);
5874}
5875
5876/**
5877 * xmlXPathEvalAxisSpecifier:
5878 * @ctxt: the XPath Parser context
5879 *
5880 *
5881 * Returns the axis found
5882 */
5883xmlXPathAxisVal
5884xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
5885 xmlXPathAxisVal ret = AXIS_CHILD;
5886 int blank = 0;
5887 xmlChar *name;
5888
5889 if (CUR == '@') {
5890 NEXT;
5891 return(AXIS_ATTRIBUTE);
5892 } else {
5893 name = xmlXPathParseNCName(ctxt);
5894 if (name == NULL) {
5895 XP_ERROR0(XPATH_EXPR_ERROR);
5896 }
5897 if (IS_BLANK(CUR))
5898 blank = 1;
5899 SKIP_BLANKS;
5900 if ((CUR == ':') && (NXT(1) == ':')) {
5901 ret = xmlXPathIsAxisName(name);
5902 } else if ((blank) && (CUR == ':'))
5903 XP_ERROR0(XPATH_EXPR_ERROR);
5904
5905 xmlFree(name);
5906 }
5907 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005908}
5909
5910/**
5911 * xmlXPathEvalStep:
5912 * @ctxt: the XPath Parser context
5913 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005914 * [4] Step ::= AxisSpecifier NodeTest Predicate*
5915 * | AbbreviatedStep
Daniel Veillardac260302000-10-04 13:33:43 +00005916 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005917 * [12] AbbreviatedStep ::= '.' | '..'
5918 *
5919 * [5] AxisSpecifier ::= AxisName '::'
5920 * | AbbreviatedAxisSpecifier
5921 *
5922 * [13] AbbreviatedAxisSpecifier ::= '@'?
Daniel Veillardac260302000-10-04 13:33:43 +00005923 *
5924 * Modified for XPtr range support as:
5925 *
5926 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5927 * | AbbreviatedStep
5928 * | 'range-to' '(' Expr ')' Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005929 *
5930 * Evaluate one step in a Location Path
5931 * A location step of . is short for self::node(). This is
5932 * particularly useful in conjunction with //. For example, the
5933 * location path .//para is short for
5934 * self::node()/descendant-or-self::node()/child::para
5935 * and so will select all para descendant elements of the context
5936 * node.
5937 * Similarly, a location step of .. is short for parent::node().
5938 * For example, ../title is short for parent::node()/child::title
5939 * and so will select the title children of the parent of the context
5940 * node.
5941 */
5942void
5943xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005944 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005945 if ((CUR == '.') && (NXT(1) == '.')) {
5946 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005947 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005948 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
Daniel Veillard767662d2000-10-27 17:04:52 +00005949 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005950 } else if (CUR == '.') {
5951 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005952 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005953 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005954 xmlChar *name = NULL;
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005955 const xmlChar *prefix = NULL;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005956 xmlXPathTestVal test;
5957 xmlXPathAxisVal axis;
5958 xmlXPathTypeVal type;
5959
5960 /*
5961 * The modification needed for XPointer change to the production
5962 */
Daniel Veillardac260302000-10-04 13:33:43 +00005963#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard55b91f22000-10-05 16:30:11 +00005964 if (ctxt->context->xptr) {
5965 name = xmlXPathParseNCName(ctxt);
5966 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
5967 xmlFree(name);
5968 SKIP_BLANKS;
5969 if (CUR != '(') {
5970 XP_ERROR(XPATH_EXPR_ERROR);
5971 }
5972 NEXT;
5973 SKIP_BLANKS;
Daniel Veillardac260302000-10-04 13:33:43 +00005974
Daniel Veillard55b91f22000-10-05 16:30:11 +00005975 xmlXPtrRangeToFunction(ctxt, 1);
Daniel Veillardac260302000-10-04 13:33:43 +00005976 CHECK_ERROR;
5977
Daniel Veillard55b91f22000-10-05 16:30:11 +00005978 SKIP_BLANKS;
5979 if (CUR != ')') {
5980 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardac260302000-10-04 13:33:43 +00005981 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005982 NEXT;
5983 goto eval_predicates;
Daniel Veillardac260302000-10-04 13:33:43 +00005984 }
Daniel Veillardac260302000-10-04 13:33:43 +00005985 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005986#endif
5987 if (name == NULL)
5988 name = xmlXPathParseNCName(ctxt);
5989 if (name != NULL) {
5990 axis = xmlXPathIsAxisName(name);
5991 if (axis != 0) {
5992 SKIP_BLANKS;
5993 if ((CUR == ':') && (NXT(1) == ':')) {
5994 SKIP(2);
5995 xmlFree(name);
5996 name = NULL;
5997 } else {
5998 /* an element name can conflict with an axis one :-\ */
5999 axis = AXIS_CHILD;
6000 }
6001 } else {
6002 axis = AXIS_CHILD;
6003 }
6004 } else if (CUR == '@') {
6005 NEXT;
6006 axis = AXIS_ATTRIBUTE;
6007 } else {
6008 axis = AXIS_CHILD;
6009 }
6010
6011 CHECK_ERROR;
6012
6013 name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
6014 if (test == 0)
6015 return;
6016
6017#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006018 xmlGenericError(xmlGenericErrorContext,
6019 "Basis : computing new set\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00006020#endif
6021 xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
6022#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006023 xmlGenericError(xmlGenericErrorContext, "Basis : ");
6024 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Daniel Veillard55b91f22000-10-05 16:30:11 +00006025#endif
6026 if (name != NULL)
6027 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00006028
6029eval_predicates:
Daniel Veillard00fdf371999-10-08 09:40:39 +00006030 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006031 while (CUR == '[') {
6032 xmlXPathEvalPredicate(ctxt);
6033 }
6034 }
6035#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006036 xmlGenericError(xmlGenericErrorContext, "Step : ");
6037 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6038 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006039#endif
6040}
6041
6042/**
6043 * xmlXPathEvalRelativeLocationPath:
6044 * @ctxt: the XPath Parser context
6045 *
6046 * [3] RelativeLocationPath ::= Step
6047 * | RelativeLocationPath '/' Step
6048 * | AbbreviatedRelativeLocationPath
6049 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6050 *
6051 */
6052void
Daniel Veillardce6e98d2000-11-25 09:54:49 +00006053#ifdef VMS
6054xmlXPathEvalRelLocationPath
6055#else
6056xmlXPathEvalRelativeLocationPath
6057#endif
6058(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00006059 SKIP_BLANKS;
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00006060 if ((CUR == '/') && (NXT(1) == '/')) {
6061 SKIP(2);
6062 SKIP_BLANKS;
6063 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00006064 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00006065 } else if (CUR == '/') {
6066 NEXT;
6067 SKIP_BLANKS;
6068 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006069 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006070 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006071 while (CUR == '/') {
6072 if ((CUR == '/') && (NXT(1) == '/')) {
6073 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006074 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00006075 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00006076 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006077 xmlXPathEvalStep(ctxt);
6078 } else if (CUR == '/') {
6079 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00006080 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006081 xmlXPathEvalStep(ctxt);
6082 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00006083 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006084 }
6085}
6086
6087/**
6088 * xmlXPathEvalLocationPath:
6089 * @ctxt: the XPath Parser context
6090 *
6091 * [1] LocationPath ::= RelativeLocationPath
6092 * | AbsoluteLocationPath
6093 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6094 * | AbbreviatedAbsoluteLocationPath
6095 * [10] AbbreviatedAbsoluteLocationPath ::=
6096 * '//' RelativeLocationPath
6097 *
6098 * // is short for /descendant-or-self::node()/. For example,
6099 * //para is short for /descendant-or-self::node()/child::para and
6100 * so will select any para element in the document (even a para element
6101 * that is a document element will be selected by //para since the
6102 * document element node is a child of the root node); div//para is
6103 * short for div/descendant-or-self::node()/child::para and so will
6104 * select all para descendants of div children.
6105 */
6106void
6107xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00006108 SKIP_BLANKS;
6109 if (CUR != '/') {
6110 xmlXPathEvalRelativeLocationPath(ctxt);
6111 } else {
6112 while (CUR == '/') {
6113 if ((CUR == '/') && (NXT(1) == '/')) {
6114 SKIP(2);
6115 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00006116 xmlXPathNodeCollectAndTest(ctxt,
Daniel Veillard00fdf371999-10-08 09:40:39 +00006117 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
Daniel Veillard767662d2000-10-27 17:04:52 +00006118 NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006119 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006120 } else if (CUR == '/') {
6121 NEXT;
6122 SKIP_BLANKS;
Daniel Veillard00fdf371999-10-08 09:40:39 +00006123 if (CUR != 0)
6124 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006125 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006126 }
6127 }
6128}
6129
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006130/**
6131 * xmlXPathEval:
6132 * @str: the XPath expression
Daniel Veillard740abf52000-10-02 23:04:54 +00006133 * @ctx: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006134 *
6135 * Evaluate the XPath Location Path in the given context.
6136 *
6137 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
6138 * the caller has to free the object.
6139 */
6140xmlXPathObjectPtr
Daniel Veillard740abf52000-10-02 23:04:54 +00006141xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
6142 xmlXPathParserContextPtr ctxt;
Daniel Veillard41e06512000-11-13 11:47:47 +00006143 xmlXPathObjectPtr res = NULL, tmp, init = NULL;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006144 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006145
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006146 xmlXPathInit();
6147
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00006148 CHECK_CONTEXT(ctx)
6149
Daniel Veillard740abf52000-10-02 23:04:54 +00006150 ctxt = xmlXPathNewParserContext(str, ctx);
Daniel Veillard5a2b6972001-01-20 21:15:50 +00006151 /**** TAG:9999
Daniel Veillard41e06512000-11-13 11:47:47 +00006152 if (ctx->node != NULL) {
6153 init = xmlXPathNewNodeSet(ctx->node);
6154 valuePush(ctxt, init);
6155 }
Daniel Veillard5a2b6972001-01-20 21:15:50 +00006156 ****/
Daniel Veillard55b91f22000-10-05 16:30:11 +00006157 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006158
Daniel Veillard767662d2000-10-27 17:04:52 +00006159 if (ctxt->value == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006160 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard767662d2000-10-27 17:04:52 +00006161 "xmlXPathEval: evaluation failed\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00006162 } else {
6163 res = valuePop(ctxt);
6164 }
6165
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006166 do {
Daniel Veillard740abf52000-10-02 23:04:54 +00006167 tmp = valuePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006168 if (tmp != NULL) {
Daniel Veillard41e06512000-11-13 11:47:47 +00006169 if (tmp != init)
6170 stack++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00006171 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006172 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00006173 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006174 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006175 xmlGenericError(xmlGenericErrorContext,
6176 "xmlXPathEval: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006177 stack);
6178 }
Daniel Veillard740abf52000-10-02 23:04:54 +00006179 if (ctxt->error != XPATH_EXPRESSION_OK) {
6180 xmlXPathFreeObject(res);
6181 res = NULL;
6182 }
Daniel Veillardbe803962000-06-28 23:40:59 +00006183
Daniel Veillard740abf52000-10-02 23:04:54 +00006184 xmlXPathFreeParserContext(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006185 return(res);
6186}
6187
6188/**
6189 * xmlXPathEvalExpression:
6190 * @str: the XPath expression
6191 * @ctxt: the XPath context
6192 *
6193 * Evaluate the XPath expression in the given context.
6194 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00006195 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006196 * the caller has to free the object.
6197 */
6198xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006199xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006200 xmlXPathParserContextPtr pctxt;
6201 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006202 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006203
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006204 xmlXPathInit();
6205
Daniel Veillard740abf52000-10-02 23:04:54 +00006206 CHECK_CONTEXT(ctxt)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006207
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006208 pctxt = xmlXPathNewParserContext(str, ctxt);
6209 xmlXPathEvalExpr(pctxt);
6210
6211 res = valuePop(pctxt);
6212 do {
6213 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006214 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006215 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006216 stack++;
6217 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006218 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006219 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006220 xmlGenericError(xmlGenericErrorContext,
6221 "xmlXPathEvalExpression: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006222 stack);
6223 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006224 xmlXPathFreeParserContext(pctxt);
6225 return(res);
6226}
6227
Daniel Veillardf17e09b2001-01-25 13:55:35 +00006228/**
6229 * xmlXPathRegisterAllFunctions:
6230 * @ctxt: the XPath context
6231 *
6232 * Registers all default XPath functions in this context
6233 */
Daniel Veillard52afe802000-10-22 16:56:02 +00006234void
6235xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
6236{
6237 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
6238 xmlXPathBooleanFunction);
6239 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
6240 xmlXPathCeilingFunction);
6241 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
6242 xmlXPathCountFunction);
6243 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
6244 xmlXPathConcatFunction);
6245 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
6246 xmlXPathContainsFunction);
6247 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
6248 xmlXPathIdFunction);
6249 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
6250 xmlXPathFalseFunction);
6251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
6252 xmlXPathFloorFunction);
6253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
6254 xmlXPathLastFunction);
6255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
6256 xmlXPathLangFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00006257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
6258 xmlXPathLocalNameFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
6260 xmlXPathNotFunction);
6261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
6262 xmlXPathNameFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00006263 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
6264 xmlXPathNamespaceURIFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006265 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
6266 xmlXPathNormalizeFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006267 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
6268 xmlXPathNumberFunction);
6269 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
6270 xmlXPathPositionFunction);
6271 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
6272 xmlXPathRoundFunction);
6273 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
6274 xmlXPathStringFunction);
6275 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
6276 xmlXPathStringLengthFunction);
6277 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
6278 xmlXPathStartsWithFunction);
6279 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
6280 xmlXPathSubstringFunction);
6281 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
6282 xmlXPathSubstringBeforeFunction);
6283 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
6284 xmlXPathSubstringAfterFunction);
6285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
6286 xmlXPathSumFunction);
6287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
6288 xmlXPathTrueFunction);
6289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
6290 xmlXPathTranslateFunction);
6291}
6292
Daniel Veillard361d8452000-04-03 19:48:13 +00006293#endif /* LIBXML_XPATH_ENABLED */