blob: 0786a6d0e1f0fa31d794f56c1c3835cfde337d23 [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 Veillardf41fbbf2001-02-13 17:05:35 +0000587/**
588 * xmlXPathNodeSetSort:
589 * @set: the node set
590 *
591 * Sort the node set in document order
592 */
593void
594xmlXPathNodeSetSort(xmlNodeSetPtr set) {
595 int i, j;
596 xmlNodePtr tmp;
597
598 if (set == NULL)
599 return;
600
601 for (i = 0;i < set->nodeNr -1;i++) {
602 for (j = i + 1; j < set->nodeNr; j++) {
603 if (xmlXPathCmpNodes(set->nodeTab[i], set->nodeTab[j]) == -1) {
604 tmp = set->nodeTab[i];
605 set->nodeTab[i] = set->nodeTab[j];
606 set->nodeTab[j] = tmp;
607 }
608 }
609 }
610}
611
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000612#define XML_NODESET_DEFAULT 10
613/**
614 * xmlXPathNodeSetCreate:
615 * @val: an initial xmlNodePtr, or NULL
616 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000617 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000618 *
619 * Returns the newly created object.
620 */
621xmlNodeSetPtr
622xmlXPathNodeSetCreate(xmlNodePtr val) {
623 xmlNodeSetPtr ret;
624
Daniel Veillard6454aec1999-09-02 22:04:43 +0000625 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000626 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000627 xmlGenericError(xmlGenericErrorContext,
628 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000629 return(NULL);
630 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000631 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000632 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000633 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000634 sizeof(xmlNodePtr));
635 if (ret->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000636 xmlGenericError(xmlGenericErrorContext,
637 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000638 return(NULL);
639 }
640 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000641 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000642 ret->nodeMax = XML_NODESET_DEFAULT;
643 ret->nodeTab[ret->nodeNr++] = val;
644 }
645 return(ret);
646}
647
648/**
649 * xmlXPathNodeSetAdd:
650 * @cur: the initial node set
651 * @val: a new xmlNodePtr
652 *
653 * add a new xmlNodePtr ot an existing NodeSet
654 */
655void
656xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
657 int i;
658
659 if (val == NULL) return;
660
661 /*
662 * check against doublons
663 */
664 for (i = 0;i < cur->nodeNr;i++)
665 if (cur->nodeTab[i] == val) return;
666
667 /*
668 * grow the nodeTab if needed
669 */
670 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000671 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000672 sizeof(xmlNodePtr));
673 if (cur->nodeTab == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000674 xmlGenericError(xmlGenericErrorContext,
675 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000676 return;
677 }
678 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000679 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000680 cur->nodeMax = XML_NODESET_DEFAULT;
681 } else if (cur->nodeNr == cur->nodeMax) {
682 xmlNodePtr *temp;
683
684 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000685 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000686 sizeof(xmlNodePtr));
687 if (temp == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000688 xmlGenericError(xmlGenericErrorContext,
689 "xmlXPathNodeSetAdd: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000690 return;
691 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000692 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000693 }
694 cur->nodeTab[cur->nodeNr++] = val;
695}
696
697/**
Daniel Veillard2c257ec2001-02-06 13:29:07 +0000698 * xmlXPathNodeSetAddUnique:
699 * @cur: the initial node set
700 * @val: a new xmlNodePtr
701 *
702 * add a new xmlNodePtr ot an existing NodeSet, optimized version
703 * when we are sure the node is not already in the set.
704 */
705void
706xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
707 if (val == NULL) return;
708
709 /*
710 * grow the nodeTab if needed
711 */
712 if (cur->nodeMax == 0) {
713 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
714 sizeof(xmlNodePtr));
715 if (cur->nodeTab == NULL) {
716 xmlGenericError(xmlGenericErrorContext,
717 "xmlXPathNodeSetAddUnique: out of memory\n");
718 return;
719 }
720 memset(cur->nodeTab, 0 ,
721 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
722 cur->nodeMax = XML_NODESET_DEFAULT;
723 } else if (cur->nodeNr == cur->nodeMax) {
724 xmlNodePtr *temp;
725
726 cur->nodeMax *= 2;
727 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
728 sizeof(xmlNodePtr));
729 if (temp == NULL) {
730 xmlGenericError(xmlGenericErrorContext,
731 "xmlXPathNodeSetAddUnique: out of memory\n");
732 return;
733 }
734 cur->nodeTab = temp;
735 }
736 cur->nodeTab[cur->nodeNr++] = val;
737}
738
739/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000740 * xmlXPathNodeSetMerge:
Daniel Veillard2d38f042000-10-11 10:54:10 +0000741 * @val1: the first NodeSet or NULL
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000742 * @val2: the second NodeSet
743 *
744 * Merges two nodesets, all nodes from @val2 are added to @val1
Daniel Veillard2d38f042000-10-11 10:54:10 +0000745 * if @val1 is NULL, a new set is created and copied from @val2
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000746 *
747 * Returns val1 once extended or NULL in case of error.
748 */
749xmlNodeSetPtr
750xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000751 int i, j, initNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000752
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000753 if (val2 == NULL) return(val1);
Daniel Veillard2d38f042000-10-11 10:54:10 +0000754 if (val1 == NULL) {
755 val1 = xmlXPathNodeSetCreate(NULL);
756 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000757
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000758 initNr = val1->nodeNr;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000759
Daniel Veillard9e8bfae2000-11-06 16:43:11 +0000760 for (i = 0;i < val2->nodeNr;i++) {
761 /*
762 * check against doublons
763 */
764 for (j = 0; j < initNr; j++)
765 if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
766
767 /*
768 * grow the nodeTab if needed
769 */
770 if (val1->nodeMax == 0) {
771 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
772 sizeof(xmlNodePtr));
773 if (val1->nodeTab == NULL) {
774 xmlGenericError(xmlGenericErrorContext,
775 "xmlXPathNodeSetMerge: out of memory\n");
776 return(NULL);
777 }
778 memset(val1->nodeTab, 0 ,
779 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
780 val1->nodeMax = XML_NODESET_DEFAULT;
781 } else if (val1->nodeNr == val1->nodeMax) {
782 xmlNodePtr *temp;
783
784 val1->nodeMax *= 2;
785 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
786 sizeof(xmlNodePtr));
787 if (temp == NULL) {
788 xmlGenericError(xmlGenericErrorContext,
789 "xmlXPathNodeSetMerge: out of memory\n");
790 return(NULL);
791 }
792 val1->nodeTab = temp;
793 }
794 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
795 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000796
797 return(val1);
798}
799
800/**
801 * xmlXPathNodeSetDel:
802 * @cur: the initial node set
803 * @val: an xmlNodePtr
804 *
805 * Removes an xmlNodePtr from an existing NodeSet
806 */
807void
808xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
809 int i;
810
811 if (cur == NULL) return;
812 if (val == NULL) return;
813
814 /*
815 * check against doublons
816 */
817 for (i = 0;i < cur->nodeNr;i++)
818 if (cur->nodeTab[i] == val) break;
819
820 if (i >= cur->nodeNr) {
821#ifdef DEBUG
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000822 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000823 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
824 val->name);
825#endif
826 return;
827 }
828 cur->nodeNr--;
829 for (;i < cur->nodeNr;i++)
830 cur->nodeTab[i] = cur->nodeTab[i + 1];
831 cur->nodeTab[cur->nodeNr] = NULL;
832}
833
834/**
835 * xmlXPathNodeSetRemove:
836 * @cur: the initial node set
837 * @val: the index to remove
838 *
839 * Removes an entry from an existing NodeSet list.
840 */
841void
842xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
843 if (cur == NULL) return;
844 if (val >= cur->nodeNr) return;
845 cur->nodeNr--;
846 for (;val < cur->nodeNr;val++)
847 cur->nodeTab[val] = cur->nodeTab[val + 1];
848 cur->nodeTab[cur->nodeNr] = NULL;
849}
850
851/**
852 * xmlXPathFreeNodeSet:
853 * @obj: the xmlNodeSetPtr to free
854 *
855 * Free the NodeSet compound (not the actual nodes !).
856 */
857void
858xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
859 if (obj == NULL) return;
860 if (obj->nodeTab != NULL) {
861#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000862 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000863#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000864 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000865 }
866#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000867 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000868#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000869 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000870}
871
Daniel Veillard8a7642f2001-01-22 10:45:16 +0000872/**
873 * xmlXPathFreeValueTree:
874 * @obj: the xmlNodeSetPtr to free
875 *
876 * Free the NodeSet compound and the actual tree, this is different
877 * from xmlXPathFreeNodeSet()
878 */
879void
880xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
881 int i;
882
883 if (obj == NULL) return;
884 for (i = 0;i < obj->nodeNr;i++)
885 if (obj->nodeTab[i] != NULL)
886 xmlFreeNode(obj->nodeTab[i]);
887
888 if (obj->nodeTab != NULL) {
889#ifdef DEBUG
890 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
891#endif
892 xmlFree(obj->nodeTab);
893 }
894#ifdef DEBUG
895 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
896#endif
897 xmlFree(obj);
898}
899
Daniel Veillardb96e6431999-08-29 21:02:19 +0000900#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000901/**
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000902 * xmlGenericErrorContextNodeSet:
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000903 * @output: a FILE * for the output
904 * @obj: the xmlNodeSetPtr to free
905 *
906 * Quick display of a NodeSet
907 */
908void
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000909xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000910 int i;
911
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000912 if (output == NULL) output = xmlGenericErrorContext;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000913 if (obj == NULL) {
914 fprintf(output, "NodeSet == NULL !\n");
915 return;
916 }
917 if (obj->nodeNr == 0) {
918 fprintf(output, "NodeSet is empty\n");
919 return;
920 }
921 if (obj->nodeTab == NULL) {
922 fprintf(output, " nodeTab == NULL !\n");
923 return;
924 }
925 for (i = 0; i < obj->nodeNr; i++) {
926 if (obj->nodeTab[i] == NULL) {
927 fprintf(output, " NULL !\n");
928 return;
929 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000930 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
931 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000932 fprintf(output, " /");
933 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000934 fprintf(output, " noname!");
935 else fprintf(output, " %s", obj->nodeTab[i]->name);
936 }
937 fprintf(output, "\n");
938}
939#endif
940
Daniel Veillard7e99c632000-10-06 12:59:53 +0000941/**
942 * xmlXPathNewNodeSet:
943 * @val: the NodePtr value
944 *
945 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
946 * it with the single Node @val
947 *
948 * Returns the newly created object.
949 */
950xmlXPathObjectPtr
951xmlXPathNewNodeSet(xmlNodePtr val) {
952 xmlXPathObjectPtr ret;
953
954 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
955 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +0000956 xmlGenericError(xmlGenericErrorContext,
957 "xmlXPathNewNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +0000958 return(NULL);
959 }
960 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
961 ret->type = XPATH_NODESET;
962 ret->nodesetval = xmlXPathNodeSetCreate(val);
963 return(ret);
964}
965
966/**
Daniel Veillarde4566462001-01-22 09:58:39 +0000967 * xmlXPathNewValueTree:
968 * @val: the NodePtr value
969 *
970 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
971 * it with the tree root @val
972 *
973 * Returns the newly created object.
974 */
975xmlXPathObjectPtr
976xmlXPathNewValueTree(xmlNodePtr val) {
977 xmlXPathObjectPtr ret;
978
979 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
980 if (ret == NULL) {
981 xmlGenericError(xmlGenericErrorContext,
982 "xmlXPathNewNodeSet: out of memory\n");
983 return(NULL);
984 }
985 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
986 ret->type = XPATH_XSLT_TREE;
987 ret->nodesetval = xmlXPathNodeSetCreate(val);
988 return(ret);
989}
990
991/**
Daniel Veillard7e99c632000-10-06 12:59:53 +0000992 * xmlXPathNewNodeSetList:
993 * @val: an existing NodeSet
994 *
995 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
996 * it with the Nodeset @val
997 *
998 * Returns the newly created object.
999 */
1000xmlXPathObjectPtr
1001xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1002 xmlXPathObjectPtr ret;
1003 int i;
1004
1005 if (val == NULL)
1006 ret = NULL;
1007 else if (val->nodeTab == NULL)
1008 ret = xmlXPathNewNodeSet(NULL);
1009 else
1010 {
1011 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1012 for (i = 1; i < val->nodeNr; ++i)
Daniel Veillard2c257ec2001-02-06 13:29:07 +00001013 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
Daniel Veillard7e99c632000-10-06 12:59:53 +00001014 }
1015
1016 return(ret);
1017}
1018
1019/**
1020 * xmlXPathWrapNodeSet:
1021 * @val: the NodePtr value
1022 *
1023 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1024 *
1025 * Returns the newly created object.
1026 */
1027xmlXPathObjectPtr
1028xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1029 xmlXPathObjectPtr ret;
1030
1031 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1032 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001033 xmlGenericError(xmlGenericErrorContext,
1034 "xmlXPathWrapNodeSet: out of memory\n");
Daniel Veillard7e99c632000-10-06 12:59:53 +00001035 return(NULL);
1036 }
1037 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1038 ret->type = XPATH_NODESET;
1039 ret->nodesetval = val;
1040 return(ret);
1041}
1042
1043/**
1044 * xmlXPathFreeNodeSetList:
1045 * @obj: an existing NodeSetList object
1046 *
1047 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1048 * the list contrary to xmlXPathFreeObject().
1049 */
1050void
1051xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1052 if (obj == NULL) return;
1053#ifdef DEBUG
1054 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
1055#endif
1056 xmlFree(obj);
1057}
1058
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001059/************************************************************************
1060 * *
Daniel Veillard2d38f042000-10-11 10:54:10 +00001061 * Routines to handle extra functions *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001062 * *
1063 ************************************************************************/
1064
1065/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001066 * xmlXPathRegisterFunc:
1067 * @ctxt: the XPath context
1068 * @name: the function name
1069 * @f: the function implementation or NULL
1070 *
1071 * Register a new function. If @f is NULL it unregisters the function
1072 *
1073 * Returns 0 in case of success, -1 in case of error
1074 */
1075int
1076xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1077 xmlXPathFunction f) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001078 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1079}
1080
1081/**
1082 * xmlXPathRegisterFuncNS:
1083 * @ctxt: the XPath context
1084 * @name: the function name
1085 * @ns_uri: the function namespace URI
1086 * @f: the function implementation or NULL
1087 *
1088 * Register a new function. If @f is NULL it unregisters the function
1089 *
1090 * Returns 0 in case of success, -1 in case of error
1091 */
1092int
1093xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1094 const xmlChar *ns_uri, xmlXPathFunction f) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001095 if (ctxt == NULL)
1096 return(-1);
1097 if (name == NULL)
1098 return(-1);
1099
Daniel Veillard52afe802000-10-22 16:56:02 +00001100 if (ctxt->funcHash == NULL)
1101 ctxt->funcHash = xmlHashCreate(0);
1102 if (ctxt->funcHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +00001103 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001104 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001105}
1106
1107/**
1108 * xmlXPathFunctionLookup:
1109 * @ctxt: the XPath context
1110 * @name: the function name
1111 *
1112 * Search in the Function array of the context for the given
1113 * function.
1114 *
1115 * Returns the xmlXPathFunction or NULL if not found
1116 */
1117xmlXPathFunction
1118xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001119 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1120}
1121
1122/**
1123 * xmlXPathFunctionLookupNS:
1124 * @ctxt: the XPath context
1125 * @name: the function name
1126 * @ns_uri: the function namespace URI
1127 *
1128 * Search in the Function array of the context for the given
1129 * function.
1130 *
1131 * Returns the xmlXPathFunction or NULL if not found
1132 */
1133xmlXPathFunction
1134xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1135 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001136 if (ctxt == NULL)
1137 return(NULL);
Daniel Veillard52afe802000-10-22 16:56:02 +00001138 if (ctxt->funcHash == NULL)
1139 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001140 if (name == NULL)
1141 return(NULL);
1142
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001143 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001144}
1145
1146/**
1147 * xmlXPathRegisteredFuncsCleanup:
1148 * @ctxt: the XPath context
1149 *
1150 * Cleanup the XPath context data associated to registered functions
1151 */
1152void
1153xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001154 if (ctxt == NULL)
1155 return;
1156
Daniel Veillard52afe802000-10-22 16:56:02 +00001157 xmlHashFree(ctxt->funcHash, NULL);
1158 ctxt->funcHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001159}
1160
1161/************************************************************************
1162 * *
1163 * Routines to handle Variable *
1164 * *
1165 ************************************************************************/
1166
1167/**
1168 * xmlXPathRegisterVariable:
1169 * @ctxt: the XPath context
1170 * @name: the variable name
1171 * @value: the variable value or NULL
1172 *
1173 * Register a new variable value. If @value is NULL it unregisters
1174 * the variable
1175 *
1176 * Returns 0 in case of success, -1 in case of error
1177 */
1178int
1179xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1180 xmlXPathObjectPtr value) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001181 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1182}
1183
1184/**
1185 * xmlXPathRegisterVariableNS:
1186 * @ctxt: the XPath context
1187 * @name: the variable name
1188 * @ns_uri: the variable namespace URI
1189 * @value: the variable value or NULL
1190 *
1191 * Register a new variable value. If @value is NULL it unregisters
1192 * the variable
1193 *
1194 * Returns 0 in case of success, -1 in case of error
1195 */
1196int
1197xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1198 const xmlChar *ns_uri,
1199 xmlXPathObjectPtr value) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001200 if (ctxt == NULL)
1201 return(-1);
1202 if (name == NULL)
1203 return(-1);
1204
Daniel Veillard126f2792000-10-24 17:10:12 +00001205 if (ctxt->varHash == NULL)
1206 ctxt->varHash = xmlHashCreate(0);
1207 if (ctxt->varHash == NULL)
Daniel Veillard2d38f042000-10-11 10:54:10 +00001208 return(-1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001209 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1210 (void *) value,
1211 (xmlHashDeallocator)xmlXPathFreeObject));
Daniel Veillard2d38f042000-10-11 10:54:10 +00001212}
1213
1214/**
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001215 * xmlXPathRegisterVariableLookup:
1216 * @ctxt: the XPath context
1217 * @f: the lookup function
1218 * @data: the lookup data
1219 *
1220 * register an external mechanism to do variable lookup
1221 */
1222void
1223xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1224 xmlXPathVariableLookupFunc f, void *data) {
1225 if (ctxt == NULL)
1226 return;
1227 ctxt->varLookupFunc = (void *) f;
1228 ctxt->varLookupData = data;
1229}
1230
1231/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001232 * xmlXPathVariableLookup:
1233 * @ctxt: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001234 * @name: the variable name
1235 *
1236 * Search in the Variable array of the context for the given
1237 * variable value.
1238 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001239 * Returns the value or NULL if not found
1240 */
1241xmlXPathObjectPtr
Daniel Veillard2d38f042000-10-11 10:54:10 +00001242xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001243 if (ctxt == NULL)
1244 return(NULL);
1245
1246 if (ctxt->varLookupFunc != NULL) {
1247 xmlXPathObjectPtr ret;
1248
1249 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1250 (ctxt->varLookupData, name, NULL);
1251 if (ret != NULL) return(ret);
1252 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001253 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1254}
1255
1256/**
1257 * xmlXPathVariableLookupNS:
1258 * @ctxt: the XPath context
1259 * @name: the variable name
1260 * @ns_uri: the variable namespace URI
1261 *
1262 * Search in the Variable array of the context for the given
1263 * variable value.
1264 *
1265 * Returns the value or NULL if not found
1266 */
1267xmlXPathObjectPtr
1268xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1269 const xmlChar *ns_uri) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001270 if (ctxt == NULL)
1271 return(NULL);
Daniel Veillard8f4d9752001-01-19 05:32:34 +00001272
1273 if (ctxt->varLookupFunc != NULL) {
1274 xmlXPathObjectPtr ret;
1275
1276 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1277 (ctxt->varLookupData, name, ns_uri);
1278 if (ret != NULL) return(ret);
1279 }
1280
Daniel Veillard126f2792000-10-24 17:10:12 +00001281 if (ctxt->varHash == NULL)
1282 return(NULL);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001283 if (name == NULL)
1284 return(NULL);
1285
Daniel Veillarda5db68a2000-10-29 18:06:06 +00001286 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001287}
1288
Daniel Veillard2d38f042000-10-11 10:54:10 +00001289/**
1290 * xmlXPathRegisteredVariablesCleanup:
1291 * @ctxt: the XPath context
1292 *
1293 * Cleanup the XPath context data associated to registered variables
1294 */
1295void
1296xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
Daniel Veillard2d38f042000-10-11 10:54:10 +00001297 if (ctxt == NULL)
1298 return;
1299
Daniel Veillard126f2792000-10-24 17:10:12 +00001300 xmlHashFree(ctxt->varHash, NULL);
1301 ctxt->varHash = NULL;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001302}
1303
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001304/**
1305 * xmlXPathRegisterNs:
1306 * @ctxt: the XPath context
1307 * @prefix: the namespace prefix
1308 * @ns_uri: the namespace name
1309 *
1310 * Register a new namespace. If @ns_uri is NULL it unregisters
1311 * the namespace
1312 *
1313 * Returns 0 in case of success, -1 in case of error
1314 */
1315int
1316xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1317 const xmlChar *ns_uri) {
1318 if (ctxt == NULL)
1319 return(-1);
1320 if (prefix == NULL)
1321 return(-1);
1322
1323 if (ctxt->nsHash == NULL)
1324 ctxt->nsHash = xmlHashCreate(10);
1325 if (ctxt->nsHash == NULL)
1326 return(-1);
1327 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1328 (xmlHashDeallocator)xmlFree));
1329}
1330
1331/**
1332 * xmlXPathNsLookup:
1333 * @ctxt: the XPath context
1334 * @prefix: the namespace prefix value
1335 *
1336 * Search in the namespace declaration array of the context for the given
1337 * namespace name associated to the given prefix
1338 *
1339 * Returns the value or NULL if not found
1340 */
1341const xmlChar *
1342xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1343 if (ctxt == NULL)
1344 return(NULL);
1345 if (prefix == NULL)
1346 return(NULL);
Daniel Veillarde0e26512001-02-16 00:11:46 +00001347
1348#ifdef XML_XML_NAMESPACE
1349 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1350 return(XML_XML_NAMESPACE);
1351#endif
1352
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001353 if (ctxt->nsHash == NULL)
1354 return(NULL);
1355
1356 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1357}
1358
1359/**
1360 * xmlXPathRegisteredVariablesCleanup:
1361 * @ctxt: the XPath context
1362 *
1363 * Cleanup the XPath context data associated to registered variables
1364 */
1365void
1366xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
1367 if (ctxt == NULL)
1368 return;
1369
1370 xmlHashFree(ctxt->nsHash, NULL);
1371 ctxt->nsHash = NULL;
1372}
1373
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001374/************************************************************************
1375 * *
1376 * Routines to handle Values *
1377 * *
1378 ************************************************************************/
1379
1380/* Allocations are terrible, one need to optimize all this !!! */
1381
1382/**
1383 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001384 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001385 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001386 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001387 *
1388 * Returns the newly created object.
1389 */
1390xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001391xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001392 xmlXPathObjectPtr ret;
1393
Daniel Veillard6454aec1999-09-02 22:04:43 +00001394 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001395 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001396 xmlGenericError(xmlGenericErrorContext,
1397 "xmlXPathNewFloat: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001398 return(NULL);
1399 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001400 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001401 ret->type = XPATH_NUMBER;
1402 ret->floatval = val;
1403 return(ret);
1404}
1405
1406/**
1407 * xmlXPathNewBoolean:
1408 * @val: the boolean value
1409 *
1410 * Create a new xmlXPathObjectPtr of type boolean and of value @val
1411 *
1412 * Returns the newly created object.
1413 */
1414xmlXPathObjectPtr
1415xmlXPathNewBoolean(int val) {
1416 xmlXPathObjectPtr ret;
1417
Daniel Veillard6454aec1999-09-02 22:04:43 +00001418 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001419 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001420 xmlGenericError(xmlGenericErrorContext,
1421 "xmlXPathNewBoolean: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001422 return(NULL);
1423 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001424 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001425 ret->type = XPATH_BOOLEAN;
1426 ret->boolval = (val != 0);
1427 return(ret);
1428}
1429
1430/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001431 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001432 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001433 *
1434 * Create a new xmlXPathObjectPtr of type string and of value @val
1435 *
1436 * Returns the newly created object.
1437 */
1438xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001439xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001440 xmlXPathObjectPtr ret;
1441
Daniel Veillard6454aec1999-09-02 22:04:43 +00001442 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001443 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001444 xmlGenericError(xmlGenericErrorContext,
1445 "xmlXPathNewString: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001446 return(NULL);
1447 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001448 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001449 ret->type = XPATH_STRING;
Daniel Veillard5a2b6972001-01-20 21:15:50 +00001450 if (val != NULL)
1451 ret->stringval = xmlStrdup(val);
1452 else
1453 ret->stringval = xmlStrdup((const xmlChar *)"");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001454 return(ret);
1455}
1456
1457/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00001458 * xmlXPathNewCString:
1459 * @val: the char * value
1460 *
1461 * Create a new xmlXPathObjectPtr of type string and of value @val
1462 *
1463 * Returns the newly created object.
1464 */
1465xmlXPathObjectPtr
1466xmlXPathNewCString(const char *val) {
1467 xmlXPathObjectPtr ret;
1468
Daniel Veillard6454aec1999-09-02 22:04:43 +00001469 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +00001470 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001471 xmlGenericError(xmlGenericErrorContext,
1472 "xmlXPathNewCString: out of memory\n");
Daniel Veillardb96e6431999-08-29 21:02:19 +00001473 return(NULL);
1474 }
1475 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1476 ret->type = XPATH_STRING;
1477 ret->stringval = xmlStrdup(BAD_CAST val);
1478 return(ret);
1479}
1480
1481/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00001482 * xmlXPathObjectCopy:
1483 * @val: the original object
1484 *
1485 * allocate a new copy of a given object
1486 *
1487 * Returns the newly created object.
1488 */
1489xmlXPathObjectPtr
1490xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1491 xmlXPathObjectPtr ret;
1492
1493 if (val == NULL)
1494 return(NULL);
1495
1496 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1497 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001498 xmlGenericError(xmlGenericErrorContext,
1499 "xmlXPathObjectCopy: out of memory\n");
Daniel Veillard2d38f042000-10-11 10:54:10 +00001500 return(NULL);
1501 }
1502 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1503 switch (val->type) {
1504 case XPATH_BOOLEAN:
1505 case XPATH_NUMBER:
Daniel Veillard2d38f042000-10-11 10:54:10 +00001506 case XPATH_POINT:
1507 case XPATH_RANGE:
1508 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00001509 case XPATH_STRING:
1510 ret->stringval = xmlStrdup(val->stringval);
Daniel Veillarde99a4762001-02-01 04:34:35 +00001511 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00001512 case XPATH_XSLT_TREE:
Daniel Veillard8a7642f2001-01-22 10:45:16 +00001513 if ((val->nodesetval != NULL) &&
1514 (val->nodesetval->nodeTab != NULL))
1515 ret->nodesetval = xmlXPathNodeSetCreate(
1516 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
1517 else
1518 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
1519 break;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001520 case XPATH_NODESET:
1521 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1522 break;
1523 case XPATH_LOCATIONSET:
1524#ifdef LIBXML_XPTR_ENABLED
1525 {
1526 xmlLocationSetPtr loc = val->user;
1527 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1528 break;
1529 }
1530#endif
1531 case XPATH_UNDEFINED:
1532 case XPATH_USERS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001533 xmlGenericError(xmlGenericErrorContext,
1534 "xmlXPathObjectCopy: unsupported type %d\n",
Daniel Veillard2d38f042000-10-11 10:54:10 +00001535 val->type);
Daniel Veillarde4566462001-01-22 09:58:39 +00001536 break;
Daniel Veillard2d38f042000-10-11 10:54:10 +00001537 }
1538 return(ret);
1539}
1540
1541/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001542 * xmlXPathFreeObject:
1543 * @obj: the object to free
1544 *
1545 * Free up an xmlXPathObjectPtr object.
1546 */
1547void
1548xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1549 if (obj == NULL) return;
Daniel Veillardac260302000-10-04 13:33:43 +00001550 if (obj->type == XPATH_NODESET) {
1551 if (obj->nodesetval != NULL)
1552 xmlXPathFreeNodeSet(obj->nodesetval);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001553#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard7e99c632000-10-06 12:59:53 +00001554 } else if (obj->type == XPATH_LOCATIONSET) {
1555 if (obj->user != NULL)
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00001556 xmlXPtrFreeLocationSet(obj->user);
Daniel Veillardb71379b2000-10-09 12:30:39 +00001557#endif
Daniel Veillardac260302000-10-04 13:33:43 +00001558 } else if (obj->type == XPATH_STRING) {
1559 if (obj->stringval != NULL)
1560 xmlFree(obj->stringval);
Daniel Veillarde4566462001-01-22 09:58:39 +00001561 } else if (obj->type == XPATH_XSLT_TREE) {
1562 if (obj->nodesetval != NULL)
Daniel Veillard8a7642f2001-01-22 10:45:16 +00001563 xmlXPathFreeValueTree(obj->nodesetval);
Daniel Veillardac260302000-10-04 13:33:43 +00001564 }
1565
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001566#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001567 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001568#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001569 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001570}
1571
1572/************************************************************************
1573 * *
1574 * Routines to handle XPath contexts *
1575 * *
1576 ************************************************************************/
1577
1578/**
1579 * xmlXPathNewContext:
1580 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001581 *
1582 * Create a new xmlXPathContext
1583 *
1584 * Returns the xmlXPathContext just allocated.
1585 */
1586xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001587xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001588 xmlXPathContextPtr ret;
1589
Daniel Veillard6454aec1999-09-02 22:04:43 +00001590 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001591 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001592 xmlGenericError(xmlGenericErrorContext,
1593 "xmlXPathNewContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001594 return(NULL);
1595 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001596 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001597 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001598 ret->node = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001599
Daniel Veillard126f2792000-10-24 17:10:12 +00001600 ret->varHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001601
1602 ret->nb_types = 0;
1603 ret->max_types = 0;
1604 ret->types = NULL;
1605
Daniel Veillard52afe802000-10-22 16:56:02 +00001606 ret->funcHash = xmlHashCreate(0);
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001607
1608 ret->nb_axis = 0;
1609 ret->max_axis = 0;
1610 ret->axis = NULL;
1611
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001612 ret->nsHash = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +00001613 ret->user = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00001614
1615 ret->contextSize = -1;
1616 ret->proximityPosition = -1;
Daniel Veillard52afe802000-10-22 16:56:02 +00001617
1618 xmlXPathRegisterAllFunctions(ret);
1619
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001620 return(ret);
1621}
1622
1623/**
1624 * xmlXPathFreeContext:
1625 * @ctxt: the context to free
1626 *
1627 * Free up an xmlXPathContext
1628 */
1629void
1630xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00001631 xmlXPathRegisteredNsCleanup(ctxt);
Daniel Veillard2d38f042000-10-11 10:54:10 +00001632 xmlXPathRegisteredFuncsCleanup(ctxt);
1633 xmlXPathRegisteredVariablesCleanup(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001634#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001635 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001636#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001637 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001638}
1639
1640/************************************************************************
1641 * *
1642 * Routines to handle XPath parser contexts *
1643 * *
1644 ************************************************************************/
1645
Daniel Veillard740abf52000-10-02 23:04:54 +00001646#define CHECK_CTXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001647 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001648 xmlGenericError(xmlGenericErrorContext, \
1649 "%s:%d Internal error: ctxt == NULL\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001650 __FILE__, __LINE__); \
1651 } \
1652
1653
Daniel Veillard740abf52000-10-02 23:04:54 +00001654#define CHECK_CONTEXT(ctxt) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001655 if (ctxt == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001656 xmlGenericError(xmlGenericErrorContext, \
1657 "%s:%d Internal error: no context\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001658 __FILE__, __LINE__); \
1659 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001660 else if (ctxt->doc == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001661 xmlGenericError(xmlGenericErrorContext, \
1662 "%s:%d Internal error: no document\n", \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001663 __FILE__, __LINE__); \
1664 } \
Daniel Veillarddf7ef2a2000-10-25 10:11:55 +00001665 else if (ctxt->doc->children == NULL) { \
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001666 xmlGenericError(xmlGenericErrorContext, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001667 "%s:%d Internal error: document without root\n", \
1668 __FILE__, __LINE__); \
1669 } \
1670
1671
1672/**
1673 * xmlXPathNewParserContext:
1674 * @str: the XPath expression
1675 * @ctxt: the XPath context
1676 *
1677 * Create a new xmlXPathParserContext
1678 *
1679 * Returns the xmlXPathParserContext just allocated.
1680 */
1681xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001682xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001683 xmlXPathParserContextPtr ret;
1684
Daniel Veillard6454aec1999-09-02 22:04:43 +00001685 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001686 if (ret == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00001687 xmlGenericError(xmlGenericErrorContext,
1688 "xmlXPathNewParserContext: out of memory\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001689 return(NULL);
1690 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001691 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001692 ret->cur = ret->base = str;
1693 ret->context = ctxt;
1694
1695 /* Allocate the value stack */
1696 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001697 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001698 ret->valueNr = 0;
1699 ret->valueMax = 10;
1700 ret->value = NULL;
1701 return(ret);
1702}
1703
1704/**
1705 * xmlXPathFreeParserContext:
1706 * @ctxt: the context to free
1707 *
1708 * Free up an xmlXPathParserContext
1709 */
1710void
1711xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1712 if (ctxt->valueTab != NULL) {
1713#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001714 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001715#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001716 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001717 }
1718#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001719 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001720#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00001721 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001722}
1723
1724/************************************************************************
1725 * *
1726 * The implicit core function library *
1727 * *
1728 ************************************************************************/
1729
1730/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001731 * Auto-pop and cast to a number
1732 */
1733void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1734
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001735
1736#define POP_FLOAT \
1737 arg = valuePop(ctxt); \
1738 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001739 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001740 } \
1741 if (arg->type != XPATH_NUMBER) { \
1742 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001743 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001744 arg = valuePop(ctxt); \
1745 }
1746
1747/**
Daniel Veillard389e6b72001-01-15 19:41:13 +00001748 * xmlXPathCompareNodeSetFloat:
1749 * @ctxt: the XPath Parser context
1750 * @inf: less than (1) or greater than (0)
1751 * @strict: is the comparison strict
1752 * @arg: the node set
1753 * @f: the value
1754 *
1755 * Implement the compare operation between a nodeset and a number
1756 * @ns < @val (1, 1, ...
1757 * @ns <= @val (1, 0, ...
1758 * @ns > @val (0, 1, ...
1759 * @ns >= @val (0, 0, ...
1760 *
1761 * If one object to be compared is a node-set and the other is a number,
1762 * then the comparison will be true if and only if there is a node in the
1763 * node-set such that the result of performing the comparison on the number
1764 * to be compared and on the result of converting the string-value of that
1765 * node to a number using the number function is true.
1766 *
1767 * Returns 0 or 1 depending on the results of the test.
1768 */
1769int
1770xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
1771 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
1772 int i, ret = 0;
1773 xmlNodeSetPtr ns;
1774 xmlChar *str2;
1775
Daniel Veillarde99a4762001-02-01 04:34:35 +00001776 if ((f == NULL) || (arg == NULL) ||
1777 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00001778 xmlXPathFreeObject(arg);
1779 xmlXPathFreeObject(f);
1780 return(0);
1781 }
1782 ns = arg->nodesetval;
1783 for (i = 0;i < ns->nodeNr;i++) {
1784 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1785 if (str2 != NULL) {
1786 valuePush(ctxt,
1787 xmlXPathNewString(str2));
1788 xmlFree(str2);
1789 xmlXPathNumberFunction(ctxt, 1);
1790 valuePush(ctxt, xmlXPathObjectCopy(f));
1791 ret = xmlXPathCompareValues(ctxt, inf, strict);
1792 if (ret)
1793 break;
1794 }
1795 }
1796 xmlXPathFreeObject(arg);
1797 xmlXPathFreeObject(f);
1798 return(ret);
1799}
1800
1801/**
1802 * xmlXPathCompareNodeSetString:
1803 * @ctxt: the XPath Parser context
1804 * @inf: less than (1) or greater than (0)
1805 * @strict: is the comparison strict
1806 * @arg: the node set
1807 * @s: the value
1808 *
1809 * Implement the compare operation between a nodeset and a string
1810 * @ns < @val (1, 1, ...
1811 * @ns <= @val (1, 0, ...
1812 * @ns > @val (0, 1, ...
1813 * @ns >= @val (0, 0, ...
1814 *
1815 * If one object to be compared is a node-set and the other is a string,
1816 * then the comparison will be true if and only if there is a node in
1817 * the node-set such that the result of performing the comparison on the
1818 * string-value of the node and the other string is true.
1819 *
1820 * Returns 0 or 1 depending on the results of the test.
1821 */
1822int
1823xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
1824 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
1825 int i, ret = 0;
1826 xmlNodeSetPtr ns;
1827 xmlChar *str2;
1828
Daniel Veillarde99a4762001-02-01 04:34:35 +00001829 if ((s == NULL) || (arg == NULL) ||
1830 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
Daniel Veillard389e6b72001-01-15 19:41:13 +00001831 xmlXPathFreeObject(arg);
1832 xmlXPathFreeObject(s);
1833 return(0);
1834 }
1835 ns = arg->nodesetval;
1836 for (i = 0;i < ns->nodeNr;i++) {
1837 str2 = xmlNodeGetContent(ns->nodeTab[i]);
1838 if (str2 != NULL) {
1839 valuePush(ctxt,
1840 xmlXPathNewString(str2));
1841 xmlFree(str2);
1842 valuePush(ctxt, xmlXPathObjectCopy(s));
1843 ret = xmlXPathCompareValues(ctxt, inf, strict);
1844 if (ret)
1845 break;
1846 }
1847 }
1848 xmlXPathFreeObject(arg);
1849 xmlXPathFreeObject(s);
1850 return(ret);
1851}
1852
1853/**
1854 * xmlXPathCompareNodeSets:
1855 * @ctxt: the XPath Parser context
1856 * @op: less than (-1), equal (0) or greater than (1)
1857 * @strict: is the comparison strict
1858 * @ns1: the fist node set
1859 * @ns2: the second node set
1860 *
1861 * Implement the compare operation on nodesets:
1862 *
1863 * If both objects to be compared are node-sets, then the comparison will be true if
1864 * and only if there is a node in the first node-set and a node in the second node-set
1865 * such that the result of performing the comparison on the string-values of the two
1866 * nodes is true.
1867 */
1868int
1869xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
1870 xmlXPathObjectPtr ns1, xmlXPathObjectPtr ns2) {
1871 TODO
1872 return(0);
1873}
1874
1875/**
1876 * xmlXPathCompareNodeSetValue:
1877 * @ctxt: the XPath Parser context
1878 * @inf: less than (1) or greater than (0)
1879 * @strict: is the comparison strict
1880 * @arg: the node set
1881 * @val: the value
1882 *
1883 * Implement the compare operation between a nodeset and a value
1884 * @ns < @val (1, 1, ...
1885 * @ns <= @val (1, 0, ...
1886 * @ns > @val (0, 1, ...
1887 * @ns >= @val (0, 0, ...
1888 *
1889 * If one object to be compared is a node-set and the other is a boolean, then the
1890 * comparison will be true if and only if the result of performing the comparison
1891 * on the boolean and on the result of converting the node-set to a boolean using
1892 * the boolean function is true.
1893 *
1894 * Returns 0 or 1 depending on the results of the test.
1895 */
1896int
1897xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
1898 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
Daniel Veillarde99a4762001-02-01 04:34:35 +00001899 if ((val == NULL) || (arg == NULL) ||
1900 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard389e6b72001-01-15 19:41:13 +00001901 return(0);
1902
1903 switch(val->type) {
1904 case XPATH_NUMBER:
1905 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
1906 case XPATH_NODESET:
Daniel Veillarde99a4762001-02-01 04:34:35 +00001907 case XPATH_XSLT_TREE:
Daniel Veillard389e6b72001-01-15 19:41:13 +00001908 return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
1909 case XPATH_STRING:
1910 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
1911 case XPATH_BOOLEAN:
1912 valuePush(ctxt, arg);
1913 xmlXPathBooleanFunction(ctxt, 1);
1914 valuePush(ctxt, val);
1915 return(xmlXPathCompareValues(ctxt, inf, strict));
1916 default:
1917 TODO
1918 return(0);
1919 }
1920 return(0);
1921}
1922
1923/**
Daniel Veillard991e63d1999-08-15 23:32:28 +00001924 * xmlXPathEqualNodeSetString
1925 * @arg: the nodeset object argument
1926 * @str: the string to compare to.
1927 *
1928 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1929 * If one object to be compared is a node-set and the other is a string,
1930 * then the comparison will be true if and only if there is a node in
1931 * the node-set such that the result of performing the comparison on the
1932 * string-value of the node and the other string is true.
1933 *
1934 * Returns 0 or 1 depending on the results of the test.
1935 */
1936int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001937xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001938 int i;
1939 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001940 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001941
Daniel Veillarde99a4762001-02-01 04:34:35 +00001942 if ((str == NULL) || (arg == NULL) ||
1943 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001944 return(0);
1945 ns = arg->nodesetval;
1946 for (i = 0;i < ns->nodeNr;i++) {
1947 str2 = xmlNodeGetContent(ns->nodeTab[i]);
Daniel Veillard8b5dd832000-10-01 20:28:44 +00001948 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001949 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001950 return(1);
1951 }
Daniel Veillard5dd2f0a2001-02-12 17:36:05 +00001952 if (str2 != NULL)
1953 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001954 }
1955 return(0);
1956}
1957
1958/**
1959 * xmlXPathEqualNodeSetFloat
1960 * @arg: the nodeset object argument
1961 * @f: the float to compare to
1962 *
1963 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1964 * If one object to be compared is a node-set and the other is a number,
1965 * then the comparison will be true if and only if there is a node in
1966 * the node-set such that the result of performing the comparison on the
1967 * number to be compared and on the result of converting the string-value
1968 * of that node to a number using the number function is true.
1969 *
1970 * Returns 0 or 1 depending on the results of the test.
1971 */
1972int
Daniel Veillardf23e0092001-02-16 13:21:29 +00001973xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001974 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001975
Daniel Veillarde99a4762001-02-01 04:34:35 +00001976 if ((arg == NULL) ||
1977 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00001978 return(0);
1979
1980 if (isnan(f))
1981 sprintf(buf, "NaN");
1982 else if (isinf(f) > 0)
1983 sprintf(buf, "+Infinity");
1984 else if (isinf(f) < 0)
1985 sprintf(buf, "-Infinity");
1986 else
1987 sprintf(buf, "%0g", f);
1988
Daniel Veillardb96e6431999-08-29 21:02:19 +00001989 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001990}
1991
1992
1993/**
1994 * xmlXPathEqualNodeSets
1995 * @arg1: first nodeset object argument
1996 * @arg2: second nodeset object argument
1997 *
1998 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1999 * If both objects to be compared are node-sets, then the comparison
2000 * will be true if and only if there is a node in the first node-set and
2001 * a node in the second node-set such that the result of performing the
2002 * comparison on the string-values of the two nodes is true.
2003 *
2004 * (needless to say, this is a costly operation)
2005 *
2006 * Returns 0 or 1 depending on the results of the test.
2007 */
2008int
2009xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
2010 int i;
2011 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002012 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002013
Daniel Veillarde99a4762001-02-01 04:34:35 +00002014 if ((arg1 == NULL) ||
2015 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00002016 return(0);
Daniel Veillarde99a4762001-02-01 04:34:35 +00002017 if ((arg2 == NULL) ||
2018 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
Daniel Veillard991e63d1999-08-15 23:32:28 +00002019 return(0);
2020
2021 ns = arg1->nodesetval;
2022 for (i = 0;i < ns->nodeNr;i++) {
2023 str = xmlNodeGetContent(ns->nodeTab[i]);
2024 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00002025 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002026 return(1);
2027 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00002028 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002029 }
2030 return(0);
2031}
2032
2033/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002034 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002035 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002036 *
2037 * Implement the equal operation on XPath objects content: @arg1 == @arg2
2038 *
2039 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002040 */
2041int
Daniel Veillard991e63d1999-08-15 23:32:28 +00002042xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
2043 xmlXPathObjectPtr arg1, arg2;
2044 int ret = 0;
2045
2046 arg1 = valuePop(ctxt);
2047 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002048 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002049
2050 arg2 = valuePop(ctxt);
2051 if (arg2 == NULL) {
2052 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002053 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002054 }
2055
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002056 if (arg1 == arg2) {
2057#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002058 xmlGenericError(xmlGenericErrorContext,
2059 "Equal: by pointer\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002060#endif
2061 return(1);
2062 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00002063
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002064 switch (arg1->type) {
2065 case XPATH_UNDEFINED:
2066#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002067 xmlGenericError(xmlGenericErrorContext,
2068 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002069#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00002070 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00002071 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002072 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002073 switch (arg2->type) {
2074 case XPATH_UNDEFINED:
2075#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002076 xmlGenericError(xmlGenericErrorContext,
2077 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00002078#endif
2079 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00002080 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002081 case XPATH_NODESET:
2082 ret = xmlXPathEqualNodeSets(arg1, arg2);
2083 break;
2084 case XPATH_BOOLEAN:
2085 if ((arg1->nodesetval == NULL) ||
2086 (arg1->nodesetval->nodeNr == 0)) ret = 0;
2087 else
2088 ret = 1;
2089 ret = (ret == arg2->boolval);
2090 break;
2091 case XPATH_NUMBER:
2092 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
2093 break;
2094 case XPATH_STRING:
2095 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
2096 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002097 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002098 case XPATH_POINT:
2099 case XPATH_RANGE:
2100 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002101 TODO
2102 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002103 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002104 break;
2105 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002106 switch (arg2->type) {
2107 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002108#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002109 xmlGenericError(xmlGenericErrorContext,
2110 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002111#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00002112 break;
2113 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002114 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002115 if ((arg2->nodesetval == NULL) ||
2116 (arg2->nodesetval->nodeNr == 0)) ret = 0;
2117 else
2118 ret = 1;
2119 break;
2120 case XPATH_BOOLEAN:
2121#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002122 xmlGenericError(xmlGenericErrorContext,
2123 "Equal: %d boolean %d \n",
Daniel Veillard991e63d1999-08-15 23:32:28 +00002124 arg1->boolval, arg2->boolval);
2125#endif
2126 ret = (arg1->boolval == arg2->boolval);
2127 break;
2128 case XPATH_NUMBER:
2129 if (arg2->floatval) ret = 1;
2130 else ret = 0;
2131 ret = (arg1->boolval == ret);
2132 break;
2133 case XPATH_STRING:
2134 if ((arg2->stringval == NULL) ||
2135 (arg2->stringval[0] == 0)) ret = 0;
2136 else
2137 ret = 1;
2138 ret = (arg1->boolval == ret);
2139 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002140 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002141 case XPATH_POINT:
2142 case XPATH_RANGE:
2143 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002144 TODO
2145 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002146 }
2147 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002148 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002149 switch (arg2->type) {
2150 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002151#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002152 xmlGenericError(xmlGenericErrorContext,
2153 "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002154#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00002155 break;
2156 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002157 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002158 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
2159 break;
2160 case XPATH_BOOLEAN:
2161 if (arg1->floatval) ret = 1;
2162 else ret = 0;
2163 ret = (arg2->boolval == ret);
2164 break;
2165 case XPATH_STRING:
2166 valuePush(ctxt, arg2);
2167 xmlXPathNumberFunction(ctxt, 1);
2168 arg2 = valuePop(ctxt);
2169 /* no break on purpose */
2170 case XPATH_NUMBER:
2171 ret = (arg1->floatval == arg2->floatval);
2172 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002173 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002174 case XPATH_POINT:
2175 case XPATH_RANGE:
2176 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002177 TODO
2178 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002179 }
2180 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002181 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002182 switch (arg2->type) {
2183 case XPATH_UNDEFINED:
2184#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00002185 xmlGenericError(xmlGenericErrorContext,
2186 "Equal: undefined\n");
Daniel Veillard991e63d1999-08-15 23:32:28 +00002187#endif
2188 break;
2189 case XPATH_NODESET:
Daniel Veillarde4566462001-01-22 09:58:39 +00002190 case XPATH_XSLT_TREE:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002191 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
2192 break;
2193 case XPATH_BOOLEAN:
2194 if ((arg1->stringval == NULL) ||
2195 (arg1->stringval[0] == 0)) ret = 0;
2196 else
2197 ret = 1;
2198 ret = (arg2->boolval == ret);
2199 break;
2200 case XPATH_STRING:
Daniel Veillard8b5dd832000-10-01 20:28:44 +00002201 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002202 break;
2203 case XPATH_NUMBER:
2204 valuePush(ctxt, arg1);
2205 xmlXPathNumberFunction(ctxt, 1);
2206 arg1 = valuePop(ctxt);
2207 ret = (arg1->floatval == arg2->floatval);
2208 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002209 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002210 case XPATH_POINT:
2211 case XPATH_RANGE:
2212 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002213 TODO
2214 break;
Daniel Veillard991e63d1999-08-15 23:32:28 +00002215 }
2216 break;
Daniel Veillard740abf52000-10-02 23:04:54 +00002217 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00002218 case XPATH_POINT:
2219 case XPATH_RANGE:
2220 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00002221 TODO
2222 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002223 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00002224 xmlXPathFreeObject(arg1);
2225 xmlXPathFreeObject(arg2);
2226 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002227}
2228
Daniel Veillard389e6b72001-01-15 19:41:13 +00002229
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002230/**
2231 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00002232 * @ctxt: the XPath Parser context
Daniel Veillard389e6b72001-01-15 19:41:13 +00002233 * @inf: less than (1) or greater than (0)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002234 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002235 *
2236 * Implement the compare operation on XPath objects:
2237 * @arg1 < @arg2 (1, 1, ...
2238 * @arg1 <= @arg2 (1, 0, ...
2239 * @arg1 > @arg2 (0, 1, ...
2240 * @arg1 >= @arg2 (0, 0, ...
2241 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00002242 * When neither object to be compared is a node-set and the operator is
2243 * <=, <, >=, >, then the objects are compared by converted both objects
2244 * to numbers and comparing the numbers according to IEEE 754. The <
2245 * comparison will be true if and only if the first number is less than the
2246 * second number. The <= comparison will be true if and only if the first
2247 * number is less than or equal to the second number. The > comparison
2248 * will be true if and only if the first number is greater than the second
2249 * number. The >= comparison will be true if and only if the first number
2250 * is greater than or equal to the second number.
Daniel Veillard389e6b72001-01-15 19:41:13 +00002251 *
2252 * Returns 1 if the comparaison succeeded, 0 if it failed
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002253 */
2254int
Daniel Veillard991e63d1999-08-15 23:32:28 +00002255xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
2256 int ret = 0;
2257 xmlXPathObjectPtr arg1, arg2;
2258
2259 arg2 = valuePop(ctxt);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002260 if (arg2 == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002261 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002262 }
2263
2264 arg1 = valuePop(ctxt);
Daniel Veillard389e6b72001-01-15 19:41:13 +00002265 if (arg1 == NULL) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00002266 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002267 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002268 }
2269
Daniel Veillard389e6b72001-01-15 19:41:13 +00002270 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
2271 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
2272 ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
2273 } else {
2274 if (arg1->type == XPATH_NODESET) {
2275 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, arg1, arg2);
2276 } else {
2277 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, !strict, arg2, arg2);
2278 }
2279 }
2280 return(ret);
2281 }
2282
Daniel Veillard991e63d1999-08-15 23:32:28 +00002283 if (arg1->type != XPATH_NUMBER) {
2284 valuePush(ctxt, arg1);
2285 xmlXPathNumberFunction(ctxt, 1);
2286 arg1 = valuePop(ctxt);
2287 }
2288 if (arg1->type != XPATH_NUMBER) {
2289 xmlXPathFreeObject(arg1);
2290 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002291 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002292 }
2293 if (arg2->type != XPATH_NUMBER) {
2294 valuePush(ctxt, arg2);
2295 xmlXPathNumberFunction(ctxt, 1);
2296 arg2 = valuePop(ctxt);
2297 }
2298 if (arg2->type != XPATH_NUMBER) {
2299 xmlXPathFreeObject(arg1);
2300 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002301 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002302 }
2303 /*
2304 * Add tests for infinity and nan
2305 * => feedback on 3.4 for Inf and NaN
2306 */
2307 if (inf && strict)
2308 ret = (arg1->floatval < arg2->floatval);
2309 else if (inf && !strict)
2310 ret = (arg1->floatval <= arg2->floatval);
2311 else if (!inf && strict)
2312 ret = (arg1->floatval > arg2->floatval);
2313 else if (!inf && !strict)
2314 ret = (arg1->floatval >= arg2->floatval);
2315 xmlXPathFreeObject(arg1);
2316 xmlXPathFreeObject(arg2);
2317 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002318}
2319
2320/**
2321 * xmlXPathValueFlipSign:
2322 * @ctxt: the XPath Parser context
2323 *
2324 * Implement the unary - operation on an XPath object
2325 * The numeric operators convert their operands to numbers as if
2326 * by calling the number function.
2327 */
2328void
2329xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
2330 xmlXPathObjectPtr arg;
2331
2332 POP_FLOAT
2333 arg->floatval = -arg->floatval;
2334 valuePush(ctxt, arg);
2335}
2336
2337/**
2338 * xmlXPathAddValues:
2339 * @ctxt: the XPath Parser context
2340 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002341 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002342 * The numeric operators convert their operands to numbers as if
2343 * by calling the number function.
2344 */
2345void
2346xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
2347 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002348 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002349
2350 POP_FLOAT
2351 val = arg->floatval;
2352 xmlXPathFreeObject(arg);
2353
2354 POP_FLOAT
2355 arg->floatval += val;
2356 valuePush(ctxt, arg);
2357}
2358
2359/**
2360 * xmlXPathSubValues:
2361 * @ctxt: the XPath Parser context
2362 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002363 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002364 * The numeric operators convert their operands to numbers as if
2365 * by calling the number function.
2366 */
2367void
2368xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
2369 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002370 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002371
2372 POP_FLOAT
2373 val = arg->floatval;
2374 xmlXPathFreeObject(arg);
2375
2376 POP_FLOAT
2377 arg->floatval -= val;
2378 valuePush(ctxt, arg);
2379}
2380
2381/**
2382 * xmlXPathMultValues:
2383 * @ctxt: the XPath Parser context
2384 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002385 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002386 * The numeric operators convert their operands to numbers as if
2387 * by calling the number function.
2388 */
2389void
2390xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
2391 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002392 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002393
2394 POP_FLOAT
2395 val = arg->floatval;
2396 xmlXPathFreeObject(arg);
2397
2398 POP_FLOAT
2399 arg->floatval *= val;
2400 valuePush(ctxt, arg);
2401}
2402
2403/**
2404 * xmlXPathDivValues:
2405 * @ctxt: the XPath Parser context
2406 *
Daniel Veillard2b325a02001-01-31 20:46:31 +00002407 * Implement the div operation on XPath objects @arg1 / @arg2:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002408 * The numeric operators convert their operands to numbers as if
2409 * by calling the number function.
2410 */
2411void
2412xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
2413 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002414 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002415
2416 POP_FLOAT
2417 val = arg->floatval;
2418 xmlXPathFreeObject(arg);
2419
2420 POP_FLOAT
2421 arg->floatval /= val;
2422 valuePush(ctxt, arg);
2423}
2424
2425/**
2426 * xmlXPathModValues:
2427 * @ctxt: the XPath Parser context
2428 *
Daniel Veillard2b325a02001-01-31 20:46:31 +00002429 * Implement the mod operation on XPath objects: @arg1 / @arg2
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002430 * The numeric operators convert their operands to numbers as if
2431 * by calling the number function.
2432 */
2433void
2434xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
2435 xmlXPathObjectPtr arg;
Daniel Veillard2b325a02001-01-31 20:46:31 +00002436 int arg1, arg2;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002437
2438 POP_FLOAT
Daniel Veillard2b325a02001-01-31 20:46:31 +00002439 arg2 = (int) arg->floatval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002440 xmlXPathFreeObject(arg);
2441
2442 POP_FLOAT
Daniel Veillard2b325a02001-01-31 20:46:31 +00002443 arg1 = (int) arg->floatval;
2444 arg->floatval = arg1 % arg2;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002445 valuePush(ctxt, arg);
2446}
2447
2448/************************************************************************
2449 * *
2450 * The traversal functions *
2451 * *
2452 ************************************************************************/
2453
Daniel Veillard740abf52000-10-02 23:04:54 +00002454typedef enum {
2455 AXIS_ANCESTOR = 1,
2456 AXIS_ANCESTOR_OR_SELF,
2457 AXIS_ATTRIBUTE,
2458 AXIS_CHILD,
2459 AXIS_DESCENDANT,
2460 AXIS_DESCENDANT_OR_SELF,
2461 AXIS_FOLLOWING,
2462 AXIS_FOLLOWING_SIBLING,
2463 AXIS_NAMESPACE,
2464 AXIS_PARENT,
2465 AXIS_PRECEDING,
2466 AXIS_PRECEDING_SIBLING,
2467 AXIS_SELF
2468} xmlXPathAxisVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002469
2470/*
2471 * A traversal function enumerates nodes along an axis.
2472 * Initially it must be called with NULL, and it indicates
2473 * termination on the axis by returning NULL.
2474 */
2475typedef xmlNodePtr (*xmlXPathTraversalFunction)
2476 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
2477
2478/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002479 * xmlXPathNextSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002480 * @ctxt: the XPath Parser context
2481 * @cur: the current node in the traversal
2482 *
2483 * Traversal function for the "self" direction
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002484 * The self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00002485 *
2486 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002487 */
2488xmlNodePtr
2489xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2490 if (cur == NULL)
2491 return(ctxt->context->node);
2492 return(NULL);
2493}
2494
2495/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002496 * xmlXPathNextChild:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002497 * @ctxt: the XPath Parser context
2498 * @cur: the current node in the traversal
2499 *
2500 * Traversal function for the "child" direction
2501 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002502 *
2503 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002504 */
2505xmlNodePtr
2506xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002507 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002508 if (ctxt->context->node == NULL) return(NULL);
2509 switch (ctxt->context->node->type) {
2510 case XML_ELEMENT_NODE:
2511 case XML_TEXT_NODE:
2512 case XML_CDATA_SECTION_NODE:
2513 case XML_ENTITY_REF_NODE:
2514 case XML_ENTITY_NODE:
2515 case XML_PI_NODE:
2516 case XML_COMMENT_NODE:
2517 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002518 case XML_DTD_NODE:
2519 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002520 case XML_DOCUMENT_NODE:
2521 case XML_DOCUMENT_TYPE_NODE:
2522 case XML_DOCUMENT_FRAG_NODE:
2523 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002524#ifdef LIBXML_SGML_ENABLED
2525 case XML_SGML_DOCUMENT_NODE:
2526#endif
Daniel Veillardcf461992000-03-14 18:30:20 +00002527 return(((xmlDocPtr) ctxt->context->node)->children);
2528 case XML_ELEMENT_DECL:
2529 case XML_ATTRIBUTE_DECL:
2530 case XML_ENTITY_DECL:
2531 case XML_ATTRIBUTE_NODE:
Daniel Veillarda4964b72000-10-31 18:23:44 +00002532 case XML_NAMESPACE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002533 case XML_XINCLUDE_START:
2534 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002535 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002536 }
2537 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002538 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002539 if ((cur->type == XML_DOCUMENT_NODE) ||
2540 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00002541 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002542 return(cur->next);
2543}
2544
2545/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002546 * xmlXPathNextDescendant:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002547 * @ctxt: the XPath Parser context
2548 * @cur: the current node in the traversal
2549 *
2550 * Traversal function for the "descendant" direction
2551 * the descendant axis contains the descendants of the context node in document
2552 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002553 *
2554 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002555 */
2556xmlNodePtr
2557xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00002558 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002559 if (ctxt->context->node == NULL)
2560 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002561 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2562 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002563 return(NULL);
2564
Daniel Veillardb05deb71999-08-10 19:04:08 +00002565 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00002566 return(ctxt->context->doc->children);
2567 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002568 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002569
Daniel Veillardbe803962000-06-28 23:40:59 +00002570 if (cur->children != NULL)
2571 {
2572 if (cur->children->type != XML_ENTITY_DECL)
2573 return(cur->children);
2574 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002575 if (cur->next != NULL) return(cur->next);
2576
2577 do {
2578 cur = cur->parent;
2579 if (cur == NULL) return(NULL);
2580 if (cur == ctxt->context->node) return(NULL);
2581 if (cur->next != NULL) {
2582 cur = cur->next;
2583 return(cur);
2584 }
2585 } while (cur != NULL);
2586 return(cur);
2587}
2588
2589/**
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002590 * xmlXPathNextDescendantOrSelf:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002591 * @ctxt: the XPath Parser context
2592 * @cur: the current node in the traversal
2593 *
2594 * Traversal function for the "descendant-or-self" direction
2595 * the descendant-or-self axis contains the context node and the descendants
2596 * of the context node in document order; thus the context node is the first
2597 * node on the axis, and the first child of the context node is the second node
2598 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002599 *
2600 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002601 */
2602xmlNodePtr
2603xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002604 if (cur == NULL) {
2605 if (ctxt->context->node == NULL)
2606 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002607 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2608 (ctxt->context->node->type == XML_NAMESPACE_DECL))
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002609 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002610 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002611 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002612
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002613 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002614}
2615
2616/**
2617 * xmlXPathNextParent:
2618 * @ctxt: the XPath Parser context
2619 * @cur: the current node in the traversal
2620 *
2621 * Traversal function for the "parent" direction
2622 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002623 *
2624 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002625 */
2626xmlNodePtr
2627xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2628 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002629 * the parent of an attribute or namespace node is the element
2630 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002631 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002632 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002633 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002634 if (ctxt->context->node == NULL) return(NULL);
2635 switch (ctxt->context->node->type) {
2636 case XML_ELEMENT_NODE:
2637 case XML_TEXT_NODE:
2638 case XML_CDATA_SECTION_NODE:
2639 case XML_ENTITY_REF_NODE:
2640 case XML_ENTITY_NODE:
2641 case XML_PI_NODE:
2642 case XML_COMMENT_NODE:
2643 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002644 case XML_DTD_NODE:
2645 case XML_ELEMENT_DECL:
2646 case XML_ATTRIBUTE_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002647 case XML_XINCLUDE_START:
2648 case XML_XINCLUDE_END:
Daniel Veillardcf461992000-03-14 18:30:20 +00002649 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002650 if (ctxt->context->node->parent == NULL)
2651 return((xmlNodePtr) ctxt->context->doc);
2652 return(ctxt->context->node->parent);
2653 case XML_ATTRIBUTE_NODE: {
2654 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2655
Daniel Veillardcf461992000-03-14 18:30:20 +00002656 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002657 }
2658 case XML_DOCUMENT_NODE:
2659 case XML_DOCUMENT_TYPE_NODE:
2660 case XML_DOCUMENT_FRAG_NODE:
2661 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002662#ifdef LIBXML_SGML_ENABLED
2663 case XML_SGML_DOCUMENT_NODE:
2664#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002665 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002666 case XML_NAMESPACE_DECL:
2667 /*
2668 * TODO !!! may require extending struct _xmlNs with
2669 * parent field
2670 * C.f. Infoset case...
2671 */
2672 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002673 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002674 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002675 return(NULL);
2676}
2677
2678/**
2679 * xmlXPathNextAncestor:
2680 * @ctxt: the XPath Parser context
2681 * @cur: the current node in the traversal
2682 *
2683 * Traversal function for the "ancestor" direction
2684 * the ancestor axis contains the ancestors of the context node; the ancestors
2685 * of the context node consist of the parent of context node and the parent's
2686 * parent and so on; the nodes are ordered in reverse document order; thus the
2687 * parent is the first node on the axis, and the parent's parent is the second
2688 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00002689 *
2690 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002691 */
2692xmlNodePtr
2693xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2694 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002695 * the parent of an attribute or namespace node is the element
2696 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002697 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002698 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00002699 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002700 if (ctxt->context->node == NULL) return(NULL);
2701 switch (ctxt->context->node->type) {
2702 case XML_ELEMENT_NODE:
2703 case XML_TEXT_NODE:
2704 case XML_CDATA_SECTION_NODE:
2705 case XML_ENTITY_REF_NODE:
2706 case XML_ENTITY_NODE:
2707 case XML_PI_NODE:
2708 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002709 case XML_DTD_NODE:
2710 case XML_ELEMENT_DECL:
2711 case XML_ATTRIBUTE_DECL:
2712 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002713 case XML_NOTATION_NODE:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002714 case XML_XINCLUDE_START:
2715 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002716 if (ctxt->context->node->parent == NULL)
2717 return((xmlNodePtr) ctxt->context->doc);
2718 return(ctxt->context->node->parent);
2719 case XML_ATTRIBUTE_NODE: {
2720 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2721
Daniel Veillardcf461992000-03-14 18:30:20 +00002722 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002723 }
2724 case XML_DOCUMENT_NODE:
2725 case XML_DOCUMENT_TYPE_NODE:
2726 case XML_DOCUMENT_FRAG_NODE:
2727 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002728#ifdef LIBXML_SGML_ENABLED
2729 case XML_SGML_DOCUMENT_NODE:
2730#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002731 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002732 case XML_NAMESPACE_DECL:
2733 /*
2734 * TODO !!! may require extending struct _xmlNs with
2735 * parent field
2736 * C.f. Infoset case...
2737 */
2738 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002739 }
2740 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002741 }
Daniel Veillardcf461992000-03-14 18:30:20 +00002742 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00002743 return((xmlNodePtr) ctxt->context->doc);
2744 if (cur == (xmlNodePtr) ctxt->context->doc)
2745 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002746 switch (cur->type) {
2747 case XML_ELEMENT_NODE:
2748 case XML_TEXT_NODE:
2749 case XML_CDATA_SECTION_NODE:
2750 case XML_ENTITY_REF_NODE:
2751 case XML_ENTITY_NODE:
2752 case XML_PI_NODE:
2753 case XML_COMMENT_NODE:
2754 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00002755 case XML_DTD_NODE:
2756 case XML_ELEMENT_DECL:
2757 case XML_ATTRIBUTE_DECL:
2758 case XML_ENTITY_DECL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002759 case XML_XINCLUDE_START:
2760 case XML_XINCLUDE_END:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002761 return(cur->parent);
2762 case XML_ATTRIBUTE_NODE: {
2763 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2764
Daniel Veillardcf461992000-03-14 18:30:20 +00002765 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002766 }
2767 case XML_DOCUMENT_NODE:
2768 case XML_DOCUMENT_TYPE_NODE:
2769 case XML_DOCUMENT_FRAG_NODE:
2770 case XML_HTML_DOCUMENT_NODE:
Daniel Veillard04698d92000-09-17 16:00:22 +00002771#ifdef LIBXML_SGML_ENABLED
2772 case XML_SGML_DOCUMENT_NODE:
2773#endif
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002774 return(NULL);
Daniel Veillarda4964b72000-10-31 18:23:44 +00002775 case XML_NAMESPACE_DECL:
2776 /*
2777 * TODO !!! may require extending struct _xmlNs with
2778 * parent field
2779 * C.f. Infoset case...
2780 */
2781 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002782 }
2783 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002784}
2785
2786/**
2787 * xmlXPathNextAncestorOrSelf:
2788 * @ctxt: the XPath Parser context
2789 * @cur: the current node in the traversal
2790 *
2791 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00002792 * he ancestor-or-self axis contains the context node and ancestors of
2793 * the context node in reverse document order; thus the context node is
2794 * the first node on the axis, and the context node's parent the second;
2795 * parent here is defined the same as with the parent axis.
2796 *
2797 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002798 */
2799xmlNodePtr
2800xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002801 if (cur == NULL)
2802 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00002803 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002804}
2805
2806/**
2807 * xmlXPathNextFollowingSibling:
2808 * @ctxt: the XPath Parser context
2809 * @cur: the current node in the traversal
2810 *
2811 * Traversal function for the "following-sibling" direction
2812 * The following-sibling axis contains the following siblings of the context
2813 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002814 *
2815 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002816 */
2817xmlNodePtr
2818xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002819 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2820 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2821 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002822 if (cur == (xmlNodePtr) ctxt->context->doc)
2823 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002824 if (cur == NULL)
2825 return(ctxt->context->node->next);
2826 return(cur->next);
2827}
2828
2829/**
2830 * xmlXPathNextPrecedingSibling:
2831 * @ctxt: the XPath Parser context
2832 * @cur: the current node in the traversal
2833 *
2834 * Traversal function for the "preceding-sibling" direction
2835 * The preceding-sibling axis contains the preceding siblings of the context
2836 * node in reverse document order; the first preceding sibling is first on the
2837 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00002838 *
2839 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002840 */
2841xmlNodePtr
2842xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002843 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
2844 (ctxt->context->node->type == XML_NAMESPACE_DECL))
2845 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002846 if (cur == (xmlNodePtr) ctxt->context->doc)
2847 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002848 if (cur == NULL)
2849 return(ctxt->context->node->prev);
2850 return(cur->prev);
2851}
2852
2853/**
2854 * xmlXPathNextFollowing:
2855 * @ctxt: the XPath Parser context
2856 * @cur: the current node in the traversal
2857 *
2858 * Traversal function for the "following" direction
2859 * The following axis contains all nodes in the same document as the context
2860 * node that are after the context node in document order, excluding any
2861 * descendants and excluding attribute nodes and namespace nodes; the nodes
2862 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00002863 *
2864 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002865 */
2866xmlNodePtr
2867xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard740abf52000-10-02 23:04:54 +00002868 if (cur != NULL && cur->children != NULL)
2869 return cur->children ;
Daniel Veillardac260302000-10-04 13:33:43 +00002870 if (cur == NULL) cur = ctxt->context->node;
2871 if (cur == NULL) return(NULL) ; /* ERROR */
2872 if (cur->next != NULL) return(cur->next) ;
Daniel Veillard740abf52000-10-02 23:04:54 +00002873 do {
2874 cur = cur->parent;
2875 if (cur == NULL) return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002876 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002877 if (cur->next != NULL) return(cur->next);
Daniel Veillard740abf52000-10-02 23:04:54 +00002878 } while (cur != NULL);
2879 return(cur);
2880}
2881
2882/*
Daniel Veillardac260302000-10-04 13:33:43 +00002883 * xmlXPathIsAncestor:
2884 * @ancestor: the ancestor node
2885 * @node: the current node
2886 *
2887 * Check that @ancestor is a @node's ancestor
2888 *
Daniel Veillard740abf52000-10-02 23:04:54 +00002889 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2890 */
2891static int
Daniel Veillardac260302000-10-04 13:33:43 +00002892xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002893 if ((ancestor == NULL) || (node == NULL)) return(0);
2894 /* nodes need to be in the same document */
2895 if (ancestor->doc != node->doc) return(0);
2896 /* avoid searching if ancestor or node is the root node */
2897 if (ancestor == (xmlNodePtr) node->doc) return(1);
2898 if (node == (xmlNodePtr) ancestor->doc) return(0);
2899 while (node->parent != NULL) {
2900 if (node->parent == ancestor)
2901 return(1);
2902 node = node->parent;
Daniel Veillard740abf52000-10-02 23:04:54 +00002903 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002904 return(0);
Daniel Veillard740abf52000-10-02 23:04:54 +00002905}
2906
2907/**
2908 * xmlXPathNextPreceding:
2909 * @ctxt: the XPath Parser context
2910 * @cur: the current node in the traversal
2911 *
2912 * Traversal function for the "preceding" direction
2913 * the preceding axis contains all nodes in the same document as the context
2914 * node that are before the context node in document order, excluding any
2915 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2916 * ordered in reverse document order
2917 *
2918 * Returns the next element following that axis
2919 */
2920xmlNodePtr
2921xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2922 if (cur == NULL)
2923 cur = ctxt->context->node ;
2924 do {
2925 if (cur->prev != NULL) {
2926 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2927 ;
2928 return(cur) ;
2929 }
2930
2931 cur = cur->parent;
2932 if (cur == NULL) return(NULL);
2933 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillardac260302000-10-04 13:33:43 +00002934 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
Daniel Veillard740abf52000-10-02 23:04:54 +00002935 return(cur);
2936}
2937
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002938/**
2939 * xmlXPathNextNamespace:
2940 * @ctxt: the XPath Parser context
2941 * @cur: the current attribute in the traversal
2942 *
2943 * Traversal function for the "namespace" direction
2944 * the namespace axis contains the namespace nodes of the context node;
2945 * the order of nodes on this axis is implementation-defined; the axis will
2946 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00002947 *
2948 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002949 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002950xmlNodePtr
2951xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2952 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002953 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2954 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002955 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002956 ctxt->context->namespaces =
2957 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2958 if (ctxt->context->namespaces == NULL) return(NULL);
2959 ctxt->context->nsNr = 0;
2960 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002961 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002962}
2963
2964/**
2965 * xmlXPathNextAttribute:
2966 * @ctxt: the XPath Parser context
2967 * @cur: the current attribute in the traversal
2968 *
2969 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00002970 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00002971 *
2972 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002973 */
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002974xmlNodePtr
2975xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2976 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002977 if (cur == NULL) {
2978 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2979 return(NULL);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002980 return((xmlNodePtr)ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00002981 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00002982 return((xmlNodePtr)cur->next);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002983}
2984
2985/************************************************************************
2986 * *
2987 * NodeTest Functions *
2988 * *
2989 ************************************************************************/
2990
Daniel Veillard740abf52000-10-02 23:04:54 +00002991typedef enum {
2992 NODE_TEST_NONE = 0,
2993 NODE_TEST_TYPE = 1,
2994 NODE_TEST_PI = 2,
2995 NODE_TEST_ALL = 3,
2996 NODE_TEST_NS = 4,
2997 NODE_TEST_NAME = 5
2998} xmlXPathTestVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002999
Daniel Veillard740abf52000-10-02 23:04:54 +00003000typedef enum {
Daniel Veillard2f913b72001-01-31 13:23:49 +00003001 NODE_TYPE_NODE = 0,
Daniel Veillard55b91f22000-10-05 16:30:11 +00003002 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
3003 NODE_TYPE_TEXT = XML_TEXT_NODE,
Daniel Veillard2f913b72001-01-31 13:23:49 +00003004 NODE_TYPE_PI = XML_PI_NODE
Daniel Veillard740abf52000-10-02 23:04:54 +00003005} xmlXPathTypeVal;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003006
3007#define IS_FUNCTION 200
3008
3009/**
3010 * xmlXPathNodeCollectAndTest:
3011 * @ctxt: the XPath Parser context
Daniel Veillard740abf52000-10-02 23:04:54 +00003012 * @axis: the XPath axis
3013 * @test: the XPath test
3014 * @type: the XPath type
3015 * @prefix: the namesapce prefix if any
3016 * @name: the name used in the search if any
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003017 *
3018 * This is the function implementing a step: based on the current list
3019 * of nodes, it builds up a new list, looking at all nodes under that
3020 * axis and selecting them.
3021 *
3022 * Returns the new NodeSet resulting from the search.
3023 */
Daniel Veillard740abf52000-10-02 23:04:54 +00003024void
3025xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
3026 xmlXPathTestVal test, xmlXPathTypeVal type,
3027 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003028#ifdef DEBUG_STEP
3029 int n = 0, t = 0;
3030#endif
3031 int i;
3032 xmlNodeSetPtr ret;
3033 xmlXPathTraversalFunction next = NULL;
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003034 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003035 xmlNodePtr cur = NULL;
Daniel Veillard740abf52000-10-02 23:04:54 +00003036 xmlXPathObjectPtr obj;
3037 xmlNodeSetPtr nodelist;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003038
Daniel Veillard740abf52000-10-02 23:04:54 +00003039 CHECK_TYPE(XPATH_NODESET);
3040 obj = valuePop(ctxt);
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003041 addNode = xmlXPathNodeSetAdd;
Daniel Veillard740abf52000-10-02 23:04:54 +00003042
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003043#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003044 xmlGenericError(xmlGenericErrorContext,
3045 "new step : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003046#endif
3047 switch (axis) {
3048 case AXIS_ANCESTOR:
3049#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003050 xmlGenericError(xmlGenericErrorContext,
3051 "axis 'ancestors' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003052#endif
3053 next = xmlXPathNextAncestor; break;
3054 case AXIS_ANCESTOR_OR_SELF:
3055#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003056 xmlGenericError(xmlGenericErrorContext,
3057 "axis 'ancestors-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003058#endif
3059 next = xmlXPathNextAncestorOrSelf; break;
3060 case AXIS_ATTRIBUTE:
3061#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003062 xmlGenericError(xmlGenericErrorContext,
3063 "axis 'attributes' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003064#endif
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003065 next = xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003066 break;
3067 case AXIS_CHILD:
3068#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003069 xmlGenericError(xmlGenericErrorContext,
3070 "axis 'child' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003071#endif
3072 next = xmlXPathNextChild; break;
3073 case AXIS_DESCENDANT:
3074#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003075 xmlGenericError(xmlGenericErrorContext,
3076 "axis 'descendant' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003077#endif
3078 next = xmlXPathNextDescendant; break;
3079 case AXIS_DESCENDANT_OR_SELF:
3080#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003081 xmlGenericError(xmlGenericErrorContext,
3082 "axis 'descendant-or-self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003083#endif
3084 next = xmlXPathNextDescendantOrSelf; break;
3085 case AXIS_FOLLOWING:
3086#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003087 xmlGenericError(xmlGenericErrorContext,
3088 "axis 'following' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003089#endif
3090 next = xmlXPathNextFollowing; break;
3091 case AXIS_FOLLOWING_SIBLING:
3092#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003093 xmlGenericError(xmlGenericErrorContext,
3094 "axis 'following-siblings' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003095#endif
3096 next = xmlXPathNextFollowingSibling; break;
3097 case AXIS_NAMESPACE:
3098#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003099 xmlGenericError(xmlGenericErrorContext,
3100 "axis 'namespace' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003101#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00003102 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003103 break;
3104 case AXIS_PARENT:
3105#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003106 xmlGenericError(xmlGenericErrorContext,
3107 "axis 'parent' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003108#endif
3109 next = xmlXPathNextParent; break;
3110 case AXIS_PRECEDING:
3111#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003112 xmlGenericError(xmlGenericErrorContext,
3113 "axis 'preceding' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003114#endif
3115 next = xmlXPathNextPreceding; break;
3116 case AXIS_PRECEDING_SIBLING:
3117#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003118 xmlGenericError(xmlGenericErrorContext,
3119 "axis 'preceding-sibling' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003120#endif
3121 next = xmlXPathNextPrecedingSibling; break;
3122 case AXIS_SELF:
3123#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003124 xmlGenericError(xmlGenericErrorContext,
3125 "axis 'self' ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003126#endif
3127 next = xmlXPathNextSelf; break;
3128 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003129 if (next == NULL)
3130 return;
3131
3132 nodelist = obj->nodesetval;
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003133 if ((nodelist != NULL) &&
3134 (nodelist->nodeNr <= 1))
3135 addNode = xmlXPathNodeSetAddUnique;
3136 else
3137 addNode = xmlXPathNodeSetAdd;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003138 ret = xmlXPathNodeSetCreate(NULL);
3139#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003140 xmlGenericError(xmlGenericErrorContext,
3141 " context contains %d nodes\n",
Daniel Veillard740abf52000-10-02 23:04:54 +00003142 nodelist->nodeNr);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003143 switch (test) {
Daniel Veillard2f913b72001-01-31 13:23:49 +00003144 case NODE_TEST_NODE:
3145 xmlGenericError(xmlGenericErrorContext,
3146 " searching all nodes\n");
3147 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003148 case NODE_TEST_NONE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003149 xmlGenericError(xmlGenericErrorContext,
3150 " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003151 break;
3152 case NODE_TEST_TYPE:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003153 xmlGenericError(xmlGenericErrorContext,
3154 " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003155 break;
3156 case NODE_TEST_PI:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003157 xmlGenericError(xmlGenericErrorContext,
3158 " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003159 break;
3160 case NODE_TEST_ALL:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003161 xmlGenericError(xmlGenericErrorContext,
3162 " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003163 break;
3164 case NODE_TEST_NS:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003165 xmlGenericError(xmlGenericErrorContext,
3166 " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003167 prefix);
3168 break;
3169 case NODE_TEST_NAME:
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003170 xmlGenericError(xmlGenericErrorContext,
3171 " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003172 if (prefix != NULL)
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003173 xmlGenericError(xmlGenericErrorContext,
3174 " with namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003175 prefix);
3176 break;
3177 }
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003178 xmlGenericError(xmlGenericErrorContext, "Testing : ");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003179#endif
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00003180 /*
3181 * 2.3 Node Tests
3182 * - For the attribute axis, the principal node type is attribute.
3183 * - For the namespace axis, the principal node type is namespace.
3184 * - For other axes, the principal node type is element.
3185 *
3186 * A node test * is true for any node of the
3187 * principal node type. For example, child::* willi
3188 * select all element children of the context node
3189 */
Daniel Veillard740abf52000-10-02 23:04:54 +00003190 for (i = 0;i < nodelist->nodeNr; i++) {
3191 ctxt->context->node = nodelist->nodeTab[i];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003192
3193 cur = NULL;
3194 do {
3195 cur = next(ctxt, cur);
3196 if (cur == NULL) break;
3197#ifdef DEBUG_STEP
3198 t++;
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003199 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003200#endif
3201 switch (test) {
3202 case NODE_TEST_NONE:
3203 STRANGE
Daniel Veillard740abf52000-10-02 23:04:54 +00003204 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003205 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003206 if ((cur->type == type) ||
Daniel Veillard2f913b72001-01-31 13:23:49 +00003207 ((type == NODE_TYPE_NODE) &&
Daniel Veillarddbfd6411999-12-28 16:35:14 +00003208 ((cur->type == XML_DOCUMENT_NODE) ||
Daniel Veillard2f913b72001-01-31 13:23:49 +00003209 (cur->type == XML_HTML_DOCUMENT_NODE) ||
3210 (cur->type == XML_ELEMENT_NODE) ||
3211 (cur->type == XML_PI_NODE) ||
3212 (cur->type == XML_COMMENT_NODE) ||
3213 (cur->type == XML_CDATA_SECTION_NODE) ||
3214 (cur->type == XML_TEXT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003215#ifdef DEBUG_STEP
3216 n++;
3217#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003218 addNode(ret, cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003219 }
3220 break;
3221 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003222 if (cur->type == XML_PI_NODE) {
3223 if ((name != NULL) &&
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003224 (!xmlStrEqual(name, cur->name)))
Daniel Veillardb96e6431999-08-29 21:02:19 +00003225 break;
3226#ifdef DEBUG_STEP
3227 n++;
3228#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003229 addNode(ret, cur);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003230 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003231 break;
3232 case NODE_TEST_ALL:
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003233 if (axis == AXIS_ATTRIBUTE) {
3234 if (cur->type == XML_ATTRIBUTE_NODE) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003235#ifdef DEBUG_STEP
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003236 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003237#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003238 addNode(ret, cur);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003239 }
3240 } else if (axis == AXIS_NAMESPACE) {
3241 if (cur->type == XML_NAMESPACE_DECL) {
3242#ifdef DEBUG_STEP
3243 n++;
3244#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003245 addNode(ret, cur);
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003246 }
3247 } else {
3248 if ((cur->type == XML_ELEMENT_NODE) ||
3249 (cur->type == XML_DOCUMENT_NODE) ||
3250 (cur->type == XML_HTML_DOCUMENT_NODE)) {
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003251 if (prefix == NULL) {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003252#ifdef DEBUG_STEP
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003253 n++;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003254#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003255 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003256 } else if ((cur->ns != NULL) &&
3257 (xmlStrEqual(prefix,
3258 cur->ns->href))) {
3259#ifdef DEBUG_STEP
3260 n++;
3261#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003262 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003263 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003264 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003265 }
3266 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003267 case NODE_TEST_NS: {
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003268 TODO;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003269 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003270 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003271 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00003272 switch (cur->type) {
3273 case XML_ELEMENT_NODE:
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003274 if (xmlStrEqual(name, cur->name)) {
3275 if (prefix == NULL) {
3276 if ((cur->ns == NULL) ||
3277 (cur->ns->prefix == NULL)) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003278#ifdef DEBUG_STEP
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003279 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003280#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003281 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003282 }
3283 } else {
3284 if ((cur->ns != NULL) &&
3285 (xmlStrEqual(prefix,
3286 cur->ns->href))) {
3287#ifdef DEBUG_STEP
3288 n++;
3289#endif
Daniel Veillard2c257ec2001-02-06 13:29:07 +00003290 addNode(ret, cur);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00003291 }
3292 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003293 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003294 break;
3295 case XML_ATTRIBUTE_NODE: {
3296 xmlAttrPtr attr = (xmlAttrPtr) cur;
Daniel Veillard8b5dd832000-10-01 20:28:44 +00003297 if (xmlStrEqual(name, attr->name)) {
Daniel Veillarde0e26512001-02-16 00:11:46 +00003298 if (prefix == NULL) {
3299 if ((attr->ns == NULL) ||
3300 (attr->ns->prefix == NULL)) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003301#ifdef DEBUG_STEP
Daniel Veillarde0e26512001-02-16 00:11:46 +00003302 n++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003303#endif
Daniel Veillarde0e26512001-02-16 00:11:46 +00003304 addNode(ret, attr);
3305 }
3306 } else {
3307 if ((attr->ns != NULL) &&
3308 (xmlStrEqual(prefix,
3309 attr->ns->href))) {
3310#ifdef DEBUG_STEP
3311 n++;
3312#endif
3313 addNode(ret, attr);
3314 }
3315 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003316 }
3317 break;
3318 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003319 case XML_NAMESPACE_DECL: {
3320 TODO;
3321 break;
3322 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00003323 default:
3324 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003325 }
3326 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003327 }
3328 } while (cur != NULL);
3329 }
3330#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003331 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003332 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
3333#endif
Daniel Veillard740abf52000-10-02 23:04:54 +00003334 xmlXPathFreeObject(obj);
3335 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003336}
3337
3338
3339/************************************************************************
3340 * *
3341 * Implicit tree core function library *
3342 * *
3343 ************************************************************************/
3344
3345/**
3346 * xmlXPathRoot:
3347 * @ctxt: the XPath Parser context
3348 *
3349 * Initialize the context to the root of the document
3350 */
3351void
3352xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00003353 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
Daniel Veillard740abf52000-10-02 23:04:54 +00003354 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003355}
3356
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003357/************************************************************************
3358 * *
3359 * The explicit core function library *
3360 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
3361 * *
3362 ************************************************************************/
3363
3364
3365/**
3366 * xmlXPathLastFunction:
3367 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003368 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003369 *
3370 * Implement the last() XPath function
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003371 * number last()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003372 * The last function returns the number of nodes in the context node list.
3373 */
3374void
3375xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3376 CHECK_ARITY(0);
Daniel Veillard142adbf2001-02-17 13:21:05 +00003377 if (ctxt->context->contextSize >= 0) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003378 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
3379#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003380 xmlGenericError(xmlGenericErrorContext,
3381 "last() : %d\n", ctxt->context->contextSize);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003382#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003383 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003384 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003385 }
3386}
3387
3388/**
3389 * xmlXPathPositionFunction:
3390 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003391 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003392 *
3393 * Implement the position() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003394 * number position()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003395 * The position function returns the position of the context node in the
3396 * context node list. The first position is 1, and so the last positionr
3397 * will be equal to last().
3398 */
3399void
3400xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003401 CHECK_ARITY(0);
Daniel Veillardff9c3302000-10-13 16:38:25 +00003402 if (ctxt->context->proximityPosition >= 0) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003403 valuePush(ctxt,
Daniel Veillardff9c3302000-10-13 16:38:25 +00003404 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003405#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003406 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
Daniel Veillardf09e7e32000-10-01 15:53:30 +00003407 ctxt->context->proximityPosition);
3408#endif
3409 } else {
3410 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003411 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003412}
3413
3414/**
3415 * xmlXPathCountFunction:
3416 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003417 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003418 *
3419 * Implement the count() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003420 * number count(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003421 */
3422void
3423xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3424 xmlXPathObjectPtr cur;
3425
3426 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003427 if ((ctxt->value == NULL) ||
3428 ((ctxt->value->type != XPATH_NODESET) &&
3429 (ctxt->value->type != XPATH_XSLT_TREE)))
3430 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003431 cur = valuePop(ctxt);
3432
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003433 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003434 xmlXPathFreeObject(cur);
3435}
3436
3437/**
3438 * xmlXPathIdFunction:
3439 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003440 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003441 *
3442 * Implement the id() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003443 * node-set id(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003444 * The id function selects elements by their unique ID
3445 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
3446 * then the result is the union of the result of applying id to the
3447 * string value of each of the nodes in the argument node-set. When the
3448 * argument to id is of any other type, the argument is converted to a
3449 * string as if by a call to the string function; the string is split
3450 * into a whitespace-separated list of tokens (whitespace is any sequence
3451 * of characters matching the production S); the result is a node-set
3452 * containing the elements in the same document as the context node that
3453 * have a unique ID equal to any of the tokens in the list.
3454 */
3455void
3456xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003457 const xmlChar *tokens;
3458 const xmlChar *cur;
3459 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003460 xmlAttrPtr attr;
3461 xmlNodePtr elem = NULL;
3462 xmlXPathObjectPtr ret, obj;
3463
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003464 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003465 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003466 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003467 if (obj->type == XPATH_NODESET) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003468 xmlXPathObjectPtr newobj;
3469 int i;
3470
3471 ret = xmlXPathNewNodeSet(NULL);
3472
3473 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
3474 valuePush(ctxt,
3475 xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
3476 xmlXPathStringFunction(ctxt, 1);
3477 xmlXPathIdFunction(ctxt, 1);
3478 newobj = valuePop(ctxt);
3479 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
3480 newobj->nodesetval);
3481 xmlXPathFreeObject(newobj);
3482 }
3483
3484 xmlXPathFreeObject(obj);
3485 valuePush(ctxt, ret);
3486 return;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003487 }
3488 if (obj->type != XPATH_STRING) {
3489 valuePush(ctxt, obj);
3490 xmlXPathStringFunction(ctxt, 1);
3491 obj = valuePop(ctxt);
3492 if (obj->type != XPATH_STRING) {
3493 xmlXPathFreeObject(obj);
3494 return;
3495 }
3496 }
3497 tokens = obj->stringval;
3498
3499 ret = xmlXPathNewNodeSet(NULL);
3500 valuePush(ctxt, ret);
3501 if (tokens == NULL) {
3502 xmlXPathFreeObject(obj);
3503 return;
3504 }
3505
3506 cur = tokens;
3507
3508 while (IS_BLANK(*cur)) cur++;
3509 while (*cur != 0) {
3510 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
3511 (*cur == '.') || (*cur == '-') ||
3512 (*cur == '_') || (*cur == ':') ||
3513 (IS_COMBINING(*cur)) ||
3514 (IS_EXTENDER(*cur)))
3515 cur++;
3516
3517 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
3518
3519 ID = xmlStrndup(tokens, cur - tokens);
3520 attr = xmlGetID(ctxt->context->doc, ID);
3521 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00003522 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003523 xmlXPathNodeSetAdd(ret->nodesetval, elem);
3524 }
3525 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003526 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003527
3528 while (IS_BLANK(*cur)) cur++;
3529 tokens = cur;
3530 }
3531 xmlXPathFreeObject(obj);
3532 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003533}
3534
3535/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003536 * xmlXPathLocalNameFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003537 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003538 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003539 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003540 * Implement the local-name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003541 * string local-name(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003542 * The local-name function returns a string containing the local part
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003543 * of the name of the node in the argument node-set that is first in
3544 * document order. If the node-set is empty or the first node has no
3545 * name, an empty string is returned. If the argument is omitted it
3546 * defaults to the context node.
3547 */
3548void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003549xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003550 xmlXPathObjectPtr cur;
3551
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003552 if (nargs == 0) {
3553 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3554 nargs = 1;
3555 }
3556
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003557 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003558 if ((ctxt->value == NULL) ||
3559 ((ctxt->value->type != XPATH_NODESET) &&
3560 (ctxt->value->type != XPATH_XSLT_TREE)))
3561 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003562 cur = valuePop(ctxt);
3563
3564 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003565 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003566 } else {
3567 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003568 switch (cur->nodesetval->nodeTab[i]->type) {
3569 case XML_ELEMENT_NODE:
3570 case XML_ATTRIBUTE_NODE:
3571 case XML_PI_NODE:
3572 valuePush(ctxt,
3573 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
3574 break;
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00003575 case XML_NAMESPACE_DECL:
3576 valuePush(ctxt, xmlXPathNewString(
3577 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
3578 break;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003579 default:
3580 valuePush(ctxt, xmlXPathNewCString(""));
3581 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003582 }
3583 xmlXPathFreeObject(cur);
3584}
3585
3586/**
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003587 * xmlXPathNamespaceURIFunction:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003588 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003589 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003590 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003591 * Implement the namespace-uri() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003592 * string namespace-uri(node-set?)
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003593 * The namespace-uri function returns a string containing the
3594 * namespace URI of the expanded name of the node in the argument
3595 * node-set that is first in document order. If the node-set is empty,
3596 * the first node has no name, or the expanded name has no namespace
3597 * URI, an empty string is returned. If the argument is omitted it
3598 * defaults to the context node.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003599 */
3600void
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003601xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003602 xmlXPathObjectPtr cur;
3603
Daniel Veillardb96e6431999-08-29 21:02:19 +00003604 if (nargs == 0) {
3605 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3606 nargs = 1;
3607 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003608 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003609 if ((ctxt->value == NULL) ||
3610 ((ctxt->value->type != XPATH_NODESET) &&
3611 (ctxt->value->type != XPATH_XSLT_TREE)))
3612 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003613 cur = valuePop(ctxt);
3614
3615 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003616 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003617 } else {
3618 int i = 0; /* Should be first in document order !!!!! */
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003619 switch (cur->nodesetval->nodeTab[i]->type) {
3620 case XML_ELEMENT_NODE:
3621 case XML_ATTRIBUTE_NODE:
3622 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3623 valuePush(ctxt, xmlXPathNewCString(""));
3624 else
3625 valuePush(ctxt, xmlXPathNewString(
3626 cur->nodesetval->nodeTab[i]->ns->href));
3627 break;
3628 default:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003629 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003630 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003631 }
3632 xmlXPathFreeObject(cur);
3633}
3634
3635/**
3636 * xmlXPathNameFunction:
3637 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003638 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003639 *
3640 * Implement the name() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003641 * string name(node-set?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003642 * The name function returns a string containing a QName representing
3643 * the name of the node in the argument node-set that is first in documenti
3644 * order. The QName must represent the name with respect to the namespace
3645 * declarations in effect on the node whose name is being represented.
3646 * Typically, this will be the form in which the name occurred in the XML
3647 * source. This need not be the case if there are namespace declarations
3648 * in effect on the node that associate multiple prefixes with the same
3649 * namespace. However, an implementation may include information about
3650 * the original prefix in its representation of nodes; in this case, an
3651 * implementation can ensure that the returned string is always the same
3652 * as the QName used in the XML source. If the argument it omitted it
3653 * defaults to the context node.
3654 * Libxml keep the original prefix so the "real qualified name" used is
3655 * returned.
3656 */
3657void
3658xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3659 xmlXPathObjectPtr cur;
3660
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003661 if (nargs == 0) {
3662 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3663 nargs = 1;
3664 }
3665
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003666 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00003667 if ((ctxt->value == NULL) ||
3668 ((ctxt->value->type != XPATH_NODESET) &&
3669 (ctxt->value->type != XPATH_XSLT_TREE)))
3670 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003671 cur = valuePop(ctxt);
3672
3673 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003674 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003675 } else {
3676 int i = 0; /* Should be first in document order !!!!! */
3677
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003678 switch (cur->nodesetval->nodeTab[i]->type) {
3679 case XML_ELEMENT_NODE:
3680 case XML_ATTRIBUTE_NODE:
3681 if (cur->nodesetval->nodeTab[i]->ns == NULL)
3682 valuePush(ctxt, xmlXPathNewString(
3683 cur->nodesetval->nodeTab[i]->name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003684
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003685 else {
3686 char name[2000];
Daniel Veillard39c7d712000-09-10 16:14:55 +00003687#ifdef HAVE_SNPRINTF
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003688 snprintf(name, sizeof(name), "%s:%s",
3689 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3690 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003691#else
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003692 sprintf(name, "%s:%s",
3693 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
3694 (char *) cur->nodesetval->nodeTab[i]->name);
Daniel Veillard39c7d712000-09-10 16:14:55 +00003695#endif
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003696 name[sizeof(name) - 1] = 0;
3697 valuePush(ctxt, xmlXPathNewCString(name));
3698 }
3699 break;
3700 default:
3701 valuePush(ctxt,
3702 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
3703 xmlXPathLocalNameFunction(ctxt, 1);
3704 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003705 }
3706 xmlXPathFreeObject(cur);
3707}
3708
3709/**
3710 * xmlXPathStringFunction:
3711 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003712 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003713 *
3714 * Implement the string() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003715 * string string(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003716 * he string function converts an object to a string as follows:
3717 * - A node-set is converted to a string by returning the value of
3718 * the node in the node-set that is first in document order.
3719 * If the node-set is empty, an empty string is returned.
3720 * - A number is converted to a string as follows
3721 * + NaN is converted to the string NaN
3722 * + positive zero is converted to the string 0
3723 * + negative zero is converted to the string 0
3724 * + positive infinity is converted to the string Infinity
3725 * + negative infinity is converted to the string -Infinity
3726 * + if the number is an integer, the number is represented in
3727 * decimal form as a Number with no decimal point and no leading
3728 * zeros, preceded by a minus sign (-) if the number is negative
3729 * + otherwise, the number is represented in decimal form as a
3730 * Number including a decimal point with at least one digit
3731 * before the decimal point and at least one digit after the
3732 * decimal point, preceded by a minus sign (-) if the number
3733 * is negative; there must be no leading zeros before the decimal
3734 * point apart possibly from the one required digit immediatelyi
3735 * before the decimal point; beyond the one required digit
3736 * after the decimal point there must be as many, but only as
3737 * many, more digits as are needed to uniquely distinguish the
3738 * number from all other IEEE 754 numeric values.
3739 * - The boolean false value is converted to the string false.
3740 * The boolean true value is converted to the string true.
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003741 *
3742 * If the argument is omitted, it defaults to a node-set with the
3743 * context node as its only member.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003744 */
3745void
3746xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3747 xmlXPathObjectPtr cur;
3748
Daniel Veillardf6bf9212000-10-26 14:07:44 +00003749 if (nargs == 0) {
3750 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
3751 nargs = 1;
3752 }
3753
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003754 CHECK_ARITY(1);
3755 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003756 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003757 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00003758 case XPATH_UNDEFINED:
3759#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00003760 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00003761#endif
3762 valuePush(ctxt, xmlXPathNewCString(""));
3763 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00003764 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003765 case XPATH_NODESET:
Daniel Veillardd12b69d2001-02-11 20:17:31 +00003766 if (cur->nodesetval == NULL)
3767 valuePush(ctxt, xmlXPathNewCString(""));
3768 else if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003769 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003770 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003771 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003772 int i = 0; /* Should be first in document order !!!!! */
3773 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
3774 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard5a2b6972001-01-20 21:15:50 +00003775 if (res != NULL)
3776 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003777 }
3778 xmlXPathFreeObject(cur);
3779 return;
3780 case XPATH_STRING:
3781 valuePush(ctxt, cur);
3782 return;
3783 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00003784 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
3785 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003786 xmlXPathFreeObject(cur);
3787 return;
3788 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00003789 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003790
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003791 if (isnan(cur->floatval))
3792 sprintf(buf, "NaN");
3793 else if (isinf(cur->floatval) > 0)
3794 sprintf(buf, "+Infinity");
3795 else if (isinf(cur->floatval) < 0)
3796 sprintf(buf, "-Infinity");
3797 else
3798 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003799 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003800 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003801 return;
3802 }
Daniel Veillard740abf52000-10-02 23:04:54 +00003803 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00003804 case XPATH_POINT:
3805 case XPATH_RANGE:
3806 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00003807 TODO
3808 valuePush(ctxt, xmlXPathNewCString(""));
3809 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003810 }
3811 STRANGE
3812}
3813
3814/**
3815 * xmlXPathStringLengthFunction:
3816 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003817 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003818 *
3819 * Implement the string-length() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003820 * number string-length(string?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003821 * The string-length returns the number of characters in the string
3822 * (see [3.6 Strings]). If the argument is omitted, it defaults to
3823 * the context node converted to a string, in other words the value
3824 * of the context node.
3825 */
3826void
3827xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3828 xmlXPathObjectPtr cur;
3829
3830 if (nargs == 0) {
3831 if (ctxt->context->node == NULL) {
3832 valuePush(ctxt, xmlXPathNewFloat(0));
3833 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003834 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003835
3836 content = xmlNodeGetContent(ctxt->context->node);
3837 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003838 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003839 }
3840 return;
3841 }
3842 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003843 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003844 CHECK_TYPE(XPATH_STRING);
3845 cur = valuePop(ctxt);
3846 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3847 xmlXPathFreeObject(cur);
3848}
3849
3850/**
3851 * xmlXPathConcatFunction:
3852 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003853 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003854 *
3855 * Implement the concat() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003856 * string concat(string, string, string*)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003857 * The concat function returns the concatenation of its arguments.
3858 */
3859void
3860xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003861 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003862 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003863
3864 if (nargs < 2) {
3865 CHECK_ARITY(2);
3866 }
3867
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003868 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003869 cur = valuePop(ctxt);
3870 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3871 xmlXPathFreeObject(cur);
3872 return;
3873 }
3874 nargs--;
3875
3876 while (nargs > 0) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003877 CAST_TO_STRING;
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003878 newobj = valuePop(ctxt);
3879 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3880 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003881 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003882 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003883 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003884 tmp = xmlStrcat(newobj->stringval, cur->stringval);
3885 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003886 cur->stringval = tmp;
3887
Daniel Veillard32bc74e2000-07-14 14:49:25 +00003888 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003889 nargs--;
3890 }
3891 valuePush(ctxt, cur);
3892}
3893
3894/**
3895 * xmlXPathContainsFunction:
3896 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003897 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003898 *
3899 * Implement the contains() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003900 * boolean contains(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003901 * The contains function returns true if the first argument string
3902 * contains the second argument string, and otherwise returns false.
3903 */
3904void
3905xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3906 xmlXPathObjectPtr hay, needle;
3907
3908 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003909 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003910 CHECK_TYPE(XPATH_STRING);
3911 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003912 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003913 hay = valuePop(ctxt);
3914 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3915 xmlXPathFreeObject(hay);
3916 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003917 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003918 }
3919 if (xmlStrstr(hay->stringval, needle->stringval))
3920 valuePush(ctxt, xmlXPathNewBoolean(1));
3921 else
3922 valuePush(ctxt, xmlXPathNewBoolean(0));
3923 xmlXPathFreeObject(hay);
3924 xmlXPathFreeObject(needle);
3925}
3926
3927/**
3928 * xmlXPathStartsWithFunction:
3929 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003930 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003931 *
3932 * Implement the starts-with() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003933 * boolean starts-with(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003934 * The starts-with function returns true if the first argument string
3935 * starts with the second argument string, and otherwise returns false.
3936 */
3937void
3938xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3939 xmlXPathObjectPtr hay, needle;
3940 int n;
3941
3942 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003943 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003944 CHECK_TYPE(XPATH_STRING);
3945 needle = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003946 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003947 hay = valuePop(ctxt);
3948 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3949 xmlXPathFreeObject(hay);
3950 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003951 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003952 }
3953 n = xmlStrlen(needle->stringval);
3954 if (xmlStrncmp(hay->stringval, needle->stringval, n))
3955 valuePush(ctxt, xmlXPathNewBoolean(0));
3956 else
3957 valuePush(ctxt, xmlXPathNewBoolean(1));
3958 xmlXPathFreeObject(hay);
3959 xmlXPathFreeObject(needle);
3960}
3961
3962/**
3963 * xmlXPathSubstringFunction:
3964 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00003965 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003966 *
3967 * Implement the substring() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00003968 * string substring(string, number, number?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003969 * The substring function returns the substring of the first argument
3970 * starting at the position specified in the second argument with
3971 * length specified in the third argument. For example,
3972 * substring("12345",2,3) returns "234". If the third argument is not
3973 * specified, it returns the substring starting at the position specified
3974 * in the second argument and continuing to the end of the string. For
3975 * example, substring("12345",2) returns "2345". More precisely, each
3976 * character in the string (see [3.6 Strings]) is considered to have a
3977 * numeric position: the position of the first character is 1, the position
3978 * of the second character is 2 and so on. The returned substring contains
3979 * those characters for which the position of the character is greater than
3980 * or equal to the second argument and, if the third argument is specified,
3981 * less than the sum of the second and third arguments; the comparisons
3982 * and addition used for the above follow the standard IEEE 754 rules. Thus:
3983 * - substring("12345", 1.5, 2.6) returns "234"
3984 * - substring("12345", 0, 3) returns "12"
3985 * - substring("12345", 0 div 0, 3) returns ""
3986 * - substring("12345", 1, 0 div 0) returns ""
3987 * - substring("12345", -42, 1 div 0) returns "12345"
3988 * - substring("12345", -1 div 0, 1 div 0) returns ""
3989 */
3990void
3991xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3992 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003993 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003994 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003995 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003996
3997 /*
3998 * Conformance needs to be checked !!!!!
3999 */
4000 if (nargs < 2) {
4001 CHECK_ARITY(2);
4002 }
4003 if (nargs > 3) {
4004 CHECK_ARITY(3);
4005 }
4006 if (nargs == 3) {
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004007 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004008 CHECK_TYPE(XPATH_NUMBER);
4009 len = valuePop(ctxt);
4010 le = len->floatval;
4011 xmlXPathFreeObject(len);
4012 } else {
4013 le = 2000000000;
4014 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004015 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004016 CHECK_TYPE(XPATH_NUMBER);
4017 start = valuePop(ctxt);
4018 in = start->floatval;
4019 xmlXPathFreeObject(start);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004020 CAST_TO_STRING;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004021 CHECK_TYPE(XPATH_STRING);
4022 str = valuePop(ctxt);
4023 le += in;
4024
4025 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004026 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004027 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004028
4029 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004030 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004031 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004032
4033 /* back to a zero based len */
4034 i--;
4035 l--;
4036
4037 /* check against the string len */
4038 if (l > 1024) {
4039 l = xmlStrlen(str->stringval);
4040 }
4041 if (i < 0) {
4042 i = 0;
4043 }
4044
4045 /* number of chars to copy */
4046 l -= i;
4047
4048 ret = xmlStrsub(str->stringval, i, l);
4049 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004050 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004051 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004052 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004053 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004054 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004055 xmlXPathFreeObject(str);
4056}
4057
4058/**
4059 * xmlXPathSubstringBeforeFunction:
4060 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004061 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004062 *
4063 * Implement the substring-before() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004064 * string substring-before(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004065 * The substring-before function returns the substring of the first
4066 * argument string that precedes the first occurrence of the second
4067 * argument string in the first argument string, or the empty string
4068 * if the first argument string does not contain the second argument
4069 * string. For example, substring-before("1999/04/01","/") returns 1999.
4070 */
4071void
4072xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004073 xmlXPathObjectPtr str;
4074 xmlXPathObjectPtr find;
4075 xmlBufferPtr target;
4076 const xmlChar *point;
4077 int offset;
4078
4079 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004080 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004081 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004082 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004083 str = valuePop(ctxt);
4084
4085 target = xmlBufferCreate();
4086 if (target) {
4087 point = xmlStrstr(str->stringval, find->stringval);
4088 if (point) {
4089 offset = (int)(point - str->stringval);
4090 xmlBufferAdd(target, str->stringval, offset);
4091 }
4092 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4093 xmlBufferFree(target);
4094 }
4095
4096 xmlXPathFreeObject(str);
4097 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004098}
4099
4100/**
4101 * xmlXPathSubstringAfterFunction:
4102 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004103 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004104 *
4105 * Implement the substring-after() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004106 * string substring-after(string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004107 * The substring-after function returns the substring of the first
4108 * argument string that follows the first occurrence of the second
4109 * argument string in the first argument string, or the empty stringi
4110 * if the first argument string does not contain the second argument
4111 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4112 * and substring-after("1999/04/01","19") returns 99/04/01.
4113 */
4114void
4115xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004116 xmlXPathObjectPtr str;
4117 xmlXPathObjectPtr find;
4118 xmlBufferPtr target;
4119 const xmlChar *point;
4120 int offset;
4121
4122 CHECK_ARITY(2);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004123 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004124 find = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004125 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004126 str = valuePop(ctxt);
4127
4128 target = xmlBufferCreate();
4129 if (target) {
4130 point = xmlStrstr(str->stringval, find->stringval);
4131 if (point) {
4132 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4133 xmlBufferAdd(target, &str->stringval[offset],
4134 xmlStrlen(str->stringval) - offset);
4135 }
4136 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4137 xmlBufferFree(target);
4138 }
4139
4140 xmlXPathFreeObject(str);
4141 xmlXPathFreeObject(find);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004142}
4143
4144/**
4145 * xmlXPathNormalizeFunction:
4146 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004147 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004148 *
Daniel Veillard767662d2000-10-27 17:04:52 +00004149 * Implement the normalize-space() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004150 * string normalize-space(string?)
Daniel Veillard767662d2000-10-27 17:04:52 +00004151 * The normalize-space function returns the argument string with white
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004152 * space normalized by stripping leading and trailing whitespace
4153 * and replacing sequences of whitespace characters by a single
4154 * space. Whitespace characters are the same allowed by the S production
4155 * in XML. If the argument is omitted, it defaults to the context
4156 * node converted to a string, in other words the value of the context node.
4157 */
4158void
4159xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004160 xmlXPathObjectPtr obj = NULL;
4161 xmlChar *source = NULL;
4162 xmlBufferPtr target;
4163 xmlChar blank;
4164
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004165 if (nargs == 0) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004166 /* Use current context node */
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004167 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4168 xmlXPathStringFunction(ctxt, 1);
4169 nargs = 1;
Daniel Veillard46057e12000-09-24 18:49:59 +00004170 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004171
4172 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004173 CAST_TO_STRING;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004174 CHECK_TYPE(XPATH_STRING);
4175 obj = valuePop(ctxt);
4176 source = obj->stringval;
4177
Daniel Veillard46057e12000-09-24 18:49:59 +00004178 target = xmlBufferCreate();
4179 if (target && source) {
4180
4181 /* Skip leading whitespaces */
4182 while (IS_BLANK(*source))
4183 source++;
4184
4185 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
4186 blank = 0;
4187 while (*source) {
4188 if (IS_BLANK(*source)) {
4189 blank = *source;
4190 } else {
4191 if (blank) {
4192 xmlBufferAdd(target, &blank, 1);
4193 blank = 0;
4194 }
4195 xmlBufferAdd(target, source, 1);
4196 }
4197 source++;
4198 }
4199
4200 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4201 xmlBufferFree(target);
4202 }
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004203 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004204}
4205
4206/**
4207 * xmlXPathTranslateFunction:
4208 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004209 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004210 *
4211 * Implement the translate() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004212 * string translate(string, string, string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004213 * The translate function returns the first argument string with
4214 * occurrences of characters in the second argument string replaced
4215 * by the character at the corresponding position in the third argument
4216 * string. For example, translate("bar","abc","ABC") returns the string
4217 * BAr. If there is a character in the second argument string with no
4218 * character at a corresponding position in the third argument string
4219 * (because the second argument string is longer than the third argument
4220 * string), then occurrences of that character in the first argument
4221 * string are removed. For example, translate("--aaa--","abc-","ABC")
4222 * returns "AAA". If a character occurs more than once in second
4223 * argument string, then the first occurrence determines the replacement
4224 * character. If the third argument string is longer than the second
4225 * argument string, then excess characters are ignored.
4226 */
4227void
4228xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard46057e12000-09-24 18:49:59 +00004229 xmlXPathObjectPtr str;
4230 xmlXPathObjectPtr from;
4231 xmlXPathObjectPtr to;
4232 xmlBufferPtr target;
4233 int i, offset, max;
4234 xmlChar ch;
4235 const xmlChar *point;
4236
4237 CHECK_ARITY(3);
4238
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004239 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004240 to = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004241 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004242 from = valuePop(ctxt);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004243 CAST_TO_STRING;
Daniel Veillard46057e12000-09-24 18:49:59 +00004244 str = valuePop(ctxt);
4245
4246 target = xmlBufferCreate();
4247 if (target) {
4248 max = xmlStrlen(to->stringval);
4249 for (i = 0; (ch = str->stringval[i]); i++) {
4250 point = xmlStrchr(from->stringval, ch);
4251 if (point) {
4252 /* Warning: This may not work with UTF-8 */
4253 offset = (int)(point - from->stringval);
4254 if (offset < max)
4255 xmlBufferAdd(target, &to->stringval[offset], 1);
4256 } else
4257 xmlBufferAdd(target, &ch, 1);
4258 }
4259 }
4260 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4261 xmlBufferFree(target);
4262 xmlXPathFreeObject(str);
4263 xmlXPathFreeObject(from);
4264 xmlXPathFreeObject(to);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004265}
4266
4267/**
4268 * xmlXPathBooleanFunction:
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 boolean() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004273 * boolean boolean(object)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004274 * he boolean function converts its argument to a boolean as follows:
4275 * - a number is true if and only if it is neither positive or
4276 * negative zero nor NaN
4277 * - a node-set is true if and only if it is non-empty
4278 * - a string is true if and only if its length is non-zero
4279 */
4280void
4281xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4282 xmlXPathObjectPtr cur;
4283 int res = 0;
4284
4285 CHECK_ARITY(1);
4286 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004287 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004288 switch (cur->type) {
4289 case XPATH_NODESET:
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00004290 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004291 if ((cur->nodesetval == NULL) ||
4292 (cur->nodesetval->nodeNr == 0)) res = 0;
4293 else
4294 res = 1;
4295 break;
4296 case XPATH_STRING:
4297 if ((cur->stringval == NULL) ||
4298 (cur->stringval[0] == 0)) res = 0;
4299 else
4300 res = 1;
4301 break;
4302 case XPATH_BOOLEAN:
4303 valuePush(ctxt, cur);
4304 return;
4305 case XPATH_NUMBER:
4306 if (cur->floatval) res = 1;
4307 break;
4308 default:
4309 STRANGE
4310 }
4311 xmlXPathFreeObject(cur);
4312 valuePush(ctxt, xmlXPathNewBoolean(res));
4313}
4314
4315/**
4316 * xmlXPathNotFunction:
4317 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004318 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004319 *
4320 * Implement the not() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004321 * boolean not(boolean)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004322 * The not function returns true if its argument is false,
4323 * and false otherwise.
4324 */
4325void
4326xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4327 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004328 CAST_TO_BOOLEAN;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004329 CHECK_TYPE(XPATH_BOOLEAN);
4330 ctxt->value->boolval = ! ctxt->value->boolval;
4331}
4332
4333/**
4334 * xmlXPathTrueFunction:
4335 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004336 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004337 *
4338 * Implement the true() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004339 * boolean true()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004340 */
4341void
4342xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4343 CHECK_ARITY(0);
4344 valuePush(ctxt, xmlXPathNewBoolean(1));
4345}
4346
4347/**
4348 * xmlXPathFalseFunction:
4349 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004350 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004351 *
4352 * Implement the false() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004353 * boolean false()
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004354 */
4355void
4356xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4357 CHECK_ARITY(0);
4358 valuePush(ctxt, xmlXPathNewBoolean(0));
4359}
4360
4361/**
4362 * xmlXPathLangFunction:
4363 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004364 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004365 *
4366 * Implement the lang() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004367 * boolean lang(string)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004368 * The lang function returns true or false depending on whether the
4369 * language of the context node as specified by xml:lang attributes
4370 * is the same as or is a sublanguage of the language specified by
4371 * the argument string. The language of the context node is determined
4372 * by the value of the xml:lang attribute on the context node, or, if
4373 * the context node has no xml:lang attribute, by the value of the
4374 * xml:lang attribute on the nearest ancestor of the context node that
4375 * has an xml:lang attribute. If there is no such attribute, then lang
4376 * returns false. If there is such an attribute, then lang returns
4377 * true if the attribute value is equal to the argument ignoring case,
4378 * or if there is some suffix starting with - such that the attribute
4379 * value is equal to the argument ignoring that suffix of the attribute
4380 * value and ignoring case.
4381 */
4382void
4383xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004384 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004385 const xmlChar *theLang;
4386 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004387 int ret = 0;
4388 int i;
4389
4390 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004391 CAST_TO_STRING;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004392 CHECK_TYPE(XPATH_STRING);
4393 val = valuePop(ctxt);
4394 lang = val->stringval;
4395 theLang = xmlNodeGetLang(ctxt->context->node);
4396 if ((theLang != NULL) && (lang != NULL)) {
4397 for (i = 0;lang[i] != 0;i++)
4398 if (toupper(lang[i]) != toupper(theLang[i]))
4399 goto not_equal;
4400 ret = 1;
4401 }
4402not_equal:
4403 xmlXPathFreeObject(val);
4404 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004405}
4406
4407/**
4408 * xmlXPathNumberFunction:
4409 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004410 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004411 *
4412 * Implement the number() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004413 * number number(object?)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004414 */
4415void
4416xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4417 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004418 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004419
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004420 if (nargs == 0) {
4421 if (ctxt->context->node == NULL) {
4422 valuePush(ctxt, xmlXPathNewFloat(0.0));
4423 } else {
4424 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
4425
4426 res = xmlXPathStringEvalNumber(content);
4427 valuePush(ctxt, xmlXPathNewFloat(res));
4428 xmlFree(content);
4429 }
4430 return;
4431 }
4432
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004433 CHECK_ARITY(1);
4434 cur = valuePop(ctxt);
4435 switch (cur->type) {
Daniel Veillard740abf52000-10-02 23:04:54 +00004436 case XPATH_UNDEFINED:
4437#ifdef DEBUG_EXPR
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00004438 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00004439#endif
4440 valuePush(ctxt, xmlXPathNewFloat(0.0));
4441 break;
Daniel Veillarde4566462001-01-22 09:58:39 +00004442 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004443 case XPATH_NODESET:
4444 valuePush(ctxt, cur);
4445 xmlXPathStringFunction(ctxt, 1);
4446 cur = valuePop(ctxt);
4447 case XPATH_STRING:
4448 res = xmlXPathStringEvalNumber(cur->stringval);
4449 valuePush(ctxt, xmlXPathNewFloat(res));
4450 xmlXPathFreeObject(cur);
4451 return;
4452 case XPATH_BOOLEAN:
4453 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
4454 else valuePush(ctxt, xmlXPathNewFloat(0.0));
4455 xmlXPathFreeObject(cur);
4456 return;
4457 case XPATH_NUMBER:
4458 valuePush(ctxt, cur);
4459 return;
Daniel Veillard740abf52000-10-02 23:04:54 +00004460 case XPATH_USERS:
Daniel Veillardac260302000-10-04 13:33:43 +00004461 case XPATH_POINT:
4462 case XPATH_RANGE:
4463 case XPATH_LOCATIONSET:
Daniel Veillard740abf52000-10-02 23:04:54 +00004464 TODO
4465 valuePush(ctxt, xmlXPathNewFloat(0.0));
4466 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004467 }
4468 STRANGE
4469}
4470
4471/**
4472 * xmlXPathSumFunction:
4473 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004474 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004475 *
4476 * Implement the sum() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004477 * number sum(node-set)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004478 * The sum function returns the sum of the values of the nodes in
4479 * the argument node-set.
4480 */
4481void
4482xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004483 xmlXPathObjectPtr cur;
4484 int i;
4485
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004486 CHECK_ARITY(1);
Daniel Veillarde99a4762001-02-01 04:34:35 +00004487 if ((ctxt->value == NULL) ||
4488 ((ctxt->value->type != XPATH_NODESET) &&
4489 (ctxt->value->type != XPATH_XSLT_TREE)))
4490 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004491 cur = valuePop(ctxt);
4492
4493 if (cur->nodesetval->nodeNr == 0) {
4494 valuePush(ctxt, xmlXPathNewFloat(0.0));
4495 } else {
4496 valuePush(ctxt,
4497 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
Daniel Veillard767662d2000-10-27 17:04:52 +00004498 xmlXPathNumberFunction(ctxt, 1);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004499 for (i = 1; i < cur->nodesetval->nodeNr; i++) {
4500 valuePush(ctxt,
4501 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4502 xmlXPathAddValues(ctxt);
4503 }
4504 }
4505 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004506}
4507
4508/**
4509 * xmlXPathFloorFunction:
4510 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004511 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004512 *
4513 * Implement the floor() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004514 * number floor(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004515 * The floor function returns the largest (closest to positive infinity)
4516 * number that is not greater than the argument and that is an integer.
4517 */
4518void
4519xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4520 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004521 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004522 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004523#if 0
4524 ctxt->value->floatval = floor(ctxt->value->floatval);
4525#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004526 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004527 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004528#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004529}
4530
4531/**
4532 * xmlXPathCeilingFunction:
4533 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004534 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004535 *
4536 * Implement the ceiling() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004537 * number ceiling(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004538 * The ceiling function returns the smallest (closest to negative infinity)
4539 * number that is not less than the argument and that is an integer.
4540 */
4541void
4542xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004543 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004544
4545 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004546 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004547 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004548
4549#if 0
4550 ctxt->value->floatval = ceil(ctxt->value->floatval);
4551#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004552 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004553 if (f != ctxt->value->floatval)
4554 ctxt->value->floatval = f + 1;
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004555#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004556}
4557
4558/**
4559 * xmlXPathRoundFunction:
4560 * @ctxt: the XPath Parser context
Daniel Veillardf17e09b2001-01-25 13:55:35 +00004561 * @nargs: the number of arguments
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004562 *
4563 * Implement the round() XPath function
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004564 * number round(number)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004565 * The round function returns the number that is closest to the
4566 * argument and that is an integer. If there are two such numbers,
4567 * then the one that is even is returned.
4568 */
4569void
4570xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004571 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004572
4573 CHECK_ARITY(1);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004574 CAST_TO_NUMBER;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004575 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004576
4577 if ((ctxt->value->floatval == xmlXPathNAN) ||
4578 (ctxt->value->floatval == xmlXPathPINF) ||
4579 (ctxt->value->floatval == xmlXPathNINF) ||
4580 (ctxt->value->floatval == 0.0))
4581 return;
4582
4583#if 0
4584 f = floor(ctxt->value->floatval);
4585#else
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004586 f = (double)((int) ctxt->value->floatval);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004587#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004588 if (ctxt->value->floatval < f + 0.5)
4589 ctxt->value->floatval = f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004590 else
4591 ctxt->value->floatval = f + 1;
4592}
4593
4594/************************************************************************
4595 * *
4596 * The Parser *
4597 * *
4598 ************************************************************************/
4599
4600/*
4601 * a couple of forward declarations since we use a recursive call based
4602 * implementation.
4603 */
4604void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
4605void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
4606void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004607#ifdef VMS
4608void xmlXPathEvalRelLocationPath(xmlXPathParserContextPtr ctxt);
4609#define xmlXPathEvalRelativeLocationPath xmlXPathEvalRelLocationPath
4610#else
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004611void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Daniel Veillardce6e98d2000-11-25 09:54:49 +00004612#endif
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004613
4614/**
4615 * xmlXPathParseNCName:
4616 * @ctxt: the XPath Parser context
4617 *
4618 * parse an XML namespace non qualified name.
4619 *
4620 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
4621 *
4622 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
4623 * CombiningChar | Extender
4624 *
4625 * Returns the namespace name or NULL
4626 */
4627
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004628xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004629xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004630 const xmlChar *q;
4631 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004632
4633 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4634 q = NEXT;
4635
4636 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4637 (CUR == '.') || (CUR == '-') ||
4638 (CUR == '_') ||
4639 (IS_COMBINING(CUR)) ||
4640 (IS_EXTENDER(CUR)))
4641 NEXT;
4642
4643 ret = xmlStrndup(q, CUR_PTR - q);
4644
4645 return(ret);
4646}
4647
4648/**
4649 * xmlXPathParseQName:
4650 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004651 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004652 *
4653 * parse an XML qualified name
4654 *
4655 * [NS 5] QName ::= (Prefix ':')? LocalPart
4656 *
4657 * [NS 6] Prefix ::= NCName
4658 *
4659 * [NS 7] LocalPart ::= NCName
4660 *
4661 * Returns the function returns the local part, and prefix is updated
4662 * to get the Prefix if any.
4663 */
4664
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004665xmlChar *
4666xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
4667 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004668
4669 *prefix = NULL;
4670 ret = xmlXPathParseNCName(ctxt);
4671 if (CUR == ':') {
4672 *prefix = ret;
4673 NEXT;
4674 ret = xmlXPathParseNCName(ctxt);
4675 }
4676 return(ret);
4677}
4678
4679/**
Daniel Veillard2d38f042000-10-11 10:54:10 +00004680 * xmlXPathParseName:
Daniel Veillardf6eea272001-01-18 12:17:12 +00004681 * @ctxt: the XPath Parser context
Daniel Veillard2d38f042000-10-11 10:54:10 +00004682 *
4683 * parse an XML name
4684 *
4685 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4686 * CombiningChar | Extender
4687 *
4688 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4689 *
4690 * Returns the namespace name or NULL
4691 */
4692
4693xmlChar *
4694xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
4695 const xmlChar *q;
4696 xmlChar *ret = NULL;
4697
4698 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
4699 q = NEXT;
4700
4701 /* TODO Make this UTF8 compliant !!! */
4702 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
4703 (CUR == '.') || (CUR == '-') ||
4704 (CUR == '_') || (CUR == ':') ||
4705 (IS_COMBINING(CUR)) ||
4706 (IS_EXTENDER(CUR)))
4707 NEXT;
4708
4709 ret = xmlStrndup(q, CUR_PTR - q);
4710
4711 return(ret);
4712}
4713
4714/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004715 * xmlXPathStringEvalNumber:
4716 * @str: A string to scan
4717 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004718 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004719 * | '.' Digits
4720 * [31] Digits ::= [0-9]+
4721 *
4722 * Parse and evaluate a Number in the string
Daniel Veillard767662d2000-10-27 17:04:52 +00004723 * In complement of the Number expression, this function also handles
4724 * negative values : '-' Number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004725 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004726 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004727 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004728double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004729xmlXPathStringEvalNumber(const xmlChar *str) {
4730 const xmlChar *cur = str;
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;
Daniel Veillard767662d2000-10-27 17:04:52 +00004734 int isneg = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004735
4736 while (*cur == ' ') cur++;
Daniel Veillard767662d2000-10-27 17:04:52 +00004737 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004738 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004739 }
Daniel Veillard767662d2000-10-27 17:04:52 +00004740 if (*cur == '-') {
4741 isneg = 1;
4742 cur++;
4743 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004744 while ((*cur >= '0') && (*cur <= '9')) {
4745 ret = ret * 10 + (*cur - '0');
4746 ok = 1;
4747 cur++;
4748 }
4749 if (*cur == '.') {
4750 cur++;
4751 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004752 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004753 }
4754 while ((*cur >= '0') && (*cur <= '9')) {
4755 mult /= 10;
4756 ret = ret + (*cur - '0') * mult;
4757 cur++;
4758 }
4759 }
4760 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004761 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard767662d2000-10-27 17:04:52 +00004762 if (isneg) ret = -ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004763 return(ret);
4764}
4765
4766/**
4767 * xmlXPathEvalNumber:
4768 * @ctxt: the XPath Parser context
4769 *
Daniel Veillardf6bf9212000-10-26 14:07:44 +00004770 * [30] Number ::= Digits ('.' Digits?)?
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004771 * | '.' Digits
4772 * [31] Digits ::= [0-9]+
4773 *
4774 * Parse and evaluate a Number, then push it on the stack
4775 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004776 */
4777void
4778xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004779 double ret = 0.0;
4780 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004781 int ok = 0;
4782
4783 CHECK_ERROR;
4784 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004785 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004786 }
4787 while ((CUR >= '0') && (CUR <= '9')) {
4788 ret = ret * 10 + (CUR - '0');
4789 ok = 1;
4790 NEXT;
4791 }
4792 if (CUR == '.') {
4793 NEXT;
4794 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004795 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004796 }
4797 while ((CUR >= '0') && (CUR <= '9')) {
4798 mult /= 10;
4799 ret = ret + (CUR - '0') * mult;
4800 NEXT;
4801 }
4802 }
4803 valuePush(ctxt, xmlXPathNewFloat(ret));
4804}
4805
4806/**
4807 * xmlXPathEvalLiteral:
4808 * @ctxt: the XPath Parser context
4809 *
4810 * Parse a Literal and push it on the stack.
4811 *
4812 * [29] Literal ::= '"' [^"]* '"'
4813 * | "'" [^']* "'"
4814 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004815 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004816 */
4817void
4818xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004819 const xmlChar *q;
4820 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004821
4822 if (CUR == '"') {
4823 NEXT;
4824 q = CUR_PTR;
4825 while ((IS_CHAR(CUR)) && (CUR != '"'))
4826 NEXT;
4827 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004828 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004829 } else {
4830 ret = xmlStrndup(q, CUR_PTR - q);
4831 NEXT;
4832 }
4833 } else if (CUR == '\'') {
4834 NEXT;
4835 q = CUR_PTR;
4836 while ((IS_CHAR(CUR)) && (CUR != '\''))
4837 NEXT;
4838 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004839 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004840 } else {
4841 ret = xmlStrndup(q, CUR_PTR - q);
4842 NEXT;
4843 }
4844 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004845 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004846 }
4847 if (ret == NULL) return;
4848 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00004849 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004850}
4851
4852/**
4853 * xmlXPathEvalVariableReference:
4854 * @ctxt: the XPath Parser context
4855 *
4856 * Parse a VariableReference, evaluate it and push it on the stack.
4857 *
4858 * The variable bindings consist of a mapping from variable names
4859 * to variable values. The value of a variable is an object, which
4860 * of any of the types that are possible for the value of an expression,
4861 * and may also be of additional types not specified here.
4862 *
4863 * Early evaluation is possible since:
4864 * The variable bindings [...] used to evaluate a subexpression are
4865 * always the same as those used to evaluate the containing expression.
4866 *
4867 * [36] VariableReference ::= '$' QName
4868 */
4869void
4870xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004871 xmlChar *name;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004872 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004873 xmlXPathObjectPtr value;
4874
Daniel Veillard55b91f22000-10-05 16:30:11 +00004875 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004876 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004877 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004878 }
Daniel Veillard5a2b6972001-01-20 21:15:50 +00004879 NEXT;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004880 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004881 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004882 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004883 }
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004884 if (prefix == NULL) {
4885 value = xmlXPathVariableLookup(ctxt->context, name);
4886 } else {
4887 TODO;
4888 value = NULL;
4889 }
4890 xmlFree(name);
4891 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004892 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004893 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004894 }
4895 valuePush(ctxt, value);
Daniel Veillard55b91f22000-10-05 16:30:11 +00004896 SKIP_BLANKS;
4897}
4898
4899/**
4900 * xmlXPathIsNodeType:
4901 * @ctxt: the XPath Parser context
4902 * @name: a name string
4903 *
4904 * Is the name given a NodeType one.
4905 *
4906 * [38] NodeType ::= 'comment'
4907 * | 'text'
4908 * | 'processing-instruction'
4909 * | 'node'
4910 *
4911 * Returns 1 if true 0 otherwise
4912 */
4913int
4914xmlXPathIsNodeType(const xmlChar *name) {
4915 if (name == NULL)
4916 return(0);
4917
4918 if (xmlStrEqual(name, BAD_CAST "comment"))
4919 return(1);
4920 if (xmlStrEqual(name, BAD_CAST "text"))
4921 return(1);
4922 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4923 return(1);
4924 if (xmlStrEqual(name, BAD_CAST "node"))
4925 return(1);
4926 return(0);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004927}
4928
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004929/**
4930 * xmlXPathEvalFunctionCall:
4931 * @ctxt: the XPath Parser context
4932 *
4933 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4934 * [17] Argument ::= Expr
4935 *
4936 * Parse and evaluate a function call, the evaluation of all arguments are
4937 * pushed on the stack
4938 */
4939void
4940xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004941 xmlChar *name;
4942 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004943 xmlXPathFunction func;
4944 int nbargs = 0;
4945
4946 name = xmlXPathParseQName(ctxt, &prefix);
4947 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004948 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004949 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004950 SKIP_BLANKS;
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004951 if (prefix == NULL) {
4952 func = xmlXPathFunctionLookup(ctxt->context, name);
4953 } else {
4954 TODO;
4955 func = NULL;
4956 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004957 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004958 xmlFree(name);
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004959 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004960 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004961 }
4962#ifdef DEBUG_EXPR
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004963 if (prefix == NULL)
4964 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
4965 name);
4966 else
4967 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
4968 prefix, name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004969#endif
4970
Daniel Veillarda5db68a2000-10-29 18:06:06 +00004971 xmlFree(name);
4972 if (prefix != NULL) xmlFree(prefix);
4973
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004974 if (CUR != '(') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004975 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004976 }
4977 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004978 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004979
4980 while (CUR != ')') {
4981 xmlXPathEvalExpr(ctxt);
4982 nbargs++;
4983 if (CUR == ')') break;
4984 if (CUR != ',') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004985 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004986 }
4987 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004988 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004989 }
4990 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004991 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004992 func(ctxt, nbargs);
4993}
4994
4995/**
4996 * xmlXPathEvalPrimaryExpr:
4997 * @ctxt: the XPath Parser context
4998 *
4999 * [15] PrimaryExpr ::= VariableReference
5000 * | '(' Expr ')'
5001 * | Literal
5002 * | Number
5003 * | FunctionCall
5004 *
5005 * Parse and evaluate a primary expression, then push the result on the stack
5006 */
5007void
5008xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00005009 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005010 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
5011 else if (CUR == '(') {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005012 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005013 SKIP_BLANKS;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005014 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005015 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005016 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005017 }
5018 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005019 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005020 } else if (IS_DIGIT(CUR)) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005021 xmlXPathEvalNumber(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005022 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005023 xmlXPathEvalLiteral(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005024 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005025 xmlXPathEvalFunctionCall(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005026 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005027 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005028}
5029
5030/**
5031 * xmlXPathEvalFilterExpr:
5032 * @ctxt: the XPath Parser context
5033 *
5034 * [20] FilterExpr ::= PrimaryExpr
5035 * | FilterExpr Predicate
5036 *
5037 * Parse and evaluate a filter expression, then push the result on the stack
5038 * Square brackets are used to filter expressions in the same way that
5039 * they are used in location paths. It is an error if the expression to
5040 * be filtered does not evaluate to a node-set. The context node list
5041 * used for evaluating the expression in square brackets is the node-set
5042 * to be filtered listed in document order.
5043 */
5044
5045void
5046xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005047 xmlXPathEvalPrimaryExpr(ctxt);
5048 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005049 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005050
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005051 while (CUR == '[') {
Daniel Veillardf62ceff2000-11-24 23:36:01 +00005052 if ((ctxt->value == NULL) ||
5053 ((ctxt->value->type != XPATH_NODESET) &&
5054 (ctxt->value->type != XPATH_LOCATIONSET)))
5055 XP_ERROR(XPATH_INVALID_TYPE)
5056
5057 if (ctxt->value->type == XPATH_NODESET)
5058 xmlXPathEvalPredicate(ctxt);
5059 else
5060 xmlXPtrEvalRangePredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005061 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005062 }
5063
5064
5065}
5066
5067/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00005068 * xmlXPathScanName:
5069 * @ctxt: the XPath Parser context
5070 *
5071 * Trickery: parse an XML name but without consuming the input flow
Daniel Veillard55b91f22000-10-05 16:30:11 +00005072 * Needed to avoid insanity in the parser state.
Daniel Veillardb96e6431999-08-29 21:02:19 +00005073 *
5074 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5075 * CombiningChar | Extender
5076 *
5077 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5078 *
5079 * [6] Names ::= Name (S Name)*
5080 *
5081 * Returns the Name parsed or NULL
5082 */
5083
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005084xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00005085xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005086 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00005087 int len = 0;
5088
Daniel Veillard00fdf371999-10-08 09:40:39 +00005089 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005090 if (!IS_LETTER(CUR) && (CUR != '_') &&
5091 (CUR != ':')) {
5092 return(NULL);
5093 }
5094
5095 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5096 (NXT(len) == '.') || (NXT(len) == '-') ||
5097 (NXT(len) == '_') || (NXT(len) == ':') ||
5098 (IS_COMBINING(NXT(len))) ||
5099 (IS_EXTENDER(NXT(len)))) {
5100 buf[len] = NXT(len);
5101 len++;
5102 if (len >= XML_MAX_NAMELEN) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005103 xmlGenericError(xmlGenericErrorContext,
Daniel Veillardb96e6431999-08-29 21:02:19 +00005104 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
5105 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
5106 (NXT(len) == '.') || (NXT(len) == '-') ||
5107 (NXT(len) == '_') || (NXT(len) == ':') ||
5108 (IS_COMBINING(NXT(len))) ||
5109 (IS_EXTENDER(NXT(len))))
5110 len++;
5111 break;
5112 }
5113 }
5114 return(xmlStrndup(buf, len));
5115}
5116
5117/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005118 * xmlXPathEvalPathExpr:
5119 * @ctxt: the XPath Parser context
5120 *
5121 * [19] PathExpr ::= LocationPath
5122 * | FilterExpr
5123 * | FilterExpr '/' RelativeLocationPath
5124 * | FilterExpr '//' RelativeLocationPath
5125 *
5126 * Parse and evaluate a path expression, then push the result on the stack
5127 * The / operator and // operators combine an arbitrary expression
5128 * and a relative location path. It is an error if the expression
5129 * does not evaluate to a node-set.
5130 * The / operator does composition in the same way as when / is
5131 * used in a location path. As in location paths, // is short for
5132 * /descendant-or-self::node()/.
5133 */
5134
5135void
5136xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005137 int lc = 1; /* Should we branch to LocationPath ? */
5138 xmlChar *name = NULL; /* we may have to preparse a name to find out */
5139
Daniel Veillard00fdf371999-10-08 09:40:39 +00005140 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005141 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
5142 (CUR == '\'') || (CUR == '"')) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005143 lc = 0;
5144 } else if (CUR == '/') {
5145 /* relative or absolute location path */
5146 lc = 1;
5147 } else if (CUR == '@') {
5148 /* relative abbreviated attribute location path */
5149 lc = 1;
5150 } else if (CUR == '.') {
5151 /* relative abbreviated attribute location path */
5152 lc = 1;
5153 } else {
5154 /*
5155 * Problem is finding if we have a name here whether it's:
5156 * - a nodetype
5157 * - a function call in which case it's followed by '('
5158 * - an axis in which case it's followed by ':'
5159 * - a element name
5160 * We do an a priori analysis here rather than having to
5161 * maintain parsed token content through the recursive function
5162 * calls. This looks uglier but makes the code quite easier to
5163 * read/write/debug.
5164 */
5165 SKIP_BLANKS;
5166 name = xmlXPathScanName(ctxt);
5167 if (name != NULL) {
5168 int len =xmlStrlen(name);
5169 int blank = 0;
5170
5171 while (NXT(len) != 0) {
5172 if (NXT(len) == '/') {
5173 /* element name */
5174#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005175 xmlGenericError(xmlGenericErrorContext,
5176 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005177#endif
5178 lc = 1;
5179 break;
5180 } else if (IS_BLANK(NXT(len))) {
5181 /* skip to next */
5182 blank = 1;
5183 } else if (NXT(len) == ':') {
5184#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005185 xmlGenericError(xmlGenericErrorContext,
5186 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005187#endif
5188 lc = 1;
5189 break;
5190 } else if ((NXT(len) == '(')) {
5191 /* Note Type or Function */
5192 if (xmlXPathIsNodeType(name)) {
5193#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005194 xmlGenericError(xmlGenericErrorContext,
5195 "PathExpr: Type search\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005196#endif
5197 lc = 1;
5198 } else {
5199#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005200 xmlGenericError(xmlGenericErrorContext,
5201 "PathExpr: function call\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005202#endif
5203 lc = 0;
5204 }
5205 break;
5206 } else if ((NXT(len) == '[')) {
5207 /* element name */
5208#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005209 xmlGenericError(xmlGenericErrorContext,
5210 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005211#endif
5212 lc = 1;
5213 break;
Daniel Veillard389e6b72001-01-15 19:41:13 +00005214 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
5215 (NXT(len) == '=')) {
5216 lc = 1;
5217 break;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005218 } else {
Daniel Veillardf6eea272001-01-18 12:17:12 +00005219 lc = 1;
5220 break;
Daniel Veillard55b91f22000-10-05 16:30:11 +00005221 }
5222 len++;
5223 }
5224 if (NXT(len) == 0) {
5225#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005226 xmlGenericError(xmlGenericErrorContext,
5227 "PathExpr: AbbrRelLocation\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00005228#endif
5229 /* element name */
5230 lc = 1;
5231 }
5232 xmlFree(name);
5233 } else {
5234 /* make sure all cases are covered explicitely */
5235 XP_ERROR(XPATH_EXPR_ERROR);
5236 }
5237 }
5238
5239 if (lc) {
Daniel Veillardc4f4f0b2000-10-29 17:46:30 +00005240 if (CUR == '/')
5241 xmlXPathRoot(ctxt);
Daniel Veillard5a2b6972001-01-20 21:15:50 +00005242 else {
5243 /* TAG:9999 */
5244 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5245 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005246 xmlXPathEvalLocationPath(ctxt);
5247 } else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005248 xmlXPathEvalFilterExpr(ctxt);
5249 CHECK_ERROR;
5250 if ((CUR == '/') && (NXT(1) == '/')) {
5251 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005252 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00005253 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00005254 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005255 ctxt->context->node = NULL;
5256 xmlXPathEvalRelativeLocationPath(ctxt);
5257 } else if (CUR == '/') {
5258 xmlXPathEvalRelativeLocationPath(ctxt);
5259 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005260 }
5261 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005262}
5263
5264/**
5265 * xmlXPathEvalUnionExpr:
5266 * @ctxt: the XPath Parser context
5267 *
5268 * [18] UnionExpr ::= PathExpr
5269 * | UnionExpr '|' PathExpr
5270 *
5271 * Parse and evaluate an union expression, then push the result on the stack
5272 */
5273
5274void
5275xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillardf41fbbf2001-02-13 17:05:35 +00005276 int sort = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005277 xmlXPathEvalPathExpr(ctxt);
5278 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005279 SKIP_BLANKS;
Daniel Veillard08108982001-01-03 15:24:58 +00005280 while (CUR == '|') {
5281 xmlXPathObjectPtr obj1,obj2, tmp;
Daniel Veillard740abf52000-10-02 23:04:54 +00005282
Daniel Veillardf41fbbf2001-02-13 17:05:35 +00005283 sort = 1;
Daniel Veillard740abf52000-10-02 23:04:54 +00005284 CHECK_TYPE(XPATH_NODESET);
5285 obj1 = valuePop(ctxt);
Daniel Veillard08108982001-01-03 15:24:58 +00005286 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5287 valuePush(ctxt, tmp);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005288
Daniel Veillard00fdf371999-10-08 09:40:39 +00005289 NEXT;
5290 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005291 xmlXPathEvalPathExpr(ctxt);
5292
Daniel Veillard740abf52000-10-02 23:04:54 +00005293 CHECK_TYPE(XPATH_NODESET);
5294 obj2 = valuePop(ctxt);
5295 obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
5296 obj2->nodesetval);
Daniel Veillard08108982001-01-03 15:24:58 +00005297 if (ctxt->value == tmp) {
5298 tmp = valuePop(ctxt);
5299 xmlXPathFreeObject(tmp);
5300 }
Daniel Veillard9e8bfae2000-11-06 16:43:11 +00005301 valuePush(ctxt, obj1);
Daniel Veillard740abf52000-10-02 23:04:54 +00005302 xmlXPathFreeObject(obj2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005303 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005304 }
Daniel Veillardf41fbbf2001-02-13 17:05:35 +00005305 if (sort) {
5306 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005307}
5308
5309/**
5310 * xmlXPathEvalUnaryExpr:
5311 * @ctxt: the XPath Parser context
5312 *
5313 * [27] UnaryExpr ::= UnionExpr
5314 * | '-' UnaryExpr
5315 *
5316 * Parse and evaluate an unary expression, then push the result on the stack
5317 */
5318
5319void
5320xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
5321 int minus = 0;
5322
Daniel Veillard00fdf371999-10-08 09:40:39 +00005323 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005324 if (CUR == '-') {
5325 minus = 1;
5326 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005327 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005328 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00005329 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005330 CHECK_ERROR;
5331 if (minus) {
5332 xmlXPathValueFlipSign(ctxt);
5333 }
5334}
5335
5336/**
5337 * xmlXPathEvalMultiplicativeExpr:
5338 * @ctxt: the XPath Parser context
5339 *
5340 * [26] MultiplicativeExpr ::= UnaryExpr
5341 * | MultiplicativeExpr MultiplyOperator UnaryExpr
5342 * | MultiplicativeExpr 'div' UnaryExpr
5343 * | MultiplicativeExpr 'mod' UnaryExpr
5344 * [34] MultiplyOperator ::= '*'
5345 *
5346 * Parse and evaluate an Additive expression, then push the result on the stack
5347 */
5348
5349void
5350xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
5351 xmlXPathEvalUnaryExpr(ctxt);
5352 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005353 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005354 while ((CUR == '*') ||
5355 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
5356 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
5357 int op = -1;
5358
5359 if (CUR == '*') {
5360 op = 0;
5361 NEXT;
5362 } else if (CUR == 'd') {
5363 op = 1;
5364 SKIP(3);
5365 } else if (CUR == 'm') {
5366 op = 2;
5367 SKIP(3);
5368 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00005369 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005370 xmlXPathEvalUnaryExpr(ctxt);
5371 CHECK_ERROR;
5372 switch (op) {
5373 case 0:
5374 xmlXPathMultValues(ctxt);
5375 break;
5376 case 1:
5377 xmlXPathDivValues(ctxt);
5378 break;
5379 case 2:
5380 xmlXPathModValues(ctxt);
5381 break;
5382 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005383 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005384 }
5385}
5386
5387/**
5388 * xmlXPathEvalAdditiveExpr:
5389 * @ctxt: the XPath Parser context
5390 *
5391 * [25] AdditiveExpr ::= MultiplicativeExpr
5392 * | AdditiveExpr '+' MultiplicativeExpr
5393 * | AdditiveExpr '-' MultiplicativeExpr
5394 *
5395 * Parse and evaluate an Additive expression, then push the result on the stack
5396 */
5397
5398void
5399xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
5400 xmlXPathEvalMultiplicativeExpr(ctxt);
5401 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005402 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005403 while ((CUR == '+') || (CUR == '-')) {
5404 int plus;
5405
5406 if (CUR == '+') plus = 1;
5407 else plus = 0;
5408 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005409 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005410 xmlXPathEvalMultiplicativeExpr(ctxt);
5411 CHECK_ERROR;
5412 if (plus) xmlXPathAddValues(ctxt);
5413 else xmlXPathSubValues(ctxt);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005414 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005415 }
5416}
5417
5418/**
5419 * xmlXPathEvalRelationalExpr:
5420 * @ctxt: the XPath Parser context
5421 *
5422 * [24] RelationalExpr ::= AdditiveExpr
5423 * | RelationalExpr '<' AdditiveExpr
5424 * | RelationalExpr '>' AdditiveExpr
5425 * | RelationalExpr '<=' AdditiveExpr
5426 * | RelationalExpr '>=' AdditiveExpr
5427 *
5428 * A <= B > C is allowed ? Answer from James, yes with
5429 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
5430 * which is basically what got implemented.
5431 *
5432 * Parse and evaluate a Relational expression, then push the result
5433 * on the stack
5434 */
5435
5436void
5437xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
5438 xmlXPathEvalAdditiveExpr(ctxt);
5439 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005440 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005441 while ((CUR == '<') ||
5442 (CUR == '>') ||
5443 ((CUR == '<') && (NXT(1) == '=')) ||
5444 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00005445 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005446
5447 if (CUR == '<') inf = 1;
5448 else inf = 0;
5449 if (NXT(1) == '=') strict = 0;
5450 else strict = 1;
5451 NEXT;
5452 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005453 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005454 xmlXPathEvalAdditiveExpr(ctxt);
5455 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00005456 ret = xmlXPathCompareValues(ctxt, inf, strict);
5457 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard55b91f22000-10-05 16:30:11 +00005458 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005459 }
5460}
5461
5462/**
5463 * xmlXPathEvalEqualityExpr:
5464 * @ctxt: the XPath Parser context
5465 *
5466 * [23] EqualityExpr ::= RelationalExpr
5467 * | EqualityExpr '=' RelationalExpr
5468 * | EqualityExpr '!=' RelationalExpr
5469 *
5470 * A != B != C is allowed ? Answer from James, yes with
5471 * (RelationalExpr = RelationalExpr) = RelationalExpr
5472 * (RelationalExpr != RelationalExpr) != RelationalExpr
5473 * which is basically what got implemented.
5474 *
5475 * Parse and evaluate an Equality expression, then push the result on the stack
5476 *
5477 */
5478void
5479xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
5480 xmlXPathEvalRelationalExpr(ctxt);
5481 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005482 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005483 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00005484 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005485 int eq, equal;
5486
5487 if (CUR == '=') eq = 1;
5488 else eq = 0;
5489 NEXT;
5490 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005491 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005492 xmlXPathEvalRelationalExpr(ctxt);
5493 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00005494 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005495 if (eq) res = xmlXPathNewBoolean(equal);
5496 else res = xmlXPathNewBoolean(!equal);
5497 valuePush(ctxt, res);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005498 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005499 }
5500}
5501
5502/**
5503 * xmlXPathEvalAndExpr:
5504 * @ctxt: the XPath Parser context
5505 *
5506 * [22] AndExpr ::= EqualityExpr
5507 * | AndExpr 'and' EqualityExpr
5508 *
5509 * Parse and evaluate an AND expression, then push the result on the stack
5510 *
5511 */
5512void
5513xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
5514 xmlXPathEvalEqualityExpr(ctxt);
5515 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005516 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00005517 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005518 xmlXPathObjectPtr arg1, arg2;
5519
5520 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005521 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005522 xmlXPathEvalEqualityExpr(ctxt);
5523 CHECK_ERROR;
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005524 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005525 arg2 = valuePop(ctxt);
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005526 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005527 arg1 = valuePop(ctxt);
5528 arg1->boolval &= arg2->boolval;
5529 valuePush(ctxt, arg1);
5530 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005531 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005532 }
5533}
5534
5535/**
5536 * xmlXPathEvalExpr:
5537 * @ctxt: the XPath Parser context
5538 *
5539 * [14] Expr ::= OrExpr
5540 * [21] OrExpr ::= AndExpr
5541 * | OrExpr 'or' AndExpr
5542 *
5543 * Parse and evaluate an expression, then push the result on the stack
5544 *
5545 */
5546void
5547xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
5548 xmlXPathEvalAndExpr(ctxt);
5549 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005550 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005551 while ((CUR == 'o') && (NXT(1) == 'r')) {
5552 xmlXPathObjectPtr arg1, arg2;
5553
5554 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00005555 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005556 xmlXPathEvalAndExpr(ctxt);
5557 CHECK_ERROR;
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005558 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005559 arg2 = valuePop(ctxt);
Daniel Veillard0f2a53c2001-02-05 17:57:33 +00005560 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005561 arg1 = valuePop(ctxt);
5562 arg1->boolval |= arg2->boolval;
5563 valuePush(ctxt, arg1);
5564 xmlXPathFreeObject(arg2);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005565 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005566 }
Daniel Veillardf41fbbf2001-02-13 17:05:35 +00005567 if ((ctxt->value != NULL) && (ctxt->value->type == XPATH_NODESET) &&
5568 (ctxt->value->nodesetval != NULL))
5569 xmlXPathNodeSetSort(ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005570}
5571
5572/**
5573 * xmlXPathEvaluatePredicateResult:
5574 * @ctxt: the XPath Parser context
5575 * @res: the Predicate Expression evaluation result
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005576 *
5577 * Evaluate a predicate result for the current node.
5578 * A PredicateExpr is evaluated by evaluating the Expr and converting
5579 * the result to a boolean. If the result is a number, the result will
5580 * be converted to true if the number is equal to the position of the
5581 * context node in the context node list (as returned by the position
5582 * function) and will be converted to false otherwise; if the result
5583 * is not a number, then the result will be converted as if by a call
5584 * to the boolean function.
Daniel Veillard2c833b62001-02-03 08:52:06 +00005585 *
5586 * Return 1 if predicate is true, 0 otherwise
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005587 */
5588int
5589xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005590 xmlXPathObjectPtr res) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005591 if (res == NULL) return(0);
5592 switch (res->type) {
5593 case XPATH_BOOLEAN:
5594 return(res->boolval);
5595 case XPATH_NUMBER:
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005596 return(res->floatval == ctxt->context->proximityPosition);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005597 case XPATH_NODESET:
Daniel Veillarde99a4762001-02-01 04:34:35 +00005598 case XPATH_XSLT_TREE:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005599 return(res->nodesetval->nodeNr != 0);
5600 case XPATH_STRING:
5601 return((res->stringval != NULL) &&
5602 (xmlStrlen(res->stringval) != 0));
5603 default:
5604 STRANGE
5605 }
5606 return(0);
5607}
5608
5609/**
5610 * xmlXPathEvalPredicate:
5611 * @ctxt: the XPath Parser context
5612 *
5613 * [8] Predicate ::= '[' PredicateExpr ']'
5614 * [9] PredicateExpr ::= Expr
5615 *
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005616 * ---------------------
5617 * For each node in the node-set to be filtered, the PredicateExpr is
5618 * evaluated with that node as the context node, with the number of nodes
5619 * in the node-set as the context size, and with the proximity position
5620 * of the node in the node-set with respect to the axis as the context
5621 * position; if PredicateExpr evaluates to true for that node, the node
5622 * is included in the new node-set; otherwise, it is not included.
5623 * ---------------------
5624 *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005625 * Parse and evaluate a predicate for all the elements of the
5626 * current node list. Then refine the list by removing all
5627 * nodes where the predicate is false.
5628 */
5629void
5630xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00005631 const xmlChar *cur;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005632 xmlXPathObjectPtr res;
Daniel Veillard740abf52000-10-02 23:04:54 +00005633 xmlXPathObjectPtr obj, tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005634 xmlNodeSetPtr newset = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005635 xmlNodeSetPtr oldset;
Daniel Veillardf41fbbf2001-02-13 17:05:35 +00005636 xmlNodePtr oldnode;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005637 int i;
5638
Daniel Veillard00fdf371999-10-08 09:40:39 +00005639 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005640 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005641 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005642 }
5643 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005644 SKIP_BLANKS;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005645
5646 /*
5647 * Extract the old set, and then evaluate the result of the
5648 * expression for all the element in the set. use it to grow
5649 * up a new set.
5650 */
Daniel Veillard740abf52000-10-02 23:04:54 +00005651 CHECK_TYPE(XPATH_NODESET);
5652 obj = valuePop(ctxt);
5653 oldset = obj->nodesetval;
Daniel Veillardf41fbbf2001-02-13 17:05:35 +00005654 oldnode = ctxt->context->node;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005655 ctxt->context->node = NULL;
5656
5657 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005658 ctxt->context->contextSize = 0;
5659 ctxt->context->proximityPosition = 0;
Daniel Veillardff9c3302000-10-13 16:38:25 +00005660 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005661 res = valuePop(ctxt);
5662 if (res != NULL)
5663 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005664 valuePush(ctxt, obj);
Daniel Veillardff9c3302000-10-13 16:38:25 +00005665 CHECK_ERROR;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005666 } else {
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005667 /*
5668 * Save the expression pointer since we will have to evaluate
5669 * it multiple times. Initialize the new set.
5670 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005671 cur = ctxt->cur;
5672 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00005673
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005674 for (i = 0; i < oldset->nodeNr; i++) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005675 ctxt->cur = cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00005676
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005677 /*
5678 * Run the evaluation with a node list made of a single item
5679 * in the nodeset.
5680 */
5681 ctxt->context->node = oldset->nodeTab[i];
Daniel Veillard740abf52000-10-02 23:04:54 +00005682 tmp = xmlXPathNewNodeSet(ctxt->context->node);
5683 valuePush(ctxt, tmp);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005684 ctxt->context->contextSize = oldset->nodeNr;
5685 ctxt->context->proximityPosition = i + 1;
Daniel Veillardbe803962000-06-28 23:40:59 +00005686
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005687 xmlXPathEvalExpr(ctxt);
5688 CHECK_ERROR;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005689
5690 /*
5691 * The result of the evaluation need to be tested to
5692 * decided whether the filter succeeded or not
5693 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005694 res = valuePop(ctxt);
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005695 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
5696 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
5697 }
Daniel Veillard740abf52000-10-02 23:04:54 +00005698
5699 /*
5700 * Cleanup
5701 */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005702 if (res != NULL)
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005703 xmlXPathFreeObject(res);
Daniel Veillard740abf52000-10-02 23:04:54 +00005704 if (ctxt->value == tmp) {
5705 res = valuePop(ctxt);
5706 xmlXPathFreeObject(res);
5707 }
Daniel Veillardbe803962000-06-28 23:40:59 +00005708
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005709 ctxt->context->node = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005710 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005711
5712 /*
5713 * The result is used as the new evaluation set.
5714 */
Daniel Veillard740abf52000-10-02 23:04:54 +00005715 xmlXPathFreeObject(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005716 ctxt->context->node = NULL;
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005717 ctxt->context->contextSize = -1;
5718 ctxt->context->proximityPosition = -1;
Daniel Veillard740abf52000-10-02 23:04:54 +00005719 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005720 }
5721 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00005722 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005723 }
Daniel Veillardf09e7e32000-10-01 15:53:30 +00005724
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005725 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00005726 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005727#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00005728 xmlGenericError(xmlGenericErrorContext, "After predicate : ");
5729 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
5730 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005731#endif
Daniel Veillardf41fbbf2001-02-13 17:05:35 +00005732 ctxt->context->node = oldnode;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005733}
5734
5735/**
Daniel Veillard55b91f22000-10-05 16:30:11 +00005736 * xmlXPathEvalNodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005737 * @ctxt: the XPath Parser context
Daniel Veillard55b91f22000-10-05 16:30:11 +00005738 * @test: pointer to a xmlXPathTestVal
5739 * @type: pointer to a xmlXPathTypeVal
5740 * @prefix: placeholder for a possible name prefix
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005741 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005742 * [7] NodeTest ::= NameTest
5743 * | NodeType '(' ')'
5744 * | 'processing-instruction' '(' Literal ')'
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005745 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005746 * [37] NameTest ::= '*'
5747 * | NCName ':' '*'
5748 * | QName
5749 * [38] NodeType ::= 'comment'
5750 * | 'text'
5751 * | 'processing-instruction'
5752 * | 'node'
5753 *
5754 * Returns the name found and update @test, @type and @prefix appropriately
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005755 */
Daniel Veillard55b91f22000-10-05 16:30:11 +00005756xmlChar *
5757xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005758 xmlXPathTypeVal *type, const xmlChar **prefix, xmlChar *name) {
Daniel Veillard55b91f22000-10-05 16:30:11 +00005759 int blanks;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005760
Daniel Veillard55b91f22000-10-05 16:30:11 +00005761 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
5762 STRANGE;
5763 return(NULL);
5764 }
5765 *type = 0;
5766 *test = 0;
5767 *prefix = NULL;
5768 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00005769
Daniel Veillard55b91f22000-10-05 16:30:11 +00005770 if ((name == NULL) && (CUR == '*')) {
5771 /*
5772 * All elements
5773 */
5774 NEXT;
5775 *test = NODE_TEST_ALL;
5776 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005777 }
5778
Daniel Veillard55b91f22000-10-05 16:30:11 +00005779 if (name == NULL)
5780 name = xmlXPathParseNCName(ctxt);
5781 if (name == NULL) {
5782 XP_ERROR0(XPATH_EXPR_ERROR);
5783 }
5784
5785 blanks = IS_BLANK(CUR);
5786 SKIP_BLANKS;
5787 if (CUR == '(') {
5788 NEXT;
5789 /*
5790 * NodeType or PI search
5791 */
5792 if (xmlStrEqual(name, BAD_CAST "comment"))
5793 *type = NODE_TYPE_COMMENT;
5794 else if (xmlStrEqual(name, BAD_CAST "node"))
5795 *type = NODE_TYPE_NODE;
5796 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5797 *type = NODE_TYPE_PI;
5798 else if (xmlStrEqual(name, BAD_CAST "text"))
5799 *type = NODE_TYPE_TEXT;
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005800 else {
5801 if (name != NULL)
5802 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005803 XP_ERROR0(XPATH_EXPR_ERROR);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005804 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005805
5806 *test = NODE_TEST_TYPE;
5807
5808 SKIP_BLANKS;
5809 if (*type == NODE_TYPE_PI) {
5810 /*
5811 * Specific case: search a PI by name.
5812 */
5813 xmlXPathObjectPtr cur;
5814
5815 if (name != NULL)
5816 xmlFree(name);
5817
5818 xmlXPathEvalLiteral(ctxt);
5819 CHECK_ERROR 0;
5820 xmlXPathStringFunction(ctxt, 1);
5821 CHECK_ERROR0;
5822 cur = valuePop(ctxt);
5823 name = xmlStrdup(cur->stringval);
5824 xmlXPathFreeObject(cur);
5825 SKIP_BLANKS;
5826 }
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005827 if (CUR != ')') {
5828 if (name != NULL)
5829 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00005830 XP_ERROR0(XPATH_UNCLOSED_ERROR);
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005831 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005832 NEXT;
5833 return(name);
5834 }
5835 *test = NODE_TEST_NAME;
5836 if ((!blanks) && (CUR == ':')) {
5837 NEXT;
5838
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00005839 /*
5840 * get the namespace name for this prefix
5841 */
5842 *prefix = xmlXPathNsLookup(ctxt->context, name);
5843 if (name != NULL)
5844 xmlFree(name);
5845 if (*prefix == NULL) {
5846 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
5847 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00005848
5849 if (CUR == '*') {
5850 /*
5851 * All elements
5852 */
5853 NEXT;
5854 *test = NODE_TEST_ALL;
5855 return(NULL);
5856 }
5857
5858 name = xmlXPathParseNCName(ctxt);
5859 if (name == NULL) {
5860 XP_ERROR0(XPATH_EXPR_ERROR);
5861 }
5862 }
5863 return(name);
5864}
5865
5866/**
5867 * xmlXPathIsAxisName:
5868 * @name: a preparsed name token
5869 *
5870 * [6] AxisName ::= 'ancestor'
5871 * | 'ancestor-or-self'
5872 * | 'attribute'
5873 * | 'child'
5874 * | 'descendant'
5875 * | 'descendant-or-self'
5876 * | 'following'
5877 * | 'following-sibling'
5878 * | 'namespace'
5879 * | 'parent'
5880 * | 'preceding'
5881 * | 'preceding-sibling'
5882 * | 'self'
5883 *
5884 * Returns the axis or 0
5885 */
5886xmlXPathAxisVal
5887xmlXPathIsAxisName(const xmlChar *name) {
5888 xmlXPathAxisVal ret = 0;
5889 switch (name[0]) {
5890 case 'a':
5891 if (xmlStrEqual(name, BAD_CAST "ancestor"))
5892 ret = AXIS_ANCESTOR;
5893 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
5894 ret = AXIS_ANCESTOR_OR_SELF;
5895 if (xmlStrEqual(name, BAD_CAST "attribute"))
5896 ret = AXIS_ATTRIBUTE;
5897 break;
5898 case 'c':
5899 if (xmlStrEqual(name, BAD_CAST "child"))
5900 ret = AXIS_CHILD;
5901 break;
5902 case 'd':
5903 if (xmlStrEqual(name, BAD_CAST "descendant"))
5904 ret = AXIS_DESCENDANT;
5905 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
5906 ret = AXIS_DESCENDANT_OR_SELF;
5907 break;
5908 case 'f':
5909 if (xmlStrEqual(name, BAD_CAST "following"))
5910 ret = AXIS_FOLLOWING;
5911 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
5912 ret = AXIS_FOLLOWING_SIBLING;
5913 break;
5914 case 'n':
5915 if (xmlStrEqual(name, BAD_CAST "namespace"))
5916 ret = AXIS_NAMESPACE;
5917 break;
5918 case 'p':
5919 if (xmlStrEqual(name, BAD_CAST "parent"))
5920 ret = AXIS_PARENT;
5921 if (xmlStrEqual(name, BAD_CAST "preceding"))
5922 ret = AXIS_PRECEDING;
5923 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
5924 ret = AXIS_PRECEDING_SIBLING;
5925 break;
5926 case 's':
5927 if (xmlStrEqual(name, BAD_CAST "self"))
5928 ret = AXIS_SELF;
5929 break;
5930 }
5931 return(ret);
5932}
5933
5934/**
5935 * xmlXPathEvalAxisSpecifier:
5936 * @ctxt: the XPath Parser context
5937 *
5938 *
5939 * Returns the axis found
5940 */
5941xmlXPathAxisVal
5942xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
5943 xmlXPathAxisVal ret = AXIS_CHILD;
5944 int blank = 0;
5945 xmlChar *name;
5946
5947 if (CUR == '@') {
5948 NEXT;
5949 return(AXIS_ATTRIBUTE);
5950 } else {
5951 name = xmlXPathParseNCName(ctxt);
5952 if (name == NULL) {
5953 XP_ERROR0(XPATH_EXPR_ERROR);
5954 }
5955 if (IS_BLANK(CUR))
5956 blank = 1;
5957 SKIP_BLANKS;
5958 if ((CUR == ':') && (NXT(1) == ':')) {
5959 ret = xmlXPathIsAxisName(name);
5960 } else if ((blank) && (CUR == ':'))
5961 XP_ERROR0(XPATH_EXPR_ERROR);
5962
5963 xmlFree(name);
5964 }
5965 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005966}
5967
5968/**
5969 * xmlXPathEvalStep:
5970 * @ctxt: the XPath Parser context
5971 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005972 * [4] Step ::= AxisSpecifier NodeTest Predicate*
5973 * | AbbreviatedStep
Daniel Veillardac260302000-10-04 13:33:43 +00005974 *
Daniel Veillard55b91f22000-10-05 16:30:11 +00005975 * [12] AbbreviatedStep ::= '.' | '..'
5976 *
5977 * [5] AxisSpecifier ::= AxisName '::'
5978 * | AbbreviatedAxisSpecifier
5979 *
5980 * [13] AbbreviatedAxisSpecifier ::= '@'?
Daniel Veillardac260302000-10-04 13:33:43 +00005981 *
5982 * Modified for XPtr range support as:
5983 *
5984 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5985 * | AbbreviatedStep
5986 * | 'range-to' '(' Expr ')' Predicate*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00005987 *
5988 * Evaluate one step in a Location Path
5989 * A location step of . is short for self::node(). This is
5990 * particularly useful in conjunction with //. For example, the
5991 * location path .//para is short for
5992 * self::node()/descendant-or-self::node()/child::para
5993 * and so will select all para descendant elements of the context
5994 * node.
5995 * Similarly, a location step of .. is short for parent::node().
5996 * For example, ../title is short for parent::node()/child::title
5997 * and so will select the title children of the parent of the context
5998 * node.
5999 */
6000void
6001xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00006002 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006003 if ((CUR == '.') && (NXT(1) == '.')) {
6004 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006005 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00006006 xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
Daniel Veillard767662d2000-10-27 17:04:52 +00006007 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006008 } else if (CUR == '.') {
6009 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00006010 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006011 } else {
Daniel Veillard55b91f22000-10-05 16:30:11 +00006012 xmlChar *name = NULL;
Daniel Veillarda6d8eb62000-12-27 10:46:47 +00006013 const xmlChar *prefix = NULL;
Daniel Veillard55b91f22000-10-05 16:30:11 +00006014 xmlXPathTestVal test;
6015 xmlXPathAxisVal axis;
6016 xmlXPathTypeVal type;
6017
6018 /*
6019 * The modification needed for XPointer change to the production
6020 */
Daniel Veillardac260302000-10-04 13:33:43 +00006021#ifdef LIBXML_XPTR_ENABLED
Daniel Veillard55b91f22000-10-05 16:30:11 +00006022 if (ctxt->context->xptr) {
6023 name = xmlXPathParseNCName(ctxt);
6024 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
6025 xmlFree(name);
6026 SKIP_BLANKS;
6027 if (CUR != '(') {
6028 XP_ERROR(XPATH_EXPR_ERROR);
6029 }
6030 NEXT;
6031 SKIP_BLANKS;
Daniel Veillardac260302000-10-04 13:33:43 +00006032
Daniel Veillard55b91f22000-10-05 16:30:11 +00006033 xmlXPtrRangeToFunction(ctxt, 1);
Daniel Veillardac260302000-10-04 13:33:43 +00006034 CHECK_ERROR;
6035
Daniel Veillard55b91f22000-10-05 16:30:11 +00006036 SKIP_BLANKS;
6037 if (CUR != ')') {
6038 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardac260302000-10-04 13:33:43 +00006039 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00006040 NEXT;
6041 goto eval_predicates;
Daniel Veillardac260302000-10-04 13:33:43 +00006042 }
Daniel Veillardac260302000-10-04 13:33:43 +00006043 }
Daniel Veillard55b91f22000-10-05 16:30:11 +00006044#endif
6045 if (name == NULL)
6046 name = xmlXPathParseNCName(ctxt);
6047 if (name != NULL) {
6048 axis = xmlXPathIsAxisName(name);
6049 if (axis != 0) {
6050 SKIP_BLANKS;
6051 if ((CUR == ':') && (NXT(1) == ':')) {
6052 SKIP(2);
6053 xmlFree(name);
6054 name = NULL;
6055 } else {
6056 /* an element name can conflict with an axis one :-\ */
6057 axis = AXIS_CHILD;
6058 }
6059 } else {
6060 axis = AXIS_CHILD;
6061 }
6062 } else if (CUR == '@') {
6063 NEXT;
6064 axis = AXIS_ATTRIBUTE;
6065 } else {
6066 axis = AXIS_CHILD;
6067 }
6068
6069 CHECK_ERROR;
6070
6071 name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
6072 if (test == 0)
6073 return;
6074
6075#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006076 xmlGenericError(xmlGenericErrorContext,
6077 "Basis : computing new set\n");
Daniel Veillard55b91f22000-10-05 16:30:11 +00006078#endif
6079 xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
6080#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006081 xmlGenericError(xmlGenericErrorContext, "Basis : ");
6082 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Daniel Veillard55b91f22000-10-05 16:30:11 +00006083#endif
6084 if (name != NULL)
6085 xmlFree(name);
Daniel Veillard55b91f22000-10-05 16:30:11 +00006086
6087eval_predicates:
Daniel Veillard00fdf371999-10-08 09:40:39 +00006088 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006089 while (CUR == '[') {
6090 xmlXPathEvalPredicate(ctxt);
6091 }
6092 }
6093#ifdef DEBUG_STEP
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006094 xmlGenericError(xmlGenericErrorContext, "Step : ");
6095 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6096 ctxt->value->nodesetval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006097#endif
6098}
6099
6100/**
6101 * xmlXPathEvalRelativeLocationPath:
6102 * @ctxt: the XPath Parser context
6103 *
6104 * [3] RelativeLocationPath ::= Step
6105 * | RelativeLocationPath '/' Step
6106 * | AbbreviatedRelativeLocationPath
6107 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6108 *
6109 */
6110void
Daniel Veillardce6e98d2000-11-25 09:54:49 +00006111#ifdef VMS
6112xmlXPathEvalRelLocationPath
6113#else
6114xmlXPathEvalRelativeLocationPath
6115#endif
6116(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00006117 SKIP_BLANKS;
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00006118 if ((CUR == '/') && (NXT(1) == '/')) {
6119 SKIP(2);
6120 SKIP_BLANKS;
6121 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00006122 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardc8df0aa2000-10-10 23:50:30 +00006123 } else if (CUR == '/') {
6124 NEXT;
6125 SKIP_BLANKS;
6126 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006127 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006128 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006129 while (CUR == '/') {
6130 if ((CUR == '/') && (NXT(1) == '/')) {
6131 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006132 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00006133 xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
Daniel Veillard767662d2000-10-27 17:04:52 +00006134 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006135 xmlXPathEvalStep(ctxt);
6136 } else if (CUR == '/') {
6137 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00006138 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006139 xmlXPathEvalStep(ctxt);
6140 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00006141 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006142 }
6143}
6144
6145/**
6146 * xmlXPathEvalLocationPath:
6147 * @ctxt: the XPath Parser context
6148 *
6149 * [1] LocationPath ::= RelativeLocationPath
6150 * | AbsoluteLocationPath
6151 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
6152 * | AbbreviatedAbsoluteLocationPath
6153 * [10] AbbreviatedAbsoluteLocationPath ::=
6154 * '//' RelativeLocationPath
6155 *
6156 * // is short for /descendant-or-self::node()/. For example,
6157 * //para is short for /descendant-or-self::node()/child::para and
6158 * so will select any para element in the document (even a para element
6159 * that is a document element will be selected by //para since the
6160 * document element node is a child of the root node); div//para is
6161 * short for div/descendant-or-self::node()/child::para and so will
6162 * select all para descendants of div children.
6163 */
6164void
6165xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00006166 SKIP_BLANKS;
6167 if (CUR != '/') {
6168 xmlXPathEvalRelativeLocationPath(ctxt);
6169 } else {
6170 while (CUR == '/') {
6171 if ((CUR == '/') && (NXT(1) == '/')) {
6172 SKIP(2);
6173 SKIP_BLANKS;
Daniel Veillard740abf52000-10-02 23:04:54 +00006174 xmlXPathNodeCollectAndTest(ctxt,
Daniel Veillard00fdf371999-10-08 09:40:39 +00006175 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
Daniel Veillard767662d2000-10-27 17:04:52 +00006176 NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00006177 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006178 } else if (CUR == '/') {
6179 NEXT;
6180 SKIP_BLANKS;
Daniel Veillard00fdf371999-10-08 09:40:39 +00006181 if (CUR != 0)
6182 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00006183 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006184 }
6185 }
6186}
6187
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006188/**
6189 * xmlXPathEval:
6190 * @str: the XPath expression
Daniel Veillard740abf52000-10-02 23:04:54 +00006191 * @ctx: the XPath context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006192 *
6193 * Evaluate the XPath Location Path in the given context.
6194 *
6195 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
6196 * the caller has to free the object.
6197 */
6198xmlXPathObjectPtr
Daniel Veillard740abf52000-10-02 23:04:54 +00006199xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
6200 xmlXPathParserContextPtr ctxt;
Daniel Veillard41e06512000-11-13 11:47:47 +00006201 xmlXPathObjectPtr res = NULL, tmp, init = NULL;
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 Veillarddf7ef2a2000-10-25 10:11:55 +00006206 CHECK_CONTEXT(ctx)
6207
Daniel Veillard740abf52000-10-02 23:04:54 +00006208 ctxt = xmlXPathNewParserContext(str, ctx);
Daniel Veillard5a2b6972001-01-20 21:15:50 +00006209 /**** TAG:9999
Daniel Veillard41e06512000-11-13 11:47:47 +00006210 if (ctx->node != NULL) {
6211 init = xmlXPathNewNodeSet(ctx->node);
6212 valuePush(ctxt, init);
6213 }
Daniel Veillard5a2b6972001-01-20 21:15:50 +00006214 ****/
Daniel Veillard55b91f22000-10-05 16:30:11 +00006215 xmlXPathEvalExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006216
Daniel Veillard767662d2000-10-27 17:04:52 +00006217 if (ctxt->value == NULL) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006218 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard767662d2000-10-27 17:04:52 +00006219 "xmlXPathEval: evaluation failed\n");
Daniel Veillard740abf52000-10-02 23:04:54 +00006220 } else {
6221 res = valuePop(ctxt);
6222 }
6223
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006224 do {
Daniel Veillard740abf52000-10-02 23:04:54 +00006225 tmp = valuePop(ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006226 if (tmp != NULL) {
Daniel Veillard41e06512000-11-13 11:47:47 +00006227 if (tmp != init)
6228 stack++;
Daniel Veillardb96e6431999-08-29 21:02:19 +00006229 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006230 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00006231 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006232 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006233 xmlGenericError(xmlGenericErrorContext,
6234 "xmlXPathEval: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006235 stack);
6236 }
Daniel Veillard740abf52000-10-02 23:04:54 +00006237 if (ctxt->error != XPATH_EXPRESSION_OK) {
6238 xmlXPathFreeObject(res);
6239 res = NULL;
6240 }
Daniel Veillardbe803962000-06-28 23:40:59 +00006241
Daniel Veillard740abf52000-10-02 23:04:54 +00006242 xmlXPathFreeParserContext(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006243 return(res);
6244}
6245
6246/**
6247 * xmlXPathEvalExpression:
6248 * @str: the XPath expression
6249 * @ctxt: the XPath context
6250 *
6251 * Evaluate the XPath expression in the given context.
6252 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00006253 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006254 * the caller has to free the object.
6255 */
6256xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00006257xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006258 xmlXPathParserContextPtr pctxt;
6259 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006260 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006261
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006262 xmlXPathInit();
6263
Daniel Veillard740abf52000-10-02 23:04:54 +00006264 CHECK_CONTEXT(ctxt)
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006265
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006266 pctxt = xmlXPathNewParserContext(str, ctxt);
6267 xmlXPathEvalExpr(pctxt);
6268
6269 res = valuePop(pctxt);
6270 do {
6271 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006272 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00006273 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006274 stack++;
6275 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006276 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006277 if (stack != 0) {
Daniel Veillardd6d7f7b2000-10-25 19:56:55 +00006278 xmlGenericError(xmlGenericErrorContext,
6279 "xmlXPathEvalExpression: %d object left on the stack\n",
Daniel Veillarddbfd6411999-12-28 16:35:14 +00006280 stack);
6281 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00006282 xmlXPathFreeParserContext(pctxt);
6283 return(res);
6284}
6285
Daniel Veillardf17e09b2001-01-25 13:55:35 +00006286/**
6287 * xmlXPathRegisterAllFunctions:
6288 * @ctxt: the XPath context
6289 *
6290 * Registers all default XPath functions in this context
6291 */
Daniel Veillard52afe802000-10-22 16:56:02 +00006292void
6293xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
6294{
6295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
6296 xmlXPathBooleanFunction);
6297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
6298 xmlXPathCeilingFunction);
6299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
6300 xmlXPathCountFunction);
6301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
6302 xmlXPathConcatFunction);
6303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
6304 xmlXPathContainsFunction);
6305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
6306 xmlXPathIdFunction);
6307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
6308 xmlXPathFalseFunction);
6309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
6310 xmlXPathFloorFunction);
6311 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
6312 xmlXPathLastFunction);
6313 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
6314 xmlXPathLangFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00006315 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
6316 xmlXPathLocalNameFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
6318 xmlXPathNotFunction);
6319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
6320 xmlXPathNameFunction);
Daniel Veillardf6bf9212000-10-26 14:07:44 +00006321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
6322 xmlXPathNamespaceURIFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
6324 xmlXPathNormalizeFunction);
Daniel Veillard52afe802000-10-22 16:56:02 +00006325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
6326 xmlXPathNumberFunction);
6327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
6328 xmlXPathPositionFunction);
6329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
6330 xmlXPathRoundFunction);
6331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
6332 xmlXPathStringFunction);
6333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
6334 xmlXPathStringLengthFunction);
6335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
6336 xmlXPathStartsWithFunction);
6337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
6338 xmlXPathSubstringFunction);
6339 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
6340 xmlXPathSubstringBeforeFunction);
6341 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
6342 xmlXPathSubstringAfterFunction);
6343 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
6344 xmlXPathSumFunction);
6345 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
6346 xmlXPathTrueFunction);
6347 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
6348 xmlXPathTranslateFunction);
6349}
6350
Daniel Veillard361d8452000-04-03 19:48:13 +00006351#endif /* LIBXML_XPATH_ENABLED */