blob: 413c16cbb599b21f63459e51d7bc9d7491300548 [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,
4 * designed to be used by both XSLT and XPointer.
5 *
6 * Reference: W3C Working Draft internal 5 July 1999
7 * http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
8 * Public reference:
9 * http://www.w3.org/TR/WD-xpath/
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 */
15
Daniel Veillard7f7d1111999-09-22 09:46:25 +000016#ifdef WIN32
Daniel Veillard3c558c31999-12-22 11:30:41 +000017#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +000018#else
19#include "config.h"
20#endif
21
Daniel Veillard361d8452000-04-03 19:48:13 +000022#include "xmlversion.h"
23#ifdef LIBXML_XPATH_ENABLED
24
Daniel Veillard7f7d1111999-09-22 09:46:25 +000025#include <stdio.h>
26#include <string.h>
27
28#ifdef HAVE_SYS_TYPES_H
29#include <sys/types.h>
30#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +000031#ifdef HAVE_MATH_H
Daniel Veillard1566d3a1999-07-15 14:24:29 +000032#include <math.h>
Daniel Veillardb05deb71999-08-10 19:04:08 +000033#endif
34#ifdef HAVE_MATH_H
35#include <float.h>
36#endif
37#ifdef HAVE_IEEEFP_H
38#include <ieeefp.h>
39#endif
40#ifdef HAVE_NAN_H
41#include <nan.h>
42#endif
Daniel Veillard7f7d1111999-09-22 09:46:25 +000043#ifdef HAVE_CTYPE_H
Daniel Veillardb96e6431999-08-29 21:02:19 +000044#include <ctype.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000045#endif
46
Daniel Veillard361d8452000-04-03 19:48:13 +000047#include <libxml/xmlmemory.h>
48#include <libxml/tree.h>
49#include <libxml/valid.h>
50#include <libxml/xpath.h>
51#include <libxml/parserInternals.h>
Daniel Veillard1566d3a1999-07-15 14:24:29 +000052
Daniel Veillarddbfd6411999-12-28 16:35:14 +000053/* #define DEBUG */
54/* #define DEBUG_STEP */
55/* #define DEBUG_EXPR */
56
Daniel Veillard1566d3a1999-07-15 14:24:29 +000057/*
Daniel Veillarde2d034d1999-07-27 19:52:06 +000058 * Setup stuff for floating point
Daniel Veillard991e63d1999-08-15 23:32:28 +000059 * The lack of portability of this section of the libc is annoying !
Daniel Veillard1566d3a1999-07-15 14:24:29 +000060 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +000061double xmlXPathNAN = 0;
62double xmlXPathPINF = 1;
63double xmlXPathMINF = -1;
64
Daniel Veillardb05deb71999-08-10 19:04:08 +000065#ifndef isinf
66#ifndef HAVE_ISINF
67
68#if HAVE_FPCLASS
69
70int isinf(double d) {
71 fpclass_t type = fpclass(d);
72 switch (type) {
73 case FP_NINF:
74 return(-1);
75 case FP_PINF:
76 return(1);
Daniel Veillardb05deb71999-08-10 19:04:08 +000077 }
78 return(0);
79}
80
81#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
82
83#if HAVE_FP_CLASS_H
84#include <fp_class.h>
85#endif
86
87int isinf(double d) {
88#if HAVE_FP_CLASS
89 int fpclass = fp_class(d);
90#else
91 int fpclass = fp_class_d(d);
92#endif
93 if (fpclass == FP_POS_INF)
94 return(1);
95 if (fpclass == FP_NEG_INF)
96 return(-1);
97 return(0);
98}
99
100#elif defined(HAVE_CLASS)
101
102int isinf(double d) {
103 int fpclass = class(d);
104 if (fpclass == FP_PLUS_INF)
105 return(1);
106 if (fpclass == FP_MINUS_INF)
107 return(-1);
108 return(0);
109}
110#elif defined(finite) || defined(HAVE_FINITE)
111int isinf(double x) { return !finite(x) && x==x; }
Daniel Veillard991e63d1999-08-15 23:32:28 +0000112#elif defined(HUGE_VAL)
Daniel Veillardfc708e22000-04-08 13:17:27 +0000113int isinf(double x)
Daniel Veillard991e63d1999-08-15 23:32:28 +0000114{
115 if (x == HUGE_VAL)
116 return(1);
117 if (x == -HUGE_VAL)
118 return(-1);
119 return(0);
120}
121#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +0000122
123#endif /* ! HAVE_ISINF */
124#endif /* ! defined(isinf) */
125
126#ifndef isnan
127#ifndef HAVE_ISNAN
128
129#ifdef HAVE_ISNAND
130#define isnan(f) isnand(f)
131#endif /* HAVE_iSNAND */
132
133#endif /* ! HAVE_iSNAN */
134#endif /* ! defined(isnan) */
135
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000136/**
137 * xmlXPathInit:
138 *
139 * Initialize the XPath environment
140 */
141void
142xmlXPathInit(void) {
143 static int initialized = 0;
144
145 if (initialized) return;
146
147 xmlXPathNAN = 0;
148 xmlXPathNAN /= 0;
149
150 xmlXPathPINF = 1;
151 xmlXPathPINF /= 0;
152
153 xmlXPathMINF = -1;
154 xmlXPathMINF /= 0;
155
156 initialized = 1;
157}
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000158
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000159FILE *xmlXPathDebug = NULL;
160
161#define TODO \
162 fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
163 __FILE__, __LINE__);
164
165#define STRANGE \
166 fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
167 __FILE__, __LINE__);
168
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000169double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000170void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000171
172/************************************************************************
173 * *
174 * Parser stacks related functions and macros *
175 * *
176 ************************************************************************/
177
178/*
179 * Generic function for accessing stacks in the Parser Context
180 */
181
182#define PUSH_AND_POP(type, name) \
183extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
184 if (ctxt->name##Nr >= ctxt->name##Max) { \
185 ctxt->name##Max *= 2; \
Daniel Veillard32bc74e2000-07-14 14:49:25 +0000186 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000187 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
188 if (ctxt->name##Tab == NULL) { \
Daniel Veillardb05deb71999-08-10 19:04:08 +0000189 fprintf(xmlXPathDebug, "realloc failed !\n"); \
Daniel Veillard0142b842000-01-14 14:45:24 +0000190 return(0); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000191 } \
192 } \
193 ctxt->name##Tab[ctxt->name##Nr] = value; \
194 ctxt->name = value; \
195 return(ctxt->name##Nr++); \
196} \
197extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
198 type ret; \
199 if (ctxt->name##Nr <= 0) return(0); \
200 ctxt->name##Nr--; \
201 if (ctxt->name##Nr > 0) \
202 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
203 else \
204 ctxt->name = NULL; \
205 ret = ctxt->name##Tab[ctxt->name##Nr]; \
206 ctxt->name##Tab[ctxt->name##Nr] = 0; \
207 return(ret); \
208} \
209
210PUSH_AND_POP(xmlXPathObjectPtr, value)
211
212/*
213 * Macros for accessing the content. Those should be used only by the parser,
214 * and not exported.
215 *
216 * Dirty macros, i.e. one need to make assumption on the context to use them
217 *
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000218 * CUR_PTR return the current pointer to the xmlChar to be parsed.
Daniel Veillardcf461992000-03-14 18:30:20 +0000219 * CUR returns the current xmlChar value, i.e. a 8 bit value
220 * in ISO-Latin or UTF-8.
221 * This should be used internally by the parser
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000222 * only to compare to ASCII values otherwise it would break when
223 * running with UTF-8 encoding.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000224 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000225 * to compare on ASCII based substring.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000226 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000227 * strings within the parser.
228 * CURRENT Returns the current char value, with the full decoding of
229 * UTF-8 if we are using this mode. It returns an int.
230 * NEXT Skip to the next character, this does the proper decoding
231 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000232 * It returns the pointer to the current xmlChar.
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000233 */
234
235#define CUR (*ctxt->cur)
236#define SKIP(val) ctxt->cur += (val)
237#define NXT(val) ctxt->cur[(val)]
238#define CUR_PTR ctxt->cur
239
240#define SKIP_BLANKS \
241 while (IS_BLANK(*(ctxt->cur))) NEXT
242
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000243#define CURRENT (*ctxt->cur)
244#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000245
246/************************************************************************
247 * *
248 * Error handling routines *
249 * *
250 ************************************************************************/
251
252#define XPATH_EXPRESSION_OK 0
253#define XPATH_NUMBER_ERROR 1
254#define XPATH_UNFINISHED_LITERAL_ERROR 2
255#define XPATH_START_LITERAL_ERROR 3
256#define XPATH_VARIABLE_REF_ERROR 4
257#define XPATH_UNDEF_VARIABLE_ERROR 5
258#define XPATH_INVALID_PREDICATE_ERROR 6
259#define XPATH_EXPR_ERROR 7
260#define XPATH_UNCLOSED_ERROR 8
261#define XPATH_UNKNOWN_FUNC_ERROR 9
262#define XPATH_INVALID_OPERAND 10
263#define XPATH_INVALID_TYPE 11
264#define XPATH_INVALID_ARITY 12
265
266const char *xmlXPathErrorMessages[] = {
267 "Ok",
268 "Number encoding",
269 "Unfinished litteral",
270 "Start of litteral",
271 "Expected $ for variable reference",
272 "Undefined variable",
273 "Invalid predicate",
274 "Invalid expression",
275 "Missing closing curly brace",
276 "Unregistered function",
277 "Invalid operand",
278 "Invalid type",
279 "Invalid number of arguments",
280};
281
282/**
283 * xmlXPathError:
284 * @ctxt: the XPath Parser context
285 * @file: the file name
286 * @line: the line number
287 * @no: the error number
288 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000289 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000290 *
291 * Returns the newly created object.
292 */
293void
294xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
295 int line, int no) {
296 int n;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000297 const xmlChar *cur;
298 const xmlChar *base;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000299
300 fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
301 xmlXPathErrorMessages[no]);
302
303 cur = ctxt->cur;
304 base = ctxt->base;
305 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
306 cur--;
307 }
308 n = 0;
309 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
310 cur--;
311 if ((*cur == '\n') || (*cur == '\r')) cur++;
312 base = cur;
313 n = 0;
314 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
315 fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
316 n++;
317 }
318 fprintf(xmlXPathDebug, "\n");
319 cur = ctxt->cur;
320 while ((*cur == '\n') || (*cur == '\r'))
321 cur--;
322 n = 0;
323 while ((cur != base) && (n++ < 80)) {
324 fprintf(xmlXPathDebug, " ");
325 base++;
326 }
327 fprintf(xmlXPathDebug,"^\n");
328}
329
330#define CHECK_ERROR \
331 if (ctxt->error != XPATH_EXPRESSION_OK) return
332
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000333#define XP_ERROR(X) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000334 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
335 ctxt->error = (X); return; }
336
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000337#define XP_ERROR0(X) \
Daniel Veillard991e63d1999-08-15 23:32:28 +0000338 { xmlXPatherror(ctxt, __FILE__, __LINE__, X); \
339 ctxt->error = (X); return(0); }
340
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000341#define CHECK_TYPE(typeval) \
342 if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000343 XP_ERROR(XPATH_INVALID_TYPE) \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000344
345
346/************************************************************************
347 * *
348 * Routines to handle NodeSets *
349 * *
350 ************************************************************************/
351
352#define XML_NODESET_DEFAULT 10
353/**
354 * xmlXPathNodeSetCreate:
355 * @val: an initial xmlNodePtr, or NULL
356 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000357 * Create a new xmlNodeSetPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000358 *
359 * Returns the newly created object.
360 */
361xmlNodeSetPtr
362xmlXPathNodeSetCreate(xmlNodePtr val) {
363 xmlNodeSetPtr ret;
364
Daniel Veillard6454aec1999-09-02 22:04:43 +0000365 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000366 if (ret == NULL) {
367 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
368 return(NULL);
369 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000370 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000371 if (val != NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000372 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000373 sizeof(xmlNodePtr));
374 if (ret->nodeTab == NULL) {
375 fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
376 return(NULL);
377 }
378 memset(ret->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000379 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000380 ret->nodeMax = XML_NODESET_DEFAULT;
381 ret->nodeTab[ret->nodeNr++] = val;
382 }
383 return(ret);
384}
385
386/**
387 * xmlXPathNodeSetAdd:
388 * @cur: the initial node set
389 * @val: a new xmlNodePtr
390 *
391 * add a new xmlNodePtr ot an existing NodeSet
392 */
393void
394xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
395 int i;
396
397 if (val == NULL) return;
398
399 /*
400 * check against doublons
401 */
402 for (i = 0;i < cur->nodeNr;i++)
403 if (cur->nodeTab[i] == val) return;
404
405 /*
406 * grow the nodeTab if needed
407 */
408 if (cur->nodeMax == 0) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000409 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000410 sizeof(xmlNodePtr));
411 if (cur->nodeTab == NULL) {
412 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
413 return;
414 }
415 memset(cur->nodeTab, 0 ,
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000416 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000417 cur->nodeMax = XML_NODESET_DEFAULT;
418 } else if (cur->nodeNr == cur->nodeMax) {
419 xmlNodePtr *temp;
420
421 cur->nodeMax *= 2;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000422 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000423 sizeof(xmlNodePtr));
424 if (temp == NULL) {
425 fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
426 return;
427 }
Daniel Veillardb96e6431999-08-29 21:02:19 +0000428 cur->nodeTab = temp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000429 }
430 cur->nodeTab[cur->nodeNr++] = val;
431}
432
433/**
434 * xmlXPathNodeSetMerge:
435 * @val1: the first NodeSet
436 * @val2: the second NodeSet
437 *
438 * Merges two nodesets, all nodes from @val2 are added to @val1
439 *
440 * Returns val1 once extended or NULL in case of error.
441 */
442xmlNodeSetPtr
443xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
444 int i;
445
446 if (val1 == NULL) return(NULL);
447 if (val2 == NULL) return(val1);
448
449 /*
450 * !!!!! this can be optimized a lot, knowing that both
451 * val1 and val2 already have unicity of their values.
452 */
453
454 for (i = 0;i < val2->nodeNr;i++)
455 xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
456
457 return(val1);
458}
459
460/**
461 * xmlXPathNodeSetDel:
462 * @cur: the initial node set
463 * @val: an xmlNodePtr
464 *
465 * Removes an xmlNodePtr from an existing NodeSet
466 */
467void
468xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
469 int i;
470
471 if (cur == NULL) return;
472 if (val == NULL) return;
473
474 /*
475 * check against doublons
476 */
477 for (i = 0;i < cur->nodeNr;i++)
478 if (cur->nodeTab[i] == val) break;
479
480 if (i >= cur->nodeNr) {
481#ifdef DEBUG
482 fprintf(xmlXPathDebug,
483 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
484 val->name);
485#endif
486 return;
487 }
488 cur->nodeNr--;
489 for (;i < cur->nodeNr;i++)
490 cur->nodeTab[i] = cur->nodeTab[i + 1];
491 cur->nodeTab[cur->nodeNr] = NULL;
492}
493
494/**
495 * xmlXPathNodeSetRemove:
496 * @cur: the initial node set
497 * @val: the index to remove
498 *
499 * Removes an entry from an existing NodeSet list.
500 */
501void
502xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
503 if (cur == NULL) return;
504 if (val >= cur->nodeNr) return;
505 cur->nodeNr--;
506 for (;val < cur->nodeNr;val++)
507 cur->nodeTab[val] = cur->nodeTab[val + 1];
508 cur->nodeTab[cur->nodeNr] = NULL;
509}
510
511/**
512 * xmlXPathFreeNodeSet:
513 * @obj: the xmlNodeSetPtr to free
514 *
515 * Free the NodeSet compound (not the actual nodes !).
516 */
517void
518xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
519 if (obj == NULL) return;
520 if (obj->nodeTab != NULL) {
521#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000522 memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000523#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000524 xmlFree(obj->nodeTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000525 }
526#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000527 memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000528#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000529 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000530}
531
Daniel Veillardb96e6431999-08-29 21:02:19 +0000532#if defined(DEBUG) || defined(DEBUG_STEP)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000533/**
534 * xmlXPathDebugNodeSet:
535 * @output: a FILE * for the output
536 * @obj: the xmlNodeSetPtr to free
537 *
538 * Quick display of a NodeSet
539 */
540void
541xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
542 int i;
543
544 if (output == NULL) output = xmlXPathDebug;
545 if (obj == NULL) {
546 fprintf(output, "NodeSet == NULL !\n");
547 return;
548 }
549 if (obj->nodeNr == 0) {
550 fprintf(output, "NodeSet is empty\n");
551 return;
552 }
553 if (obj->nodeTab == NULL) {
554 fprintf(output, " nodeTab == NULL !\n");
555 return;
556 }
557 for (i = 0; i < obj->nodeNr; i++) {
558 if (obj->nodeTab[i] == NULL) {
559 fprintf(output, " NULL !\n");
560 return;
561 }
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000562 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
563 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +0000564 fprintf(output, " /");
565 else if (obj->nodeTab[i]->name == NULL)
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000566 fprintf(output, " noname!");
567 else fprintf(output, " %s", obj->nodeTab[i]->name);
568 }
569 fprintf(output, "\n");
570}
571#endif
572
573/************************************************************************
574 * *
575 * Routines to handle Variable *
576 * *
577 * UNIMPLEMENTED CURRENTLY *
578 * *
579 ************************************************************************/
580
581/**
582 * xmlXPathVariablelookup:
583 * @ctxt: the XPath Parser context
584 * @prefix: the variable name namespace if any
585 * @name: the variable name
586 *
587 * Search in the Variable array of the context for the given
588 * variable value.
589 *
590 * UNIMPLEMENTED: always return NULL.
591 *
592 * Returns the value or NULL if not found
593 */
594xmlXPathObjectPtr
595xmlXPathVariablelookup(xmlXPathParserContextPtr ctxt,
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000596 const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000597 return(NULL);
598}
599
600/************************************************************************
601 * *
602 * Routines to handle Values *
603 * *
604 ************************************************************************/
605
606/* Allocations are terrible, one need to optimize all this !!! */
607
608/**
609 * xmlXPathNewFloat:
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000610 * @val: the double value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000611 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000612 * Create a new xmlXPathObjectPtr of type double and of value @val
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000613 *
614 * Returns the newly created object.
615 */
616xmlXPathObjectPtr
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000617xmlXPathNewFloat(double val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000618 xmlXPathObjectPtr ret;
619
Daniel Veillard6454aec1999-09-02 22:04:43 +0000620 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000621 if (ret == NULL) {
622 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
623 return(NULL);
624 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000625 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000626 ret->type = XPATH_NUMBER;
627 ret->floatval = val;
628 return(ret);
629}
630
631/**
632 * xmlXPathNewBoolean:
633 * @val: the boolean value
634 *
635 * Create a new xmlXPathObjectPtr of type boolean and of value @val
636 *
637 * Returns the newly created object.
638 */
639xmlXPathObjectPtr
640xmlXPathNewBoolean(int val) {
641 xmlXPathObjectPtr ret;
642
Daniel Veillard6454aec1999-09-02 22:04:43 +0000643 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000644 if (ret == NULL) {
645 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
646 return(NULL);
647 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000648 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000649 ret->type = XPATH_BOOLEAN;
650 ret->boolval = (val != 0);
651 return(ret);
652}
653
654/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000655 * xmlXPathNewString:
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000656 * @val: the xmlChar * value
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000657 *
658 * Create a new xmlXPathObjectPtr of type string and of value @val
659 *
660 * Returns the newly created object.
661 */
662xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000663xmlXPathNewString(const xmlChar *val) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000664 xmlXPathObjectPtr ret;
665
Daniel Veillard6454aec1999-09-02 22:04:43 +0000666 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000667 if (ret == NULL) {
668 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
669 return(NULL);
670 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000671 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000672 ret->type = XPATH_STRING;
673 ret->stringval = xmlStrdup(val);
674 return(ret);
675}
676
677/**
Daniel Veillardb96e6431999-08-29 21:02:19 +0000678 * xmlXPathNewCString:
679 * @val: the char * value
680 *
681 * Create a new xmlXPathObjectPtr of type string and of value @val
682 *
683 * Returns the newly created object.
684 */
685xmlXPathObjectPtr
686xmlXPathNewCString(const char *val) {
687 xmlXPathObjectPtr ret;
688
Daniel Veillard6454aec1999-09-02 22:04:43 +0000689 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillardb96e6431999-08-29 21:02:19 +0000690 if (ret == NULL) {
691 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
692 return(NULL);
693 }
694 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
695 ret->type = XPATH_STRING;
696 ret->stringval = xmlStrdup(BAD_CAST val);
697 return(ret);
698}
699
700/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000701 * xmlXPathNewNodeSet:
702 * @val: the NodePtr value
703 *
704 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
705 * it with the single Node @val
706 *
707 * Returns the newly created object.
708 */
709xmlXPathObjectPtr
710xmlXPathNewNodeSet(xmlNodePtr val) {
711 xmlXPathObjectPtr ret;
712
Daniel Veillard6454aec1999-09-02 22:04:43 +0000713 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000714 if (ret == NULL) {
715 fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
716 return(NULL);
717 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000718 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000719 ret->type = XPATH_NODESET;
720 ret->nodesetval = xmlXPathNodeSetCreate(val);
721 return(ret);
722}
723
724/**
725 * xmlXPathNewNodeSetList:
726 * @val: an existing NodeSet
727 *
728 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
729 * it with the Nodeset @val
730 *
731 * Returns the newly created object.
732 */
733xmlXPathObjectPtr
734xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
735 xmlXPathObjectPtr ret;
Daniel Veillardbe803962000-06-28 23:40:59 +0000736 int i;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000737
Daniel Veillardbe803962000-06-28 23:40:59 +0000738 if (val == NULL)
739 ret = NULL;
740 else if (val->nodeTab == NULL)
741 ret = xmlXPathNewNodeSet(NULL);
742 else
743 {
744 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
745 for (i = 1; i < val->nodeNr; ++i)
746 xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
747 }
748
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000749 return(ret);
750}
751
752/**
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000753 * xmlXPathFreeNodeSetList:
754 * @obj: an existing NodeSetList object
755 *
756 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
757 * the list contrary to xmlXPathFreeObject().
758 */
759void
760xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
761 if (obj == NULL) return;
762#ifdef DEBUG
763 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
764#endif
765 xmlFree(obj);
766}
767
768/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000769 * xmlXPathFreeObject:
770 * @obj: the object to free
771 *
772 * Free up an xmlXPathObjectPtr object.
773 */
774void
775xmlXPathFreeObject(xmlXPathObjectPtr obj) {
776 if (obj == NULL) return;
777 if (obj->nodesetval != NULL)
778 xmlXPathFreeNodeSet(obj->nodesetval);
779 if (obj->stringval != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000780 xmlFree(obj->stringval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000781#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000782 memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000783#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000784 xmlFree(obj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000785}
786
787/************************************************************************
788 * *
789 * Routines to handle XPath contexts *
790 * *
791 ************************************************************************/
792
793/**
794 * xmlXPathNewContext:
795 * @doc: the XML document
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000796 *
797 * Create a new xmlXPathContext
798 *
799 * Returns the xmlXPathContext just allocated.
800 */
801xmlXPathContextPtr
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000802xmlXPathNewContext(xmlDocPtr doc) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000803 xmlXPathContextPtr ret;
804
Daniel Veillard6454aec1999-09-02 22:04:43 +0000805 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000806 if (ret == NULL) {
807 fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
808 return(NULL);
809 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000810 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000811 ret->doc = doc;
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000812 /***********
813 ret->node = (xmlNodePtr) doc;
814 ret->nodelist = xmlXPathNodeSetCreate(ret->node);
815 ***********/
816 ret->node = NULL;
817 ret->nodelist = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000818
819 ret->nb_variables = 0;
820 ret->max_variables = 0;
821 ret->variables = NULL;
822
823 ret->nb_types = 0;
824 ret->max_types = 0;
825 ret->types = NULL;
826
827 ret->nb_funcs = 0;
828 ret->max_funcs = 0;
829 ret->funcs = NULL;
830
831 ret->nb_axis = 0;
832 ret->max_axis = 0;
833 ret->axis = NULL;
834
Daniel Veillardb96e6431999-08-29 21:02:19 +0000835 ret->namespaces = NULL;
Daniel Veillardc08a2c61999-09-08 21:35:25 +0000836 ret->user = NULL;
Daniel Veillardb96e6431999-08-29 21:02:19 +0000837 ret->nsNr = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000838 return(ret);
839}
840
841/**
842 * xmlXPathFreeContext:
843 * @ctxt: the context to free
844 *
845 * Free up an xmlXPathContext
846 */
847void
848xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
Daniel Veillardb96e6431999-08-29 21:02:19 +0000849 if (ctxt->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000850 xmlFree(ctxt->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +0000851
Daniel Veillarddbfd6411999-12-28 16:35:14 +0000852 if (ctxt->nodelist != NULL)
853 xmlXPathFreeNodeSet(ctxt->nodelist);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000854#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000855 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000856#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000857 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000858}
859
860/************************************************************************
861 * *
862 * Routines to handle XPath parser contexts *
863 * *
864 ************************************************************************/
865
866#define CHECK_CTXT \
867 if (ctxt == NULL) { \
868 fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
869 __FILE__, __LINE__); \
870 } \
871
872
873#define CHECK_CONTEXT \
874 if (ctxt == NULL) { \
875 fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
876 __FILE__, __LINE__); \
877 } \
878 if (ctxt->doc == NULL) { \
879 fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
880 __FILE__, __LINE__); \
881 } \
Daniel Veillardcf461992000-03-14 18:30:20 +0000882 if (ctxt->doc->children == NULL) { \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000883 fprintf(xmlXPathDebug, \
884 "%s:%d Internal error: document without root\n", \
885 __FILE__, __LINE__); \
886 } \
887
888
889/**
890 * xmlXPathNewParserContext:
891 * @str: the XPath expression
892 * @ctxt: the XPath context
893 *
894 * Create a new xmlXPathParserContext
895 *
896 * Returns the xmlXPathParserContext just allocated.
897 */
898xmlXPathParserContextPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000899xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000900 xmlXPathParserContextPtr ret;
901
Daniel Veillard6454aec1999-09-02 22:04:43 +0000902 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000903 if (ret == NULL) {
904 fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
905 return(NULL);
906 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000907 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000908 ret->cur = ret->base = str;
909 ret->context = ctxt;
910
911 /* Allocate the value stack */
912 ret->valueTab = (xmlXPathObjectPtr *)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000913 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000914 ret->valueNr = 0;
915 ret->valueMax = 10;
916 ret->value = NULL;
917 return(ret);
918}
919
920/**
921 * xmlXPathFreeParserContext:
922 * @ctxt: the context to free
923 *
924 * Free up an xmlXPathParserContext
925 */
926void
927xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
928 if (ctxt->valueTab != NULL) {
929#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000930 memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000931#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000932 xmlFree(ctxt->valueTab);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000933 }
934#ifdef DEBUG
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000935 memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000936#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000937 xmlFree(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000938}
939
940/************************************************************************
941 * *
942 * The implicit core function library *
943 * *
944 ************************************************************************/
945
946/*
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000947 * Auto-pop and cast to a number
948 */
949void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
950
951#define CHECK_ARITY(x) \
952 if (nargs != (x)) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000953 XP_ERROR(XPATH_INVALID_ARITY); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000954 } \
955
956
957#define POP_FLOAT \
958 arg = valuePop(ctxt); \
959 if (arg == NULL) { \
Daniel Veillard3f6f7f62000-06-30 17:58:25 +0000960 XP_ERROR(XPATH_INVALID_OPERAND); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000961 } \
962 if (arg->type != XPATH_NUMBER) { \
963 valuePush(ctxt, arg); \
Daniel Veillarde2d034d1999-07-27 19:52:06 +0000964 xmlXPathNumberFunction(ctxt, 1); \
Daniel Veillard1566d3a1999-07-15 14:24:29 +0000965 arg = valuePop(ctxt); \
966 }
967
968/**
Daniel Veillard991e63d1999-08-15 23:32:28 +0000969 * xmlXPathEqualNodeSetString
970 * @arg: the nodeset object argument
971 * @str: the string to compare to.
972 *
973 * Implement the equal operation on XPath objects content: @arg1 == @arg2
974 * If one object to be compared is a node-set and the other is a string,
975 * then the comparison will be true if and only if there is a node in
976 * the node-set such that the result of performing the comparison on the
977 * string-value of the node and the other string is true.
978 *
979 * Returns 0 or 1 depending on the results of the test.
980 */
981int
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000982xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
Daniel Veillard991e63d1999-08-15 23:32:28 +0000983 int i;
984 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +0000985 xmlChar *str2;
Daniel Veillard991e63d1999-08-15 23:32:28 +0000986
987 if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
988 return(0);
989 ns = arg->nodesetval;
990 for (i = 0;i < ns->nodeNr;i++) {
991 str2 = xmlNodeGetContent(ns->nodeTab[i]);
992 if ((str2 != NULL) && (!xmlStrcmp(str, str2))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000993 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000994 return(1);
995 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000996 xmlFree(str2);
Daniel Veillard991e63d1999-08-15 23:32:28 +0000997 }
998 return(0);
999}
1000
1001/**
1002 * xmlXPathEqualNodeSetFloat
1003 * @arg: the nodeset object argument
1004 * @f: the float to compare to
1005 *
1006 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1007 * If one object to be compared is a node-set and the other is a number,
1008 * then the comparison will be true if and only if there is a node in
1009 * the node-set such that the result of performing the comparison on the
1010 * number to be compared and on the result of converting the string-value
1011 * of that node to a number using the number function is true.
1012 *
1013 * Returns 0 or 1 depending on the results of the test.
1014 */
1015int
1016xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001017 char buf[100] = "";
Daniel Veillard991e63d1999-08-15 23:32:28 +00001018
1019 if ((arg == NULL) || (arg->type != XPATH_NODESET))
1020 return(0);
1021
1022 if (isnan(f))
1023 sprintf(buf, "NaN");
1024 else if (isinf(f) > 0)
1025 sprintf(buf, "+Infinity");
1026 else if (isinf(f) < 0)
1027 sprintf(buf, "-Infinity");
1028 else
1029 sprintf(buf, "%0g", f);
1030
Daniel Veillardb96e6431999-08-29 21:02:19 +00001031 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
Daniel Veillard991e63d1999-08-15 23:32:28 +00001032}
1033
1034
1035/**
1036 * xmlXPathEqualNodeSets
1037 * @arg1: first nodeset object argument
1038 * @arg2: second nodeset object argument
1039 *
1040 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1041 * If both objects to be compared are node-sets, then the comparison
1042 * will be true if and only if there is a node in the first node-set and
1043 * a node in the second node-set such that the result of performing the
1044 * comparison on the string-values of the two nodes is true.
1045 *
1046 * (needless to say, this is a costly operation)
1047 *
1048 * Returns 0 or 1 depending on the results of the test.
1049 */
1050int
1051xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1052 int i;
1053 xmlNodeSetPtr ns;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001054 xmlChar *str;
Daniel Veillard991e63d1999-08-15 23:32:28 +00001055
1056 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1057 return(0);
1058 if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1059 return(0);
1060
1061 ns = arg1->nodesetval;
1062 for (i = 0;i < ns->nodeNr;i++) {
1063 str = xmlNodeGetContent(ns->nodeTab[i]);
1064 if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00001065 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001066 return(1);
1067 }
Daniel Veillard6454aec1999-09-02 22:04:43 +00001068 xmlFree(str);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001069 }
1070 return(0);
1071}
1072
1073/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001074 * xmlXPathEqualValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001075 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001076 *
1077 * Implement the equal operation on XPath objects content: @arg1 == @arg2
1078 *
1079 * Returns 0 or 1 depending on the results of the test.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001080 */
1081int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001082xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1083 xmlXPathObjectPtr arg1, arg2;
1084 int ret = 0;
1085
1086 arg1 = valuePop(ctxt);
1087 if (arg1 == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001088 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001089
1090 arg2 = valuePop(ctxt);
1091 if (arg2 == NULL) {
1092 xmlXPathFreeObject(arg1);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001093 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001094 }
1095
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001096 if (arg1 == arg2) {
1097#ifdef DEBUG_EXPR
1098 fprintf(xmlXPathDebug, "Equal: by pointer\n");
1099#endif
1100 return(1);
1101 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001102
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001103 switch (arg1->type) {
1104 case XPATH_UNDEFINED:
1105#ifdef DEBUG_EXPR
1106 fprintf(xmlXPathDebug, "Equal: undefined\n");
1107#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001108 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001109 case XPATH_NODESET:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001110 switch (arg2->type) {
1111 case XPATH_UNDEFINED:
1112#ifdef DEBUG_EXPR
1113 fprintf(xmlXPathDebug, "Equal: undefined\n");
1114#endif
1115 break;
1116 case XPATH_NODESET:
1117 ret = xmlXPathEqualNodeSets(arg1, arg2);
1118 break;
1119 case XPATH_BOOLEAN:
1120 if ((arg1->nodesetval == NULL) ||
1121 (arg1->nodesetval->nodeNr == 0)) ret = 0;
1122 else
1123 ret = 1;
1124 ret = (ret == arg2->boolval);
1125 break;
1126 case XPATH_NUMBER:
1127 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1128 break;
1129 case XPATH_STRING:
1130 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1131 break;
1132 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001133 break;
1134 case XPATH_BOOLEAN:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001135 switch (arg2->type) {
1136 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001137#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001138 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001139#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001140 break;
1141 case XPATH_NODESET:
1142 if ((arg2->nodesetval == NULL) ||
1143 (arg2->nodesetval->nodeNr == 0)) ret = 0;
1144 else
1145 ret = 1;
1146 break;
1147 case XPATH_BOOLEAN:
1148#ifdef DEBUG_EXPR
1149 fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1150 arg1->boolval, arg2->boolval);
1151#endif
1152 ret = (arg1->boolval == arg2->boolval);
1153 break;
1154 case XPATH_NUMBER:
1155 if (arg2->floatval) ret = 1;
1156 else ret = 0;
1157 ret = (arg1->boolval == ret);
1158 break;
1159 case XPATH_STRING:
1160 if ((arg2->stringval == NULL) ||
1161 (arg2->stringval[0] == 0)) ret = 0;
1162 else
1163 ret = 1;
1164 ret = (arg1->boolval == ret);
1165 break;
1166 }
1167 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001168 case XPATH_NUMBER:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001169 switch (arg2->type) {
1170 case XPATH_UNDEFINED:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001171#ifdef DEBUG_EXPR
Daniel Veillard991e63d1999-08-15 23:32:28 +00001172 fprintf(xmlXPathDebug, "Equal: undefined\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001173#endif
Daniel Veillard991e63d1999-08-15 23:32:28 +00001174 break;
1175 case XPATH_NODESET:
1176 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1177 break;
1178 case XPATH_BOOLEAN:
1179 if (arg1->floatval) ret = 1;
1180 else ret = 0;
1181 ret = (arg2->boolval == ret);
1182 break;
1183 case XPATH_STRING:
1184 valuePush(ctxt, arg2);
1185 xmlXPathNumberFunction(ctxt, 1);
1186 arg2 = valuePop(ctxt);
1187 /* no break on purpose */
1188 case XPATH_NUMBER:
1189 ret = (arg1->floatval == arg2->floatval);
1190 break;
1191 }
1192 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001193 case XPATH_STRING:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001194 switch (arg2->type) {
1195 case XPATH_UNDEFINED:
1196#ifdef DEBUG_EXPR
1197 fprintf(xmlXPathDebug, "Equal: undefined\n");
1198#endif
1199 break;
1200 case XPATH_NODESET:
1201 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1202 break;
1203 case XPATH_BOOLEAN:
1204 if ((arg1->stringval == NULL) ||
1205 (arg1->stringval[0] == 0)) ret = 0;
1206 else
1207 ret = 1;
1208 ret = (arg2->boolval == ret);
1209 break;
1210 case XPATH_STRING:
1211 ret = !xmlStrcmp(arg1->stringval, arg2->stringval);
1212 break;
1213 case XPATH_NUMBER:
1214 valuePush(ctxt, arg1);
1215 xmlXPathNumberFunction(ctxt, 1);
1216 arg1 = valuePop(ctxt);
1217 ret = (arg1->floatval == arg2->floatval);
1218 break;
1219 }
1220 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001221 }
Daniel Veillard991e63d1999-08-15 23:32:28 +00001222 xmlXPathFreeObject(arg1);
1223 xmlXPathFreeObject(arg2);
1224 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001225}
1226
1227/**
1228 * xmlXPathCompareValues:
Daniel Veillard991e63d1999-08-15 23:32:28 +00001229 * @ctxt: the XPath Parser context
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001230 * @inf: less than (1) or greater than (2)
1231 * @strict: is the comparison strict
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001232 *
1233 * Implement the compare operation on XPath objects:
1234 * @arg1 < @arg2 (1, 1, ...
1235 * @arg1 <= @arg2 (1, 0, ...
1236 * @arg1 > @arg2 (0, 1, ...
1237 * @arg1 >= @arg2 (0, 0, ...
1238 *
Daniel Veillard991e63d1999-08-15 23:32:28 +00001239 * When neither object to be compared is a node-set and the operator is
1240 * <=, <, >=, >, then the objects are compared by converted both objects
1241 * to numbers and comparing the numbers according to IEEE 754. The <
1242 * comparison will be true if and only if the first number is less than the
1243 * second number. The <= comparison will be true if and only if the first
1244 * number is less than or equal to the second number. The > comparison
1245 * will be true if and only if the first number is greater than the second
1246 * number. The >= comparison will be true if and only if the first number
1247 * is greater than or equal to the second number.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001248 */
1249int
Daniel Veillard991e63d1999-08-15 23:32:28 +00001250xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1251 int ret = 0;
1252 xmlXPathObjectPtr arg1, arg2;
1253
1254 arg2 = valuePop(ctxt);
1255 if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1256 if (arg2 != NULL)
1257 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001258 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001259 }
1260
1261 arg1 = valuePop(ctxt);
1262 if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1263 if (arg1 != NULL)
1264 xmlXPathFreeObject(arg1);
1265 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001266 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001267 }
1268
1269 if (arg1->type != XPATH_NUMBER) {
1270 valuePush(ctxt, arg1);
1271 xmlXPathNumberFunction(ctxt, 1);
1272 arg1 = valuePop(ctxt);
1273 }
1274 if (arg1->type != XPATH_NUMBER) {
1275 xmlXPathFreeObject(arg1);
1276 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001277 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001278 }
1279 if (arg2->type != XPATH_NUMBER) {
1280 valuePush(ctxt, arg2);
1281 xmlXPathNumberFunction(ctxt, 1);
1282 arg2 = valuePop(ctxt);
1283 }
1284 if (arg2->type != XPATH_NUMBER) {
1285 xmlXPathFreeObject(arg1);
1286 xmlXPathFreeObject(arg2);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00001287 XP_ERROR0(XPATH_INVALID_OPERAND);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001288 }
1289 /*
1290 * Add tests for infinity and nan
1291 * => feedback on 3.4 for Inf and NaN
1292 */
1293 if (inf && strict)
1294 ret = (arg1->floatval < arg2->floatval);
1295 else if (inf && !strict)
1296 ret = (arg1->floatval <= arg2->floatval);
1297 else if (!inf && strict)
1298 ret = (arg1->floatval > arg2->floatval);
1299 else if (!inf && !strict)
1300 ret = (arg1->floatval >= arg2->floatval);
1301 xmlXPathFreeObject(arg1);
1302 xmlXPathFreeObject(arg2);
1303 return(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001304}
1305
1306/**
1307 * xmlXPathValueFlipSign:
1308 * @ctxt: the XPath Parser context
1309 *
1310 * Implement the unary - operation on an XPath object
1311 * The numeric operators convert their operands to numbers as if
1312 * by calling the number function.
1313 */
1314void
1315xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1316 xmlXPathObjectPtr arg;
1317
1318 POP_FLOAT
1319 arg->floatval = -arg->floatval;
1320 valuePush(ctxt, arg);
1321}
1322
1323/**
1324 * xmlXPathAddValues:
1325 * @ctxt: the XPath Parser context
1326 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001327 * Implement the add operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001328 * The numeric operators convert their operands to numbers as if
1329 * by calling the number function.
1330 */
1331void
1332xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1333 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001334 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001335
1336 POP_FLOAT
1337 val = arg->floatval;
1338 xmlXPathFreeObject(arg);
1339
1340 POP_FLOAT
1341 arg->floatval += val;
1342 valuePush(ctxt, arg);
1343}
1344
1345/**
1346 * xmlXPathSubValues:
1347 * @ctxt: the XPath Parser context
1348 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001349 * Implement the substraction operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001350 * The numeric operators convert their operands to numbers as if
1351 * by calling the number function.
1352 */
1353void
1354xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1355 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001356 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001357
1358 POP_FLOAT
1359 val = arg->floatval;
1360 xmlXPathFreeObject(arg);
1361
1362 POP_FLOAT
1363 arg->floatval -= val;
1364 valuePush(ctxt, arg);
1365}
1366
1367/**
1368 * xmlXPathMultValues:
1369 * @ctxt: the XPath Parser context
1370 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001371 * Implement the multiply operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001372 * The numeric operators convert their operands to numbers as if
1373 * by calling the number function.
1374 */
1375void
1376xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1377 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001378 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001379
1380 POP_FLOAT
1381 val = arg->floatval;
1382 xmlXPathFreeObject(arg);
1383
1384 POP_FLOAT
1385 arg->floatval *= val;
1386 valuePush(ctxt, arg);
1387}
1388
1389/**
1390 * xmlXPathDivValues:
1391 * @ctxt: the XPath Parser context
1392 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001393 * Implement the div operation on XPath objects:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001394 * The numeric operators convert their operands to numbers as if
1395 * by calling the number function.
1396 */
1397void
1398xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1399 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001400 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001401
1402 POP_FLOAT
1403 val = arg->floatval;
1404 xmlXPathFreeObject(arg);
1405
1406 POP_FLOAT
1407 arg->floatval /= val;
1408 valuePush(ctxt, arg);
1409}
1410
1411/**
1412 * xmlXPathModValues:
1413 * @ctxt: the XPath Parser context
1414 *
1415 * Implement the div operation on XPath objects: @arg1 / @arg2
1416 * The numeric operators convert their operands to numbers as if
1417 * by calling the number function.
1418 */
1419void
1420xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1421 xmlXPathObjectPtr arg;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00001422 double val;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001423
1424 POP_FLOAT
1425 val = arg->floatval;
1426 xmlXPathFreeObject(arg);
1427
1428 POP_FLOAT
1429 arg->floatval /= val;
1430 valuePush(ctxt, arg);
1431}
1432
1433/************************************************************************
1434 * *
1435 * The traversal functions *
1436 * *
1437 ************************************************************************/
1438
1439#define AXIS_ANCESTOR 1
1440#define AXIS_ANCESTOR_OR_SELF 2
1441#define AXIS_ATTRIBUTE 3
1442#define AXIS_CHILD 4
1443#define AXIS_DESCENDANT 5
1444#define AXIS_DESCENDANT_OR_SELF 6
1445#define AXIS_FOLLOWING 7
1446#define AXIS_FOLLOWING_SIBLING 8
1447#define AXIS_NAMESPACE 9
1448#define AXIS_PARENT 10
1449#define AXIS_PRECEDING 11
1450#define AXIS_PRECEDING_SIBLING 12
1451#define AXIS_SELF 13
1452
1453/*
1454 * A traversal function enumerates nodes along an axis.
1455 * Initially it must be called with NULL, and it indicates
1456 * termination on the axis by returning NULL.
1457 */
1458typedef xmlNodePtr (*xmlXPathTraversalFunction)
1459 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1460
1461/**
1462 * mlXPathNextSelf:
1463 * @ctxt: the XPath Parser context
1464 * @cur: the current node in the traversal
1465 *
1466 * Traversal function for the "self" direction
1467 * he self axis contains just the context node itself
Daniel Veillardb96e6431999-08-29 21:02:19 +00001468 *
1469 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001470 */
1471xmlNodePtr
1472xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1473 if (cur == NULL)
1474 return(ctxt->context->node);
1475 return(NULL);
1476}
1477
1478/**
1479 * mlXPathNextChild:
1480 * @ctxt: the XPath Parser context
1481 * @cur: the current node in the traversal
1482 *
1483 * Traversal function for the "child" direction
1484 * The child axis contains the children of the context node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001485 *
1486 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001487 */
1488xmlNodePtr
1489xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001490 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001491 if (ctxt->context->node == NULL) return(NULL);
1492 switch (ctxt->context->node->type) {
1493 case XML_ELEMENT_NODE:
1494 case XML_TEXT_NODE:
1495 case XML_CDATA_SECTION_NODE:
1496 case XML_ENTITY_REF_NODE:
1497 case XML_ENTITY_NODE:
1498 case XML_PI_NODE:
1499 case XML_COMMENT_NODE:
1500 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001501 case XML_DTD_NODE:
1502 return(ctxt->context->node->children);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001503 case XML_DOCUMENT_NODE:
1504 case XML_DOCUMENT_TYPE_NODE:
1505 case XML_DOCUMENT_FRAG_NODE:
1506 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001507 return(((xmlDocPtr) ctxt->context->node)->children);
1508 case XML_ELEMENT_DECL:
1509 case XML_ATTRIBUTE_DECL:
1510 case XML_ENTITY_DECL:
1511 case XML_ATTRIBUTE_NODE:
1512 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001513 }
1514 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001515 }
Daniel Veillarddbfd6411999-12-28 16:35:14 +00001516 if ((cur->type == XML_DOCUMENT_NODE) ||
1517 (cur->type == XML_HTML_DOCUMENT_NODE))
Daniel Veillardb05deb71999-08-10 19:04:08 +00001518 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001519 return(cur->next);
1520}
1521
1522/**
1523 * mlXPathNextDescendant:
1524 * @ctxt: the XPath Parser context
1525 * @cur: the current node in the traversal
1526 *
1527 * Traversal function for the "descendant" direction
1528 * the descendant axis contains the descendants of the context node in document
1529 * order; a descendant is a child or a child of a child and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001530 *
1531 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001532 */
1533xmlNodePtr
1534xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001535 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001536 if (ctxt->context->node == NULL)
1537 return(NULL);
1538 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1539 return(NULL);
1540
Daniel Veillardb05deb71999-08-10 19:04:08 +00001541 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
Daniel Veillardcf461992000-03-14 18:30:20 +00001542 return(ctxt->context->doc->children);
1543 return(ctxt->context->node->children);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001544 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001545
Daniel Veillardbe803962000-06-28 23:40:59 +00001546 if (cur->children != NULL)
1547 {
1548 if (cur->children->type != XML_ENTITY_DECL)
1549 return(cur->children);
1550 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001551 if (cur->next != NULL) return(cur->next);
1552
1553 do {
1554 cur = cur->parent;
1555 if (cur == NULL) return(NULL);
1556 if (cur == ctxt->context->node) return(NULL);
1557 if (cur->next != NULL) {
1558 cur = cur->next;
1559 return(cur);
1560 }
1561 } while (cur != NULL);
1562 return(cur);
1563}
1564
1565/**
1566 * mlXPathNextDescendantOrSelf:
1567 * @ctxt: the XPath Parser context
1568 * @cur: the current node in the traversal
1569 *
1570 * Traversal function for the "descendant-or-self" direction
1571 * the descendant-or-self axis contains the context node and the descendants
1572 * of the context node in document order; thus the context node is the first
1573 * node on the axis, and the first child of the context node is the second node
1574 * on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001575 *
1576 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001577 */
1578xmlNodePtr
1579xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001580 if (cur == NULL) {
1581 if (ctxt->context->node == NULL)
1582 return(NULL);
1583 if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1584 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001585 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001586 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001587
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001588 return(xmlXPathNextDescendant(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001589}
1590
1591/**
1592 * xmlXPathNextParent:
1593 * @ctxt: the XPath Parser context
1594 * @cur: the current node in the traversal
1595 *
1596 * Traversal function for the "parent" direction
1597 * The parent axis contains the parent of the context node, if there is one.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001598 *
1599 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001600 */
1601xmlNodePtr
1602xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1603 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001604 * the parent of an attribute or namespace node is the element
1605 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001606 * Namespace handling !!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001607 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001608 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001609 if (ctxt->context->node == NULL) return(NULL);
1610 switch (ctxt->context->node->type) {
1611 case XML_ELEMENT_NODE:
1612 case XML_TEXT_NODE:
1613 case XML_CDATA_SECTION_NODE:
1614 case XML_ENTITY_REF_NODE:
1615 case XML_ENTITY_NODE:
1616 case XML_PI_NODE:
1617 case XML_COMMENT_NODE:
1618 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001619 case XML_DTD_NODE:
1620 case XML_ELEMENT_DECL:
1621 case XML_ATTRIBUTE_DECL:
1622 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001623 if (ctxt->context->node->parent == NULL)
1624 return((xmlNodePtr) ctxt->context->doc);
1625 return(ctxt->context->node->parent);
1626 case XML_ATTRIBUTE_NODE: {
1627 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1628
Daniel Veillardcf461992000-03-14 18:30:20 +00001629 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001630 }
1631 case XML_DOCUMENT_NODE:
1632 case XML_DOCUMENT_TYPE_NODE:
1633 case XML_DOCUMENT_FRAG_NODE:
1634 case XML_HTML_DOCUMENT_NODE:
1635 return(NULL);
1636 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00001637 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001638 return(NULL);
1639}
1640
1641/**
1642 * xmlXPathNextAncestor:
1643 * @ctxt: the XPath Parser context
1644 * @cur: the current node in the traversal
1645 *
1646 * Traversal function for the "ancestor" direction
1647 * the ancestor axis contains the ancestors of the context node; the ancestors
1648 * of the context node consist of the parent of context node and the parent's
1649 * parent and so on; the nodes are ordered in reverse document order; thus the
1650 * parent is the first node on the axis, and the parent's parent is the second
1651 * node on the axis
Daniel Veillardb96e6431999-08-29 21:02:19 +00001652 *
1653 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001654 */
1655xmlNodePtr
1656xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1657 /*
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001658 * the parent of an attribute or namespace node is the element
1659 * to which the attribute or namespace node is attached
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001660 * !!!!!!!!!!!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001661 */
Daniel Veillardb05deb71999-08-10 19:04:08 +00001662 if (cur == NULL) {
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001663 if (ctxt->context->node == NULL) return(NULL);
1664 switch (ctxt->context->node->type) {
1665 case XML_ELEMENT_NODE:
1666 case XML_TEXT_NODE:
1667 case XML_CDATA_SECTION_NODE:
1668 case XML_ENTITY_REF_NODE:
1669 case XML_ENTITY_NODE:
1670 case XML_PI_NODE:
1671 case XML_COMMENT_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001672 case XML_DTD_NODE:
1673 case XML_ELEMENT_DECL:
1674 case XML_ATTRIBUTE_DECL:
1675 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001676 case XML_NOTATION_NODE:
1677 if (ctxt->context->node->parent == NULL)
1678 return((xmlNodePtr) ctxt->context->doc);
1679 return(ctxt->context->node->parent);
1680 case XML_ATTRIBUTE_NODE: {
1681 xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
1682
Daniel Veillardcf461992000-03-14 18:30:20 +00001683 return(cur->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001684 }
1685 case XML_DOCUMENT_NODE:
1686 case XML_DOCUMENT_TYPE_NODE:
1687 case XML_DOCUMENT_FRAG_NODE:
1688 case XML_HTML_DOCUMENT_NODE:
1689 return(NULL);
1690 }
1691 return(NULL);
Daniel Veillardb05deb71999-08-10 19:04:08 +00001692 }
Daniel Veillardcf461992000-03-14 18:30:20 +00001693 if (cur == ctxt->context->doc->children)
Daniel Veillardb05deb71999-08-10 19:04:08 +00001694 return((xmlNodePtr) ctxt->context->doc);
1695 if (cur == (xmlNodePtr) ctxt->context->doc)
1696 return(NULL);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001697 switch (cur->type) {
1698 case XML_ELEMENT_NODE:
1699 case XML_TEXT_NODE:
1700 case XML_CDATA_SECTION_NODE:
1701 case XML_ENTITY_REF_NODE:
1702 case XML_ENTITY_NODE:
1703 case XML_PI_NODE:
1704 case XML_COMMENT_NODE:
1705 case XML_NOTATION_NODE:
Daniel Veillardcf461992000-03-14 18:30:20 +00001706 case XML_DTD_NODE:
1707 case XML_ELEMENT_DECL:
1708 case XML_ATTRIBUTE_DECL:
1709 case XML_ENTITY_DECL:
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001710 return(cur->parent);
1711 case XML_ATTRIBUTE_NODE: {
1712 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
1713
Daniel Veillardcf461992000-03-14 18:30:20 +00001714 return(att->parent);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001715 }
1716 case XML_DOCUMENT_NODE:
1717 case XML_DOCUMENT_TYPE_NODE:
1718 case XML_DOCUMENT_FRAG_NODE:
1719 case XML_HTML_DOCUMENT_NODE:
1720 return(NULL);
1721 }
1722 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001723}
1724
1725/**
1726 * xmlXPathNextAncestorOrSelf:
1727 * @ctxt: the XPath Parser context
1728 * @cur: the current node in the traversal
1729 *
1730 * Traversal function for the "ancestor-or-self" direction
Daniel Veillardb96e6431999-08-29 21:02:19 +00001731 * he ancestor-or-self axis contains the context node and ancestors of
1732 * the context node in reverse document order; thus the context node is
1733 * the first node on the axis, and the context node's parent the second;
1734 * parent here is defined the same as with the parent axis.
1735 *
1736 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001737 */
1738xmlNodePtr
1739xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001740 if (cur == NULL)
1741 return(ctxt->context->node);
Daniel Veillarde3d88ef2000-01-24 13:55:06 +00001742 return(xmlXPathNextAncestor(ctxt, cur));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001743}
1744
1745/**
1746 * xmlXPathNextFollowingSibling:
1747 * @ctxt: the XPath Parser context
1748 * @cur: the current node in the traversal
1749 *
1750 * Traversal function for the "following-sibling" direction
1751 * The following-sibling axis contains the following siblings of the context
1752 * node in document order.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001753 *
1754 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001755 */
1756xmlNodePtr
1757xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001758 if (cur == (xmlNodePtr) ctxt->context->doc)
1759 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001760 if (cur == NULL)
1761 return(ctxt->context->node->next);
1762 return(cur->next);
1763}
1764
1765/**
1766 * xmlXPathNextPrecedingSibling:
1767 * @ctxt: the XPath Parser context
1768 * @cur: the current node in the traversal
1769 *
1770 * Traversal function for the "preceding-sibling" direction
1771 * The preceding-sibling axis contains the preceding siblings of the context
1772 * node in reverse document order; the first preceding sibling is first on the
1773 * axis; the sibling preceding that node is the second on the axis and so on.
Daniel Veillardb96e6431999-08-29 21:02:19 +00001774 *
1775 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001776 */
1777xmlNodePtr
1778xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001779 if (cur == (xmlNodePtr) ctxt->context->doc)
1780 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001781 if (cur == NULL)
1782 return(ctxt->context->node->prev);
1783 return(cur->prev);
1784}
1785
1786/**
1787 * xmlXPathNextFollowing:
1788 * @ctxt: the XPath Parser context
1789 * @cur: the current node in the traversal
1790 *
1791 * Traversal function for the "following" direction
1792 * The following axis contains all nodes in the same document as the context
1793 * node that are after the context node in document order, excluding any
1794 * descendants and excluding attribute nodes and namespace nodes; the nodes
1795 * are ordered in document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001796 *
1797 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001798 */
1799xmlNodePtr
1800xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001801 if (cur == (xmlNodePtr) ctxt->context->doc)
1802 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001803 if (cur == NULL)
1804 return(ctxt->context->node->next);; /* !!!!!!!!! */
Daniel Veillardcf461992000-03-14 18:30:20 +00001805 if (cur->children != NULL) return(cur->children);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001806 if (cur->next != NULL) return(cur->next);
1807
1808 do {
1809 cur = cur->parent;
1810 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00001811 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001812 if (cur->next != NULL) {
1813 cur = cur->next;
1814 return(cur);
1815 }
1816 } while (cur != NULL);
1817 return(cur);
1818}
1819
1820/**
1821 * xmlXPathNextPreceding:
1822 * @ctxt: the XPath Parser context
1823 * @cur: the current node in the traversal
1824 *
1825 * Traversal function for the "preceding" direction
1826 * the preceding axis contains all nodes in the same document as the context
1827 * node that are before the context node in document order, excluding any
1828 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
1829 * ordered in reverse document order
Daniel Veillardb96e6431999-08-29 21:02:19 +00001830 *
1831 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001832 */
1833xmlNodePtr
1834xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillardb05deb71999-08-10 19:04:08 +00001835 if (cur == (xmlNodePtr) ctxt->context->doc)
1836 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001837 if (cur == NULL)
1838 return(ctxt->context->node->prev); /* !!!!!!!!! */
1839 if (cur->last != NULL) return(cur->last);
1840 if (cur->prev != NULL) return(cur->prev);
1841
1842 do {
1843 cur = cur->parent;
1844 if (cur == NULL) return(NULL);
Daniel Veillardcf461992000-03-14 18:30:20 +00001845 if (cur == ctxt->context->doc->children) return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001846 if (cur->prev != NULL) {
1847 cur = cur->prev;
1848 return(cur);
1849 }
1850 } while (cur != NULL);
1851 return(cur);
1852}
1853
1854/**
1855 * xmlXPathNextNamespace:
1856 * @ctxt: the XPath Parser context
1857 * @cur: the current attribute in the traversal
1858 *
1859 * Traversal function for the "namespace" direction
1860 * the namespace axis contains the namespace nodes of the context node;
1861 * the order of nodes on this axis is implementation-defined; the axis will
1862 * be empty unless the context node is an element
Daniel Veillardb96e6431999-08-29 21:02:19 +00001863 *
1864 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001865 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00001866xmlNsPtr
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001867xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00001868 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
1869 if (ctxt->context->namespaces != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00001870 xmlFree(ctxt->context->namespaces);
Daniel Veillardb96e6431999-08-29 21:02:19 +00001871 ctxt->context->namespaces =
1872 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
1873 if (ctxt->context->namespaces == NULL) return(NULL);
1874 ctxt->context->nsNr = 0;
1875 }
1876 return(ctxt->context->namespaces[ctxt->context->nsNr++]);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001877}
1878
1879/**
1880 * xmlXPathNextAttribute:
1881 * @ctxt: the XPath Parser context
1882 * @cur: the current attribute in the traversal
1883 *
1884 * Traversal function for the "attribute" direction
Daniel Veillard10a2c651999-12-12 13:03:50 +00001885 * TODO: support DTD inherited default attributes
Daniel Veillardb96e6431999-08-29 21:02:19 +00001886 *
1887 * Returns the next element following that axis
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001888 */
1889xmlAttrPtr
1890xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00001891 if (cur == NULL) {
1892 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1893 return(NULL);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001894 return(ctxt->context->node->properties);
Daniel Veillard991e63d1999-08-15 23:32:28 +00001895 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001896 return(cur->next);
1897}
1898
1899/************************************************************************
1900 * *
1901 * NodeTest Functions *
1902 * *
1903 ************************************************************************/
1904
1905#define NODE_TEST_NONE 0
1906#define NODE_TEST_TYPE 1
1907#define NODE_TEST_PI 2
1908#define NODE_TEST_ALL 3
1909#define NODE_TEST_NS 4
1910#define NODE_TEST_NAME 5
1911
1912#define NODE_TYPE_COMMENT 50
1913#define NODE_TYPE_TEXT 51
1914#define NODE_TYPE_PI 52
1915#define NODE_TYPE_NODE 53
1916
1917#define IS_FUNCTION 200
1918
1919/**
1920 * xmlXPathNodeCollectAndTest:
1921 * @ctxt: the XPath Parser context
1922 * @cur: the current node to test
1923 *
1924 * This is the function implementing a step: based on the current list
1925 * of nodes, it builds up a new list, looking at all nodes under that
1926 * axis and selecting them.
1927 *
1928 * Returns the new NodeSet resulting from the search.
1929 */
1930xmlNodeSetPtr
1931xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int axis,
Daniel Veillarddd6b3671999-09-23 22:19:22 +00001932 int test, int type, const xmlChar *prefix, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001933#ifdef DEBUG_STEP
1934 int n = 0, t = 0;
1935#endif
1936 int i;
1937 xmlNodeSetPtr ret;
1938 xmlXPathTraversalFunction next = NULL;
1939 xmlNodePtr cur = NULL;
1940
1941 if (ctxt->context->nodelist == NULL) {
1942 if (ctxt->context->node == NULL) {
1943 fprintf(xmlXPathDebug,
1944 "xmlXPathNodeCollectAndTest %s:%d : nodelist and node are NULL\n",
1945 __FILE__, __LINE__);
1946 return(NULL);
1947 }
1948 STRANGE
1949 return(NULL);
1950 }
1951#ifdef DEBUG_STEP
1952 fprintf(xmlXPathDebug, "new step : ");
1953#endif
1954 switch (axis) {
1955 case AXIS_ANCESTOR:
1956#ifdef DEBUG_STEP
1957 fprintf(xmlXPathDebug, "axis 'ancestors' ");
1958#endif
1959 next = xmlXPathNextAncestor; break;
1960 case AXIS_ANCESTOR_OR_SELF:
1961#ifdef DEBUG_STEP
1962 fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1963#endif
1964 next = xmlXPathNextAncestorOrSelf; break;
1965 case AXIS_ATTRIBUTE:
1966#ifdef DEBUG_STEP
1967 fprintf(xmlXPathDebug, "axis 'attributes' ");
1968#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00001969 next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00001970 break;
1971 case AXIS_CHILD:
1972#ifdef DEBUG_STEP
1973 fprintf(xmlXPathDebug, "axis 'child' ");
1974#endif
1975 next = xmlXPathNextChild; break;
1976 case AXIS_DESCENDANT:
1977#ifdef DEBUG_STEP
1978 fprintf(xmlXPathDebug, "axis 'descendant' ");
1979#endif
1980 next = xmlXPathNextDescendant; break;
1981 case AXIS_DESCENDANT_OR_SELF:
1982#ifdef DEBUG_STEP
1983 fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1984#endif
1985 next = xmlXPathNextDescendantOrSelf; break;
1986 case AXIS_FOLLOWING:
1987#ifdef DEBUG_STEP
1988 fprintf(xmlXPathDebug, "axis 'following' ");
1989#endif
1990 next = xmlXPathNextFollowing; break;
1991 case AXIS_FOLLOWING_SIBLING:
1992#ifdef DEBUG_STEP
1993 fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1994#endif
1995 next = xmlXPathNextFollowingSibling; break;
1996 case AXIS_NAMESPACE:
1997#ifdef DEBUG_STEP
1998 fprintf(xmlXPathDebug, "axis 'namespace' ");
1999#endif
Daniel Veillardb96e6431999-08-29 21:02:19 +00002000 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002001 break;
2002 case AXIS_PARENT:
2003#ifdef DEBUG_STEP
2004 fprintf(xmlXPathDebug, "axis 'parent' ");
2005#endif
2006 next = xmlXPathNextParent; break;
2007 case AXIS_PRECEDING:
2008#ifdef DEBUG_STEP
2009 fprintf(xmlXPathDebug, "axis 'preceding' ");
2010#endif
2011 next = xmlXPathNextPreceding; break;
2012 case AXIS_PRECEDING_SIBLING:
2013#ifdef DEBUG_STEP
2014 fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
2015#endif
2016 next = xmlXPathNextPrecedingSibling; break;
2017 case AXIS_SELF:
2018#ifdef DEBUG_STEP
2019 fprintf(xmlXPathDebug, "axis 'self' ");
2020#endif
2021 next = xmlXPathNextSelf; break;
2022 }
2023 if (next == NULL) return(NULL);
2024 ret = xmlXPathNodeSetCreate(NULL);
2025#ifdef DEBUG_STEP
2026 fprintf(xmlXPathDebug, " context contains %d nodes\n",
2027 ctxt->context->nodelist->nodeNr);
2028 switch (test) {
2029 case NODE_TEST_NONE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002030 fprintf(xmlXPathDebug, " searching for none !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002031 break;
2032 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002033 fprintf(xmlXPathDebug, " searching for type %d\n", type);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002034 break;
2035 case NODE_TEST_PI:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002036 fprintf(xmlXPathDebug, " searching for PI !!!\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002037 break;
2038 case NODE_TEST_ALL:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002039 fprintf(xmlXPathDebug, " searching for *\n");
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002040 break;
2041 case NODE_TEST_NS:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002042 fprintf(xmlXPathDebug, " searching for namespace %s\n",
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002043 prefix);
2044 break;
2045 case NODE_TEST_NAME:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002046 fprintf(xmlXPathDebug, " searching for name %s\n", name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002047 if (prefix != NULL)
2048 fprintf(xmlXPathDebug, " with namespace %s\n",
2049 prefix);
2050 break;
2051 }
2052 fprintf(xmlXPathDebug, "Testing : ");
2053#endif
2054 for (i = 0;i < ctxt->context->nodelist->nodeNr; i++) {
2055 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
2056
2057 cur = NULL;
2058 do {
2059 cur = next(ctxt, cur);
2060 if (cur == NULL) break;
2061#ifdef DEBUG_STEP
2062 t++;
2063 fprintf(xmlXPathDebug, " %s", cur->name);
2064#endif
2065 switch (test) {
2066 case NODE_TEST_NONE:
2067 STRANGE
2068 return(NULL);
2069 case NODE_TEST_TYPE:
Daniel Veillarddbfd6411999-12-28 16:35:14 +00002070 if ((cur->type == type) ||
2071 ((type == XML_ELEMENT_NODE) &&
2072 ((cur->type == XML_DOCUMENT_NODE) ||
2073 (cur->type == XML_HTML_DOCUMENT_NODE)))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002074#ifdef DEBUG_STEP
2075 n++;
2076#endif
2077 xmlXPathNodeSetAdd(ret, cur);
2078 }
2079 break;
2080 case NODE_TEST_PI:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002081 if (cur->type == XML_PI_NODE) {
2082 if ((name != NULL) &&
2083 (xmlStrcmp(name, cur->name)))
2084 break;
2085#ifdef DEBUG_STEP
2086 n++;
2087#endif
2088 xmlXPathNodeSetAdd(ret, cur);
2089 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002090 break;
2091 case NODE_TEST_ALL:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002092 if ((cur->type == XML_ELEMENT_NODE) ||
2093 (cur->type == XML_ATTRIBUTE_NODE)) {
2094 /* !!! || (cur->type == XML_TEXT_NODE)) { */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002095#ifdef DEBUG_STEP
2096 n++;
2097#endif
2098 xmlXPathNodeSetAdd(ret, cur);
2099 }
2100 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002101 case NODE_TEST_NS: {
2102 TODO /* namespace search */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002103 break;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002104 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002105 case NODE_TEST_NAME:
Daniel Veillardb05deb71999-08-10 19:04:08 +00002106 switch (cur->type) {
2107 case XML_ELEMENT_NODE:
2108 if (!xmlStrcmp(name, cur->name) &&
2109 (((prefix == NULL) ||
2110 ((cur->ns != NULL) &&
2111 (!xmlStrcmp(prefix, cur->ns->href)))))) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002112#ifdef DEBUG_STEP
Daniel Veillardb05deb71999-08-10 19:04:08 +00002113 n++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002114#endif
Daniel Veillardb05deb71999-08-10 19:04:08 +00002115 xmlXPathNodeSetAdd(ret, cur);
2116 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00002117 break;
2118 case XML_ATTRIBUTE_NODE: {
2119 xmlAttrPtr attr = (xmlAttrPtr) cur;
2120 if (!xmlStrcmp(name, attr->name)) {
2121#ifdef DEBUG_STEP
2122 n++;
2123#endif
2124 xmlXPathNodeSetAdd(ret, cur);
2125 }
2126 break;
2127 }
Daniel Veillardb05deb71999-08-10 19:04:08 +00002128 default:
2129 break;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002130 }
2131 break;
2132
2133 }
2134 } while (cur != NULL);
2135 }
2136#ifdef DEBUG_STEP
2137 fprintf(xmlXPathDebug,
2138 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
2139#endif
2140 return(ret);
2141}
2142
2143
2144/************************************************************************
2145 * *
2146 * Implicit tree core function library *
2147 * *
2148 ************************************************************************/
2149
2150/**
2151 * xmlXPathRoot:
2152 * @ctxt: the XPath Parser context
2153 *
2154 * Initialize the context to the root of the document
2155 */
2156void
2157xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
2158 if (ctxt->context->nodelist != NULL)
2159 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardb05deb71999-08-10 19:04:08 +00002160 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
2161 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002162}
2163
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002164/************************************************************************
2165 * *
2166 * The explicit core function library *
2167 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2168 * *
2169 ************************************************************************/
2170
2171
2172/**
2173 * xmlXPathLastFunction:
2174 * @ctxt: the XPath Parser context
2175 *
2176 * Implement the last() XPath function
2177 * The last function returns the number of nodes in the context node list.
2178 */
2179void
2180xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2181 CHECK_ARITY(0);
2182 if ((ctxt->context->nodelist == NULL) ||
2183 (ctxt->context->node == NULL) ||
2184 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002185 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002186 } else {
2187 valuePush(ctxt,
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002188 xmlXPathNewFloat((double) ctxt->context->nodelist->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002189 }
2190}
2191
2192/**
2193 * xmlXPathPositionFunction:
2194 * @ctxt: the XPath Parser context
2195 *
2196 * Implement the position() XPath function
2197 * The position function returns the position of the context node in the
2198 * context node list. The first position is 1, and so the last positionr
2199 * will be equal to last().
2200 */
2201void
2202xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2203 int i;
2204
2205 CHECK_ARITY(0);
2206 if ((ctxt->context->nodelist == NULL) ||
2207 (ctxt->context->node == NULL) ||
2208 (ctxt->context->nodelist->nodeNr == 0)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002209 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002210 }
2211 for (i = 0; i < ctxt->context->nodelist->nodeNr;i++) {
2212 if (ctxt->context->node == ctxt->context->nodelist->nodeTab[i]) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002213 valuePush(ctxt, xmlXPathNewFloat((double) i + 1));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002214 return;
2215 }
2216 }
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002217 valuePush(ctxt, xmlXPathNewFloat((double) 0));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002218}
2219
2220/**
2221 * xmlXPathCountFunction:
2222 * @ctxt: the XPath Parser context
2223 *
2224 * Implement the count() XPath function
2225 */
2226void
2227xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2228 xmlXPathObjectPtr cur;
2229
2230 CHECK_ARITY(1);
2231 CHECK_TYPE(XPATH_NODESET);
2232 cur = valuePop(ctxt);
2233
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002234 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002235 xmlXPathFreeObject(cur);
2236}
2237
2238/**
2239 * xmlXPathIdFunction:
2240 * @ctxt: the XPath Parser context
2241 *
2242 * Implement the id() XPath function
2243 * The id function selects elements by their unique ID
2244 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2245 * then the result is the union of the result of applying id to the
2246 * string value of each of the nodes in the argument node-set. When the
2247 * argument to id is of any other type, the argument is converted to a
2248 * string as if by a call to the string function; the string is split
2249 * into a whitespace-separated list of tokens (whitespace is any sequence
2250 * of characters matching the production S); the result is a node-set
2251 * containing the elements in the same document as the context node that
2252 * have a unique ID equal to any of the tokens in the list.
2253 */
2254void
2255xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002256 const xmlChar *tokens;
2257 const xmlChar *cur;
2258 xmlChar *ID;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002259 xmlAttrPtr attr;
2260 xmlNodePtr elem = NULL;
2261 xmlXPathObjectPtr ret, obj;
2262
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002263 CHECK_ARITY(1);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002264 obj = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002265 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002266 if (obj->type == XPATH_NODESET) {
2267 TODO /* ID function in case of NodeSet */
2268 }
2269 if (obj->type != XPATH_STRING) {
2270 valuePush(ctxt, obj);
2271 xmlXPathStringFunction(ctxt, 1);
2272 obj = valuePop(ctxt);
2273 if (obj->type != XPATH_STRING) {
2274 xmlXPathFreeObject(obj);
2275 return;
2276 }
2277 }
2278 tokens = obj->stringval;
2279
2280 ret = xmlXPathNewNodeSet(NULL);
2281 valuePush(ctxt, ret);
2282 if (tokens == NULL) {
2283 xmlXPathFreeObject(obj);
2284 return;
2285 }
2286
2287 cur = tokens;
2288
2289 while (IS_BLANK(*cur)) cur++;
2290 while (*cur != 0) {
2291 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2292 (*cur == '.') || (*cur == '-') ||
2293 (*cur == '_') || (*cur == ':') ||
2294 (IS_COMBINING(*cur)) ||
2295 (IS_EXTENDER(*cur)))
2296 cur++;
2297
2298 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2299
2300 ID = xmlStrndup(tokens, cur - tokens);
2301 attr = xmlGetID(ctxt->context->doc, ID);
2302 if (attr != NULL) {
Daniel Veillardcf461992000-03-14 18:30:20 +00002303 elem = attr->parent;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002304 xmlXPathNodeSetAdd(ret->nodesetval, elem);
2305 }
2306 if (ID != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00002307 xmlFree(ID);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002308
2309 while (IS_BLANK(*cur)) cur++;
2310 tokens = cur;
2311 }
2312 xmlXPathFreeObject(obj);
2313 return;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002314}
2315
2316/**
2317 * xmlXPathLocalPartFunction:
2318 * @ctxt: the XPath Parser context
2319 *
2320 * Implement the local-part() XPath function
2321 * The local-part function returns a string containing the local part
2322 * of the name of the node in the argument node-set that is first in
2323 * document order. If the node-set is empty or the first node has no
2324 * name, an empty string is returned. If the argument is omitted it
2325 * defaults to the context node.
2326 */
2327void
2328xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2329 xmlXPathObjectPtr cur;
2330
2331 CHECK_ARITY(1);
2332 CHECK_TYPE(XPATH_NODESET);
2333 cur = valuePop(ctxt);
2334
2335 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002336 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002337 } else {
2338 int i = 0; /* Should be first in document order !!!!! */
2339 valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2340 }
2341 xmlXPathFreeObject(cur);
2342}
2343
2344/**
2345 * xmlXPathNamespaceFunction:
2346 * @ctxt: the XPath Parser context
2347 *
2348 * Implement the namespace() XPath function
2349 * The namespace function returns a string containing the namespace URI
2350 * of the expanded name of the node in the argument node-set that is
2351 * first in document order. If the node-set is empty, the first node has
2352 * no name, or the expanded name has no namespace URI, an empty string
2353 * is returned. If the argument is omitted it defaults to the context node.
2354 */
2355void
2356xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2357 xmlXPathObjectPtr cur;
2358
Daniel Veillardb96e6431999-08-29 21:02:19 +00002359 if (nargs == 0) {
2360 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2361 nargs = 1;
2362 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002363 CHECK_ARITY(1);
2364 CHECK_TYPE(XPATH_NODESET);
2365 cur = valuePop(ctxt);
2366
2367 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002368 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002369 } else {
2370 int i = 0; /* Should be first in document order !!!!! */
2371
2372 if (cur->nodesetval->nodeTab[i]->ns == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002373 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002374 else
2375 valuePush(ctxt, xmlXPathNewString(
2376 cur->nodesetval->nodeTab[i]->ns->href));
2377 }
2378 xmlXPathFreeObject(cur);
2379}
2380
2381/**
2382 * xmlXPathNameFunction:
2383 * @ctxt: the XPath Parser context
2384 *
2385 * Implement the name() XPath function
2386 * The name function returns a string containing a QName representing
2387 * the name of the node in the argument node-set that is first in documenti
2388 * order. The QName must represent the name with respect to the namespace
2389 * declarations in effect on the node whose name is being represented.
2390 * Typically, this will be the form in which the name occurred in the XML
2391 * source. This need not be the case if there are namespace declarations
2392 * in effect on the node that associate multiple prefixes with the same
2393 * namespace. However, an implementation may include information about
2394 * the original prefix in its representation of nodes; in this case, an
2395 * implementation can ensure that the returned string is always the same
2396 * as the QName used in the XML source. If the argument it omitted it
2397 * defaults to the context node.
2398 * Libxml keep the original prefix so the "real qualified name" used is
2399 * returned.
2400 */
2401void
2402xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2403 xmlXPathObjectPtr cur;
2404
2405 CHECK_ARITY(1);
2406 CHECK_TYPE(XPATH_NODESET);
2407 cur = valuePop(ctxt);
2408
2409 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002410 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002411 } else {
2412 int i = 0; /* Should be first in document order !!!!! */
2413
2414 if (cur->nodesetval->nodeTab[i]->ns == NULL)
2415 valuePush(ctxt, xmlXPathNewString(
2416 cur->nodesetval->nodeTab[i]->name));
2417
2418 else {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002419 char name[2000];
2420 sprintf(name, "%s:%s",
2421 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2422 (char *) cur->nodesetval->nodeTab[i]->name);
2423 valuePush(ctxt, xmlXPathNewCString(name));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002424 }
2425 }
2426 xmlXPathFreeObject(cur);
2427}
2428
2429/**
2430 * xmlXPathStringFunction:
2431 * @ctxt: the XPath Parser context
2432 *
2433 * Implement the string() XPath function
2434 * he string function converts an object to a string as follows:
2435 * - A node-set is converted to a string by returning the value of
2436 * the node in the node-set that is first in document order.
2437 * If the node-set is empty, an empty string is returned.
2438 * - A number is converted to a string as follows
2439 * + NaN is converted to the string NaN
2440 * + positive zero is converted to the string 0
2441 * + negative zero is converted to the string 0
2442 * + positive infinity is converted to the string Infinity
2443 * + negative infinity is converted to the string -Infinity
2444 * + if the number is an integer, the number is represented in
2445 * decimal form as a Number with no decimal point and no leading
2446 * zeros, preceded by a minus sign (-) if the number is negative
2447 * + otherwise, the number is represented in decimal form as a
2448 * Number including a decimal point with at least one digit
2449 * before the decimal point and at least one digit after the
2450 * decimal point, preceded by a minus sign (-) if the number
2451 * is negative; there must be no leading zeros before the decimal
2452 * point apart possibly from the one required digit immediatelyi
2453 * before the decimal point; beyond the one required digit
2454 * after the decimal point there must be as many, but only as
2455 * many, more digits as are needed to uniquely distinguish the
2456 * number from all other IEEE 754 numeric values.
2457 * - The boolean false value is converted to the string false.
2458 * The boolean true value is converted to the string true.
2459 */
2460void
2461xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2462 xmlXPathObjectPtr cur;
2463
2464 CHECK_ARITY(1);
2465 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002466 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002467 switch (cur->type) {
2468 case XPATH_NODESET:
2469 if (cur->nodesetval->nodeNr == 0) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002470 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002471 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002472 xmlChar *res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002473 int i = 0; /* Should be first in document order !!!!! */
2474 res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2475 valuePush(ctxt, xmlXPathNewString(res));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002476 xmlFree(res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002477 }
2478 xmlXPathFreeObject(cur);
2479 return;
2480 case XPATH_STRING:
2481 valuePush(ctxt, cur);
2482 return;
2483 case XPATH_BOOLEAN:
Daniel Veillardb96e6431999-08-29 21:02:19 +00002484 if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2485 else valuePush(ctxt, xmlXPathNewCString("false"));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002486 xmlXPathFreeObject(cur);
2487 return;
2488 case XPATH_NUMBER: {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002489 char buf[100];
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002490
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002491 if (isnan(cur->floatval))
2492 sprintf(buf, "NaN");
2493 else if (isinf(cur->floatval) > 0)
2494 sprintf(buf, "+Infinity");
2495 else if (isinf(cur->floatval) < 0)
2496 sprintf(buf, "-Infinity");
2497 else
2498 sprintf(buf, "%0g", cur->floatval);
Daniel Veillardb96e6431999-08-29 21:02:19 +00002499 valuePush(ctxt, xmlXPathNewCString(buf));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002500 xmlXPathFreeObject(cur);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002501 return;
2502 }
2503 }
2504 STRANGE
2505}
2506
2507/**
2508 * xmlXPathStringLengthFunction:
2509 * @ctxt: the XPath Parser context
2510 *
2511 * Implement the string-length() XPath function
2512 * The string-length returns the number of characters in the string
2513 * (see [3.6 Strings]). If the argument is omitted, it defaults to
2514 * the context node converted to a string, in other words the value
2515 * of the context node.
2516 */
2517void
2518xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2519 xmlXPathObjectPtr cur;
2520
2521 if (nargs == 0) {
2522 if (ctxt->context->node == NULL) {
2523 valuePush(ctxt, xmlXPathNewFloat(0));
2524 } else {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002525 xmlChar *content;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002526
2527 content = xmlNodeGetContent(ctxt->context->node);
2528 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002529 xmlFree(content);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002530 }
2531 return;
2532 }
2533 CHECK_ARITY(1);
2534 CHECK_TYPE(XPATH_STRING);
2535 cur = valuePop(ctxt);
2536 valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
2537 xmlXPathFreeObject(cur);
2538}
2539
2540/**
2541 * xmlXPathConcatFunction:
2542 * @ctxt: the XPath Parser context
2543 *
2544 * Implement the concat() XPath function
2545 * The concat function returns the concatenation of its arguments.
2546 */
2547void
2548xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002549 xmlXPathObjectPtr cur, newobj;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002550 xmlChar *tmp;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002551
2552 if (nargs < 2) {
2553 CHECK_ARITY(2);
2554 }
2555
2556 cur = valuePop(ctxt);
2557 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
2558 xmlXPathFreeObject(cur);
2559 return;
2560 }
2561 nargs--;
2562
2563 while (nargs > 0) {
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002564 newobj = valuePop(ctxt);
2565 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
2566 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002567 xmlXPathFreeObject(cur);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002568 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002569 }
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002570 tmp = xmlStrcat(newobj->stringval, cur->stringval);
2571 newobj->stringval = cur->stringval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002572 cur->stringval = tmp;
2573
Daniel Veillard32bc74e2000-07-14 14:49:25 +00002574 xmlXPathFreeObject(newobj);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002575 nargs--;
2576 }
2577 valuePush(ctxt, cur);
2578}
2579
2580/**
2581 * xmlXPathContainsFunction:
2582 * @ctxt: the XPath Parser context
2583 *
2584 * Implement the contains() XPath function
2585 * The contains function returns true if the first argument string
2586 * contains the second argument string, and otherwise returns false.
2587 */
2588void
2589xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2590 xmlXPathObjectPtr hay, needle;
2591
2592 CHECK_ARITY(2);
2593 CHECK_TYPE(XPATH_STRING);
2594 needle = valuePop(ctxt);
2595 hay = valuePop(ctxt);
2596 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2597 xmlXPathFreeObject(hay);
2598 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002599 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002600 }
2601 if (xmlStrstr(hay->stringval, needle->stringval))
2602 valuePush(ctxt, xmlXPathNewBoolean(1));
2603 else
2604 valuePush(ctxt, xmlXPathNewBoolean(0));
2605 xmlXPathFreeObject(hay);
2606 xmlXPathFreeObject(needle);
2607}
2608
2609/**
2610 * xmlXPathStartsWithFunction:
2611 * @ctxt: the XPath Parser context
2612 *
2613 * Implement the starts-with() XPath function
2614 * The starts-with function returns true if the first argument string
2615 * starts with the second argument string, and otherwise returns false.
2616 */
2617void
2618xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2619 xmlXPathObjectPtr hay, needle;
2620 int n;
2621
2622 CHECK_ARITY(2);
2623 CHECK_TYPE(XPATH_STRING);
2624 needle = valuePop(ctxt);
2625 hay = valuePop(ctxt);
2626 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
2627 xmlXPathFreeObject(hay);
2628 xmlXPathFreeObject(needle);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002629 XP_ERROR(XPATH_INVALID_TYPE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002630 }
2631 n = xmlStrlen(needle->stringval);
2632 if (xmlStrncmp(hay->stringval, needle->stringval, n))
2633 valuePush(ctxt, xmlXPathNewBoolean(0));
2634 else
2635 valuePush(ctxt, xmlXPathNewBoolean(1));
2636 xmlXPathFreeObject(hay);
2637 xmlXPathFreeObject(needle);
2638}
2639
2640/**
2641 * xmlXPathSubstringFunction:
2642 * @ctxt: the XPath Parser context
2643 *
2644 * Implement the substring() XPath function
2645 * The substring function returns the substring of the first argument
2646 * starting at the position specified in the second argument with
2647 * length specified in the third argument. For example,
2648 * substring("12345",2,3) returns "234". If the third argument is not
2649 * specified, it returns the substring starting at the position specified
2650 * in the second argument and continuing to the end of the string. For
2651 * example, substring("12345",2) returns "2345". More precisely, each
2652 * character in the string (see [3.6 Strings]) is considered to have a
2653 * numeric position: the position of the first character is 1, the position
2654 * of the second character is 2 and so on. The returned substring contains
2655 * those characters for which the position of the character is greater than
2656 * or equal to the second argument and, if the third argument is specified,
2657 * less than the sum of the second and third arguments; the comparisons
2658 * and addition used for the above follow the standard IEEE 754 rules. Thus:
2659 * - substring("12345", 1.5, 2.6) returns "234"
2660 * - substring("12345", 0, 3) returns "12"
2661 * - substring("12345", 0 div 0, 3) returns ""
2662 * - substring("12345", 1, 0 div 0) returns ""
2663 * - substring("12345", -42, 1 div 0) returns "12345"
2664 * - substring("12345", -1 div 0, 1 div 0) returns ""
2665 */
2666void
2667xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2668 xmlXPathObjectPtr str, start, len;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002669 double le, in;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002670 int i, l;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002671 xmlChar *ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002672
2673 /*
2674 * Conformance needs to be checked !!!!!
2675 */
2676 if (nargs < 2) {
2677 CHECK_ARITY(2);
2678 }
2679 if (nargs > 3) {
2680 CHECK_ARITY(3);
2681 }
2682 if (nargs == 3) {
2683 CHECK_TYPE(XPATH_NUMBER);
2684 len = valuePop(ctxt);
2685 le = len->floatval;
2686 xmlXPathFreeObject(len);
2687 } else {
2688 le = 2000000000;
2689 }
2690 CHECK_TYPE(XPATH_NUMBER);
2691 start = valuePop(ctxt);
2692 in = start->floatval;
2693 xmlXPathFreeObject(start);
2694 CHECK_TYPE(XPATH_STRING);
2695 str = valuePop(ctxt);
2696 le += in;
2697
2698 /* integer index of the first char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002699 i = (int) in;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002700 if (((double)i) != in) i++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002701
2702 /* integer index of the last char */
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002703 l = (int) le;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002704 if (((double)l) != le) l++;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002705
2706 /* back to a zero based len */
2707 i--;
2708 l--;
2709
2710 /* check against the string len */
2711 if (l > 1024) {
2712 l = xmlStrlen(str->stringval);
2713 }
2714 if (i < 0) {
2715 i = 0;
2716 }
2717
2718 /* number of chars to copy */
2719 l -= i;
2720
2721 ret = xmlStrsub(str->stringval, i, l);
2722 if (ret == NULL)
Daniel Veillardb96e6431999-08-29 21:02:19 +00002723 valuePush(ctxt, xmlXPathNewCString(""));
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002724 else {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002725 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00002726 xmlFree(ret);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002727 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002728 xmlXPathFreeObject(str);
2729}
2730
2731/**
2732 * xmlXPathSubstringBeforeFunction:
2733 * @ctxt: the XPath Parser context
2734 *
2735 * Implement the substring-before() XPath function
2736 * The substring-before function returns the substring of the first
2737 * argument string that precedes the first occurrence of the second
2738 * argument string in the first argument string, or the empty string
2739 * if the first argument string does not contain the second argument
2740 * string. For example, substring-before("1999/04/01","/") returns 1999.
2741 */
2742void
2743xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2744 CHECK_ARITY(2);
2745 TODO /* substring before */
2746}
2747
2748/**
2749 * xmlXPathSubstringAfterFunction:
2750 * @ctxt: the XPath Parser context
2751 *
2752 * Implement the substring-after() XPath function
2753 * The substring-after function returns the substring of the first
2754 * argument string that follows the first occurrence of the second
2755 * argument string in the first argument string, or the empty stringi
2756 * if the first argument string does not contain the second argument
2757 * string. For example, substring-after("1999/04/01","/") returns 04/01,
2758 * and substring-after("1999/04/01","19") returns 99/04/01.
2759 */
2760void
2761xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2762 CHECK_ARITY(2);
2763 TODO /* substring after */
2764}
2765
2766/**
2767 * xmlXPathNormalizeFunction:
2768 * @ctxt: the XPath Parser context
2769 *
2770 * Implement the normalize() XPath function
2771 * The normalize function returns the argument string with white
2772 * space normalized by stripping leading and trailing whitespace
2773 * and replacing sequences of whitespace characters by a single
2774 * space. Whitespace characters are the same allowed by the S production
2775 * in XML. If the argument is omitted, it defaults to the context
2776 * node converted to a string, in other words the value of the context node.
2777 */
2778void
2779xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2780 CHECK_ARITY(1);
2781 TODO /* normalize isn't as boring as translate, but pretty much */
2782}
2783
2784/**
2785 * xmlXPathTranslateFunction:
2786 * @ctxt: the XPath Parser context
2787 *
2788 * Implement the translate() XPath function
2789 * The translate function returns the first argument string with
2790 * occurrences of characters in the second argument string replaced
2791 * by the character at the corresponding position in the third argument
2792 * string. For example, translate("bar","abc","ABC") returns the string
2793 * BAr. If there is a character in the second argument string with no
2794 * character at a corresponding position in the third argument string
2795 * (because the second argument string is longer than the third argument
2796 * string), then occurrences of that character in the first argument
2797 * string are removed. For example, translate("--aaa--","abc-","ABC")
2798 * returns "AAA". If a character occurs more than once in second
2799 * argument string, then the first occurrence determines the replacement
2800 * character. If the third argument string is longer than the second
2801 * argument string, then excess characters are ignored.
2802 */
2803void
2804xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2805 CHECK_ARITY(3);
2806 TODO /* translate is boring, waiting for UTF-8 representation too */
2807}
2808
2809/**
2810 * xmlXPathBooleanFunction:
2811 * @ctxt: the XPath Parser context
2812 *
2813 * Implement the boolean() XPath function
2814 * he boolean function converts its argument to a boolean as follows:
2815 * - a number is true if and only if it is neither positive or
2816 * negative zero nor NaN
2817 * - a node-set is true if and only if it is non-empty
2818 * - a string is true if and only if its length is non-zero
2819 */
2820void
2821xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2822 xmlXPathObjectPtr cur;
2823 int res = 0;
2824
2825 CHECK_ARITY(1);
2826 cur = valuePop(ctxt);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00002827 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002828 switch (cur->type) {
2829 case XPATH_NODESET:
2830 if ((cur->nodesetval == NULL) ||
2831 (cur->nodesetval->nodeNr == 0)) res = 0;
2832 else
2833 res = 1;
2834 break;
2835 case XPATH_STRING:
2836 if ((cur->stringval == NULL) ||
2837 (cur->stringval[0] == 0)) res = 0;
2838 else
2839 res = 1;
2840 break;
2841 case XPATH_BOOLEAN:
2842 valuePush(ctxt, cur);
2843 return;
2844 case XPATH_NUMBER:
2845 if (cur->floatval) res = 1;
2846 break;
2847 default:
2848 STRANGE
2849 }
2850 xmlXPathFreeObject(cur);
2851 valuePush(ctxt, xmlXPathNewBoolean(res));
2852}
2853
2854/**
2855 * xmlXPathNotFunction:
2856 * @ctxt: the XPath Parser context
2857 *
2858 * Implement the not() XPath function
2859 * The not function returns true if its argument is false,
2860 * and false otherwise.
2861 */
2862void
2863xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2864 CHECK_ARITY(1);
2865 CHECK_TYPE(XPATH_BOOLEAN);
2866 ctxt->value->boolval = ! ctxt->value->boolval;
2867}
2868
2869/**
2870 * xmlXPathTrueFunction:
2871 * @ctxt: the XPath Parser context
2872 *
2873 * Implement the true() XPath function
2874 */
2875void
2876xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2877 CHECK_ARITY(0);
2878 valuePush(ctxt, xmlXPathNewBoolean(1));
2879}
2880
2881/**
2882 * xmlXPathFalseFunction:
2883 * @ctxt: the XPath Parser context
2884 *
2885 * Implement the false() XPath function
2886 */
2887void
2888xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2889 CHECK_ARITY(0);
2890 valuePush(ctxt, xmlXPathNewBoolean(0));
2891}
2892
2893/**
2894 * xmlXPathLangFunction:
2895 * @ctxt: the XPath Parser context
2896 *
2897 * Implement the lang() XPath function
2898 * The lang function returns true or false depending on whether the
2899 * language of the context node as specified by xml:lang attributes
2900 * is the same as or is a sublanguage of the language specified by
2901 * the argument string. The language of the context node is determined
2902 * by the value of the xml:lang attribute on the context node, or, if
2903 * the context node has no xml:lang attribute, by the value of the
2904 * xml:lang attribute on the nearest ancestor of the context node that
2905 * has an xml:lang attribute. If there is no such attribute, then lang
2906 * returns false. If there is such an attribute, then lang returns
2907 * true if the attribute value is equal to the argument ignoring case,
2908 * or if there is some suffix starting with - such that the attribute
2909 * value is equal to the argument ignoring that suffix of the attribute
2910 * value and ignoring case.
2911 */
2912void
2913xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00002914 xmlXPathObjectPtr val;
Daniel Veillarddd6b3671999-09-23 22:19:22 +00002915 const xmlChar *theLang;
2916 const xmlChar *lang;
Daniel Veillardb96e6431999-08-29 21:02:19 +00002917 int ret = 0;
2918 int i;
2919
2920 CHECK_ARITY(1);
2921 CHECK_TYPE(XPATH_STRING);
2922 val = valuePop(ctxt);
2923 lang = val->stringval;
2924 theLang = xmlNodeGetLang(ctxt->context->node);
2925 if ((theLang != NULL) && (lang != NULL)) {
2926 for (i = 0;lang[i] != 0;i++)
2927 if (toupper(lang[i]) != toupper(theLang[i]))
2928 goto not_equal;
2929 ret = 1;
2930 }
2931not_equal:
2932 xmlXPathFreeObject(val);
2933 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002934}
2935
2936/**
2937 * xmlXPathNumberFunction:
2938 * @ctxt: the XPath Parser context
2939 *
2940 * Implement the number() XPath function
2941 */
2942void
2943xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2944 xmlXPathObjectPtr cur;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002945 double res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002946
2947 CHECK_ARITY(1);
2948 cur = valuePop(ctxt);
2949 switch (cur->type) {
2950 case XPATH_NODESET:
2951 valuePush(ctxt, cur);
2952 xmlXPathStringFunction(ctxt, 1);
2953 cur = valuePop(ctxt);
2954 case XPATH_STRING:
2955 res = xmlXPathStringEvalNumber(cur->stringval);
2956 valuePush(ctxt, xmlXPathNewFloat(res));
2957 xmlXPathFreeObject(cur);
2958 return;
2959 case XPATH_BOOLEAN:
2960 if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
2961 else valuePush(ctxt, xmlXPathNewFloat(0.0));
2962 xmlXPathFreeObject(cur);
2963 return;
2964 case XPATH_NUMBER:
2965 valuePush(ctxt, cur);
2966 return;
2967 }
2968 STRANGE
2969}
2970
2971/**
2972 * xmlXPathSumFunction:
2973 * @ctxt: the XPath Parser context
2974 *
2975 * Implement the sum() XPath function
2976 * The sum function returns the sum of the values of the nodes in
2977 * the argument node-set.
2978 */
2979void
2980xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2981 CHECK_ARITY(1);
2982 TODO /* BUG Sum : don't understand the definition */
2983}
2984
2985/**
2986 * xmlXPathFloorFunction:
2987 * @ctxt: the XPath Parser context
2988 *
2989 * Implement the floor() XPath function
2990 * The floor function returns the largest (closest to positive infinity)
2991 * number that is not greater than the argument and that is an integer.
2992 */
2993void
2994xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2995 CHECK_ARITY(1);
2996 CHECK_TYPE(XPATH_NUMBER);
2997 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00002998 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00002999}
3000
3001/**
3002 * xmlXPathCeilingFunction:
3003 * @ctxt: the XPath Parser context
3004 *
3005 * Implement the ceiling() XPath function
3006 * The ceiling function returns the smallest (closest to negative infinity)
3007 * number that is not less than the argument and that is an integer.
3008 */
3009void
3010xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003011 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003012
3013 CHECK_ARITY(1);
3014 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003015 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003016 if (f != ctxt->value->floatval)
3017 ctxt->value->floatval = f + 1;
3018}
3019
3020/**
3021 * xmlXPathRoundFunction:
3022 * @ctxt: the XPath Parser context
3023 *
3024 * Implement the round() XPath function
3025 * The round function returns the number that is closest to the
3026 * argument and that is an integer. If there are two such numbers,
3027 * then the one that is even is returned.
3028 */
3029void
3030xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003031 double f;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003032
3033 CHECK_ARITY(1);
3034 CHECK_TYPE(XPATH_NUMBER);
3035 /* round(0.50000001) => 0 !!!!! */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003036 f = (double)((int) ctxt->value->floatval);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003037 if (ctxt->value->floatval < f + 0.5)
3038 ctxt->value->floatval = f;
3039 else if (ctxt->value->floatval == f + 0.5)
3040 ctxt->value->floatval = f; /* !!!! Not following the spec here */
3041 else
3042 ctxt->value->floatval = f + 1;
3043}
3044
3045/************************************************************************
3046 * *
3047 * The Parser *
3048 * *
3049 ************************************************************************/
3050
3051/*
3052 * a couple of forward declarations since we use a recursive call based
3053 * implementation.
3054 */
3055void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
3056void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3057void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3058void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
3059
3060/**
3061 * xmlXPathParseNCName:
3062 * @ctxt: the XPath Parser context
3063 *
3064 * parse an XML namespace non qualified name.
3065 *
3066 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3067 *
3068 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3069 * CombiningChar | Extender
3070 *
3071 * Returns the namespace name or NULL
3072 */
3073
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003074xmlChar *
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003075xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003076 const xmlChar *q;
3077 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003078
3079 if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3080 q = NEXT;
3081
3082 while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3083 (CUR == '.') || (CUR == '-') ||
3084 (CUR == '_') ||
3085 (IS_COMBINING(CUR)) ||
3086 (IS_EXTENDER(CUR)))
3087 NEXT;
3088
3089 ret = xmlStrndup(q, CUR_PTR - q);
3090
3091 return(ret);
3092}
3093
3094/**
3095 * xmlXPathParseQName:
3096 * @ctxt: the XPath Parser context
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003097 * @prefix: a xmlChar **
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003098 *
3099 * parse an XML qualified name
3100 *
3101 * [NS 5] QName ::= (Prefix ':')? LocalPart
3102 *
3103 * [NS 6] Prefix ::= NCName
3104 *
3105 * [NS 7] LocalPart ::= NCName
3106 *
3107 * Returns the function returns the local part, and prefix is updated
3108 * to get the Prefix if any.
3109 */
3110
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003111xmlChar *
3112xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3113 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003114
3115 *prefix = NULL;
3116 ret = xmlXPathParseNCName(ctxt);
3117 if (CUR == ':') {
3118 *prefix = ret;
3119 NEXT;
3120 ret = xmlXPathParseNCName(ctxt);
3121 }
3122 return(ret);
3123}
3124
3125/**
3126 * xmlXPathStringEvalNumber:
3127 * @str: A string to scan
3128 *
3129 * [30] Number ::= Digits ('.' Digits)?
3130 * | '.' Digits
3131 * [31] Digits ::= [0-9]+
3132 *
3133 * Parse and evaluate a Number in the string
3134 *
3135 * BUG: "1.' is not valid ... James promised correction
3136 * as Digits ('.' Digits?)?
3137 *
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003138 * Returns the double value.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003139 */
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003140double
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003141xmlXPathStringEvalNumber(const xmlChar *str) {
3142 const xmlChar *cur = str;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003143 double ret = 0.0;
3144 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003145 int ok = 0;
3146
3147 while (*cur == ' ') cur++;
3148 if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003149 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003150 }
3151 while ((*cur >= '0') && (*cur <= '9')) {
3152 ret = ret * 10 + (*cur - '0');
3153 ok = 1;
3154 cur++;
3155 }
3156 if (*cur == '.') {
3157 cur++;
3158 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003159 return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003160 }
3161 while ((*cur >= '0') && (*cur <= '9')) {
3162 mult /= 10;
3163 ret = ret + (*cur - '0') * mult;
3164 cur++;
3165 }
3166 }
3167 while (*cur == ' ') cur++;
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003168 if (*cur != 0) return(xmlXPathNAN);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003169 return(ret);
3170}
3171
3172/**
3173 * xmlXPathEvalNumber:
3174 * @ctxt: the XPath Parser context
3175 *
3176 * [30] Number ::= Digits ('.' Digits)?
3177 * | '.' Digits
3178 * [31] Digits ::= [0-9]+
3179 *
3180 * Parse and evaluate a Number, then push it on the stack
3181 *
3182 * BUG: "1.' is not valid ... James promised correction
3183 * as Digits ('.' Digits?)?
3184 */
3185void
3186xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00003187 double ret = 0.0;
3188 double mult = 1;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003189 int ok = 0;
3190
3191 CHECK_ERROR;
3192 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003193 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003194 }
3195 while ((CUR >= '0') && (CUR <= '9')) {
3196 ret = ret * 10 + (CUR - '0');
3197 ok = 1;
3198 NEXT;
3199 }
3200 if (CUR == '.') {
3201 NEXT;
3202 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003203 XP_ERROR(XPATH_NUMBER_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003204 }
3205 while ((CUR >= '0') && (CUR <= '9')) {
3206 mult /= 10;
3207 ret = ret + (CUR - '0') * mult;
3208 NEXT;
3209 }
3210 }
3211 valuePush(ctxt, xmlXPathNewFloat(ret));
3212}
3213
3214/**
3215 * xmlXPathEvalLiteral:
3216 * @ctxt: the XPath Parser context
3217 *
3218 * Parse a Literal and push it on the stack.
3219 *
3220 * [29] Literal ::= '"' [^"]* '"'
3221 * | "'" [^']* "'"
3222 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003223 * TODO: xmlXPathEvalLiteral memory allocation could be improved.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003224 */
3225void
3226xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003227 const xmlChar *q;
3228 xmlChar *ret = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003229
3230 if (CUR == '"') {
3231 NEXT;
3232 q = CUR_PTR;
3233 while ((IS_CHAR(CUR)) && (CUR != '"'))
3234 NEXT;
3235 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003236 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003237 } else {
3238 ret = xmlStrndup(q, CUR_PTR - q);
3239 NEXT;
3240 }
3241 } else if (CUR == '\'') {
3242 NEXT;
3243 q = CUR_PTR;
3244 while ((IS_CHAR(CUR)) && (CUR != '\''))
3245 NEXT;
3246 if (!IS_CHAR(CUR)) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003247 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003248 } else {
3249 ret = xmlStrndup(q, CUR_PTR - q);
3250 NEXT;
3251 }
3252 } else {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003253 XP_ERROR(XPATH_START_LITERAL_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003254 }
3255 if (ret == NULL) return;
3256 valuePush(ctxt, xmlXPathNewString(ret));
Daniel Veillard6454aec1999-09-02 22:04:43 +00003257 xmlFree(ret);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003258}
3259
3260/**
3261 * xmlXPathEvalVariableReference:
3262 * @ctxt: the XPath Parser context
3263 *
3264 * Parse a VariableReference, evaluate it and push it on the stack.
3265 *
3266 * The variable bindings consist of a mapping from variable names
3267 * to variable values. The value of a variable is an object, which
3268 * of any of the types that are possible for the value of an expression,
3269 * and may also be of additional types not specified here.
3270 *
3271 * Early evaluation is possible since:
3272 * The variable bindings [...] used to evaluate a subexpression are
3273 * always the same as those used to evaluate the containing expression.
3274 *
3275 * [36] VariableReference ::= '$' QName
3276 */
3277void
3278xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003279 xmlChar *name;
3280 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003281 xmlXPathObjectPtr value;
3282
3283 if (CUR != '$') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003284 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003285 }
3286 name = xmlXPathParseQName(ctxt, &prefix);
3287 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003288 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003289 }
3290 value = xmlXPathVariablelookup(ctxt, prefix, name);
3291 if (value == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003292 XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003293 }
3294 valuePush(ctxt, value);
Daniel Veillard6454aec1999-09-02 22:04:43 +00003295 if (prefix != NULL) xmlFree(prefix);
3296 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003297}
3298
3299
3300/**
3301 * xmlXPathFunctionLookup:
3302 * @ctxt: the XPath Parser context
3303 * @name: a name string
3304 *
3305 * Search for a function of the given name
3306 *
3307 * [35] FunctionName ::= QName - NodeType
3308 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003309 * TODO: for the moment the function list is hardcoded from the spec !!!!
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003310 *
3311 * Returns the xmlXPathFunction if found, or NULL otherwise
3312 */
3313xmlXPathFunction
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003314xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003315 switch (name[0]) {
3316 case 'b':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003317 if (!xmlStrcmp(name, BAD_CAST "boolean"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003318 return(xmlXPathBooleanFunction);
3319 break;
3320 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003321 if (!xmlStrcmp(name, BAD_CAST "ceiling"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003322 return(xmlXPathCeilingFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003323 if (!xmlStrcmp(name, BAD_CAST "count"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003324 return(xmlXPathCountFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003325 if (!xmlStrcmp(name, BAD_CAST "concat"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003326 return(xmlXPathConcatFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003327 if (!xmlStrcmp(name, BAD_CAST "contains"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003328 return(xmlXPathContainsFunction);
3329 break;
3330 case 'i':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003331 if (!xmlStrcmp(name, BAD_CAST "id"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003332 return(xmlXPathIdFunction);
3333 break;
3334 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003335 if (!xmlStrcmp(name, BAD_CAST "false"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003336 return(xmlXPathFalseFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003337 if (!xmlStrcmp(name, BAD_CAST "floor"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003338 return(xmlXPathFloorFunction);
3339 break;
3340 case 'l':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003341 if (!xmlStrcmp(name, BAD_CAST "last"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003342 return(xmlXPathLastFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003343 if (!xmlStrcmp(name, BAD_CAST "lang"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003344 return(xmlXPathLangFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003345 if (!xmlStrcmp(name, BAD_CAST "local-part"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003346 return(xmlXPathLocalPartFunction);
3347 break;
3348 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003349 if (!xmlStrcmp(name, BAD_CAST "not"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003350 return(xmlXPathNotFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003351 if (!xmlStrcmp(name, BAD_CAST "name"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003352 return(xmlXPathNameFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003353 if (!xmlStrcmp(name, BAD_CAST "namespace"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003354 return(xmlXPathNamespaceFunction);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003355 if (!xmlStrcmp(name, BAD_CAST "normalize-space"))
3356 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003357 if (!xmlStrcmp(name, BAD_CAST "normalize"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003358 return(xmlXPathNormalizeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003359 if (!xmlStrcmp(name, BAD_CAST "number"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003360 return(xmlXPathNumberFunction);
3361 break;
3362 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003363 if (!xmlStrcmp(name, BAD_CAST "position"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003364 return(xmlXPathPositionFunction);
3365 break;
3366 case 'r':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003367 if (!xmlStrcmp(name, BAD_CAST "round"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003368 return(xmlXPathRoundFunction);
3369 break;
3370 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003371 if (!xmlStrcmp(name, BAD_CAST "string"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003372 return(xmlXPathStringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003373 if (!xmlStrcmp(name, BAD_CAST "string-length"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003374 return(xmlXPathStringLengthFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003375 if (!xmlStrcmp(name, BAD_CAST "starts-with"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003376 return(xmlXPathStartsWithFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003377 if (!xmlStrcmp(name, BAD_CAST "substring"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003378 return(xmlXPathSubstringFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003379 if (!xmlStrcmp(name, BAD_CAST "substring-before"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003380 return(xmlXPathSubstringBeforeFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003381 if (!xmlStrcmp(name, BAD_CAST "substring-after"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003382 return(xmlXPathSubstringAfterFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003383 if (!xmlStrcmp(name, BAD_CAST "sum"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003384 return(xmlXPathSumFunction);
3385 break;
3386 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003387 if (!xmlStrcmp(name, BAD_CAST "true"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003388 return(xmlXPathTrueFunction);
Daniel Veillardb96e6431999-08-29 21:02:19 +00003389 if (!xmlStrcmp(name, BAD_CAST "translate"))
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003390 return(xmlXPathTranslateFunction);
3391 break;
3392 }
3393 return(NULL);
3394}
3395
3396/**
3397 * xmlXPathEvalLocationPathName:
3398 * @ctxt: the XPath Parser context
3399 * @name: a name string
3400 *
3401 * Various names in the beginning of a LocationPath expression
3402 * indicate whether that's an Axis, a node type,
3403 *
3404 * [6] AxisName ::= 'ancestor'
3405 * | 'ancestor-or-self'
3406 * | 'attribute'
3407 * | 'child'
3408 * | 'descendant'
3409 * | 'descendant-or-self'
3410 * | 'following'
3411 * | 'following-sibling'
3412 * | 'namespace'
3413 * | 'parent'
3414 * | 'preceding'
3415 * | 'preceding-sibling'
3416 * | 'self'
3417 * [38] NodeType ::= 'comment'
3418 * | 'text'
3419 * | 'processing-instruction'
3420 * | 'node'
3421 */
3422int
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003423xmlXPathGetNameType(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003424 switch (name[0]) {
3425 case 'a':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003426 if (!xmlStrcmp(name, BAD_CAST "ancestor")) return(AXIS_ANCESTOR);
3427 if (!xmlStrcmp(name, BAD_CAST "ancestor-or-self"))
3428 return(AXIS_ANCESTOR_OR_SELF);
3429 if (!xmlStrcmp(name, BAD_CAST "attribute")) return(AXIS_ATTRIBUTE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003430 break;
3431 case 'c':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003432 if (!xmlStrcmp(name, BAD_CAST "child")) return(AXIS_CHILD);
3433 if (!xmlStrcmp(name, BAD_CAST "comment")) return(NODE_TYPE_COMMENT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003434 break;
3435 case 'd':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003436 if (!xmlStrcmp(name, BAD_CAST "descendant"))
3437 return(AXIS_DESCENDANT);
3438 if (!xmlStrcmp(name, BAD_CAST "descendant-or-self"))
3439 return(AXIS_DESCENDANT_OR_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003440 break;
3441 case 'f':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003442 if (!xmlStrcmp(name, BAD_CAST "following")) return(AXIS_FOLLOWING);
3443 if (!xmlStrcmp(name, BAD_CAST "following-sibling"))
3444 return(AXIS_FOLLOWING_SIBLING);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003445 break;
3446 case 'n':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003447 if (!xmlStrcmp(name, BAD_CAST "namespace")) return(AXIS_NAMESPACE);
3448 if (!xmlStrcmp(name, BAD_CAST "node")) return(NODE_TYPE_NODE);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003449 break;
3450 case 'p':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003451 if (!xmlStrcmp(name, BAD_CAST "parent")) return(AXIS_PARENT);
3452 if (!xmlStrcmp(name, BAD_CAST "preceding")) return(AXIS_PRECEDING);
3453 if (!xmlStrcmp(name, BAD_CAST "preceding-sibling"))
3454 return(AXIS_PRECEDING_SIBLING);
3455 if (!xmlStrcmp(name, BAD_CAST "processing-instruction"))
3456 return(NODE_TYPE_PI);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003457 break;
3458 case 's':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003459 if (!xmlStrcmp(name, BAD_CAST "self")) return(AXIS_SELF);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003460 break;
3461 case 't':
Daniel Veillardb96e6431999-08-29 21:02:19 +00003462 if (!xmlStrcmp(name, BAD_CAST "text")) return(NODE_TYPE_TEXT);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003463 break;
3464 }
3465 if (xmlXPathIsFunction(ctxt, name)) return(IS_FUNCTION);
3466 return(0);
3467}
3468
3469/**
3470 * xmlXPathEvalFunctionCall:
3471 * @ctxt: the XPath Parser context
3472 *
3473 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
3474 * [17] Argument ::= Expr
3475 *
3476 * Parse and evaluate a function call, the evaluation of all arguments are
3477 * pushed on the stack
3478 */
3479void
3480xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003481 xmlChar *name;
3482 xmlChar *prefix;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003483 xmlXPathFunction func;
3484 int nbargs = 0;
3485
3486 name = xmlXPathParseQName(ctxt, &prefix);
3487 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003488 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003489 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003490 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003491 func = xmlXPathIsFunction(ctxt, name);
3492 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003493 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003494 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003495 }
3496#ifdef DEBUG_EXPR
3497 fprintf(xmlXPathDebug, "Calling function %s\n", name);
3498#endif
3499
3500 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003501 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003502 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003503 }
3504 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003505 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003506
3507 while (CUR != ')') {
3508 xmlXPathEvalExpr(ctxt);
3509 nbargs++;
3510 if (CUR == ')') break;
3511 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00003512 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003513 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003514 }
3515 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003516 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003517 }
3518 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003519 SKIP_BLANKS;
Daniel Veillard6454aec1999-09-02 22:04:43 +00003520 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003521 func(ctxt, nbargs);
3522}
3523
3524/**
3525 * xmlXPathEvalPrimaryExpr:
3526 * @ctxt: the XPath Parser context
3527 *
3528 * [15] PrimaryExpr ::= VariableReference
3529 * | '(' Expr ')'
3530 * | Literal
3531 * | Number
3532 * | FunctionCall
3533 *
3534 * Parse and evaluate a primary expression, then push the result on the stack
3535 */
3536void
3537xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003538 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003539 if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
3540 else if (CUR == '(') {
3541 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003542 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003543 xmlXPathEvalExpr(ctxt);
3544 if (CUR != ')') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00003545 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003546 }
3547 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003548 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003549 } else if (IS_DIGIT(CUR)) {
3550 xmlXPathEvalNumber(ctxt);
3551 } else if ((CUR == '\'') || (CUR == '"')) {
3552 xmlXPathEvalLiteral(ctxt);
3553 } else {
3554 xmlXPathEvalFunctionCall(ctxt);
3555 }
3556}
3557
3558/**
3559 * xmlXPathEvalFilterExpr:
3560 * @ctxt: the XPath Parser context
3561 *
3562 * [20] FilterExpr ::= PrimaryExpr
3563 * | FilterExpr Predicate
3564 *
3565 * Parse and evaluate a filter expression, then push the result on the stack
3566 * Square brackets are used to filter expressions in the same way that
3567 * they are used in location paths. It is an error if the expression to
3568 * be filtered does not evaluate to a node-set. The context node list
3569 * used for evaluating the expression in square brackets is the node-set
3570 * to be filtered listed in document order.
3571 */
3572
3573void
3574xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
3575 /****
3576 xmlNodeSetPtr oldset = NULL;
3577 xmlXPathObjectPtr arg;
3578 ****/
3579
3580 xmlXPathEvalPrimaryExpr(ctxt);
3581 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003582 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003583
3584 if (CUR != '[') return;
3585
3586 CHECK_TYPE(XPATH_NODESET);
3587
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003588 while (CUR == '[') {
3589 xmlXPathEvalPredicate(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003590 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003591 }
3592
3593
3594}
3595
3596/**
Daniel Veillardb96e6431999-08-29 21:02:19 +00003597 * xmlXPathScanName:
3598 * @ctxt: the XPath Parser context
3599 *
3600 * Trickery: parse an XML name but without consuming the input flow
3601 * Needed for rollback cases.
3602 *
3603 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3604 * CombiningChar | Extender
3605 *
3606 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3607 *
3608 * [6] Names ::= Name (S Name)*
3609 *
3610 * Returns the Name parsed or NULL
3611 */
3612
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003613xmlChar *
Daniel Veillardb96e6431999-08-29 21:02:19 +00003614xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003615 xmlChar buf[XML_MAX_NAMELEN];
Daniel Veillardb96e6431999-08-29 21:02:19 +00003616 int len = 0;
3617
Daniel Veillard00fdf371999-10-08 09:40:39 +00003618 SKIP_BLANKS;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003619 if (!IS_LETTER(CUR) && (CUR != '_') &&
3620 (CUR != ':')) {
3621 return(NULL);
3622 }
3623
3624 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3625 (NXT(len) == '.') || (NXT(len) == '-') ||
3626 (NXT(len) == '_') || (NXT(len) == ':') ||
3627 (IS_COMBINING(NXT(len))) ||
3628 (IS_EXTENDER(NXT(len)))) {
3629 buf[len] = NXT(len);
3630 len++;
3631 if (len >= XML_MAX_NAMELEN) {
3632 fprintf(stderr,
3633 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
3634 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
3635 (NXT(len) == '.') || (NXT(len) == '-') ||
3636 (NXT(len) == '_') || (NXT(len) == ':') ||
3637 (IS_COMBINING(NXT(len))) ||
3638 (IS_EXTENDER(NXT(len))))
3639 len++;
3640 break;
3641 }
3642 }
3643 return(xmlStrndup(buf, len));
3644}
3645
3646/**
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003647 * xmlXPathEvalPathExpr:
3648 * @ctxt: the XPath Parser context
3649 *
3650 * [19] PathExpr ::= LocationPath
3651 * | FilterExpr
3652 * | FilterExpr '/' RelativeLocationPath
3653 * | FilterExpr '//' RelativeLocationPath
3654 *
3655 * Parse and evaluate a path expression, then push the result on the stack
3656 * The / operator and // operators combine an arbitrary expression
3657 * and a relative location path. It is an error if the expression
3658 * does not evaluate to a node-set.
3659 * The / operator does composition in the same way as when / is
3660 * used in a location path. As in location paths, // is short for
3661 * /descendant-or-self::node()/.
3662 */
3663
3664void
3665xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
3666 xmlNodeSetPtr newset = NULL;
3667
Daniel Veillard00fdf371999-10-08 09:40:39 +00003668 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003669 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
3670 (CUR == '\'') || (CUR == '"')) {
3671 xmlXPathEvalFilterExpr(ctxt);
3672 CHECK_ERROR;
3673 if ((CUR == '/') && (NXT(1) == '/')) {
3674 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003675 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003676 if (ctxt->context->nodelist == NULL) {
3677 STRANGE
3678 xmlXPathRoot(ctxt);
3679 }
3680 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
3681 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
3682 if (ctxt->context->nodelist != NULL)
3683 xmlXPathFreeNodeSet(ctxt->context->nodelist);
3684 ctxt->context->nodelist = newset;
3685 ctxt->context->node = NULL;
3686 xmlXPathEvalRelativeLocationPath(ctxt);
3687 } else if (CUR == '/') {
3688 xmlXPathEvalRelativeLocationPath(ctxt);
3689 }
3690 } else {
Daniel Veillard00fdf371999-10-08 09:40:39 +00003691 /******* !!!!!!!!!! @attname */
Daniel Veillarddd6b3671999-09-23 22:19:22 +00003692 xmlChar *name;
Daniel Veillardb96e6431999-08-29 21:02:19 +00003693
3694 name = xmlXPathScanName(ctxt);
3695 if ((name == NULL) || (!xmlXPathIsFunction(ctxt, name)))
3696 xmlXPathEvalLocationPath(ctxt);
3697 else
3698 xmlXPathEvalFilterExpr(ctxt);
3699 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00003700 xmlFree(name);
Daniel Veillardbe803962000-06-28 23:40:59 +00003701
Daniel Veillardcf461992000-03-14 18:30:20 +00003702 if (ctxt->context->nodelist != NULL)
3703 valuePush(ctxt, xmlXPathNewNodeSetList(ctxt->context->nodelist));
Daniel Veillardbe803962000-06-28 23:40:59 +00003704 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003705}
3706
3707/**
3708 * xmlXPathEvalUnionExpr:
3709 * @ctxt: the XPath Parser context
3710 *
3711 * [18] UnionExpr ::= PathExpr
3712 * | UnionExpr '|' PathExpr
3713 *
3714 * Parse and evaluate an union expression, then push the result on the stack
3715 */
3716
3717void
3718xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
3719 xmlXPathEvalPathExpr(ctxt);
3720 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003721 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003722 if (CUR == '|') {
3723 xmlNodeSetPtr old = ctxt->context->nodelist;
3724
Daniel Veillard00fdf371999-10-08 09:40:39 +00003725 NEXT;
3726 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003727 xmlXPathEvalPathExpr(ctxt);
3728
3729 if (ctxt->context->nodelist == NULL)
3730 ctxt->context->nodelist = old;
3731 else {
3732 ctxt->context->nodelist =
3733 xmlXPathNodeSetMerge(ctxt->context->nodelist, old);
3734 xmlXPathFreeNodeSet(old);
3735 }
3736 }
3737}
3738
3739/**
3740 * xmlXPathEvalUnaryExpr:
3741 * @ctxt: the XPath Parser context
3742 *
3743 * [27] UnaryExpr ::= UnionExpr
3744 * | '-' UnaryExpr
3745 *
3746 * Parse and evaluate an unary expression, then push the result on the stack
3747 */
3748
3749void
3750xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
3751 int minus = 0;
3752
Daniel Veillard00fdf371999-10-08 09:40:39 +00003753 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003754 if (CUR == '-') {
3755 minus = 1;
3756 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003757 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003758 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00003759 xmlXPathEvalUnionExpr(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003760 CHECK_ERROR;
3761 if (minus) {
3762 xmlXPathValueFlipSign(ctxt);
3763 }
3764}
3765
3766/**
3767 * xmlXPathEvalMultiplicativeExpr:
3768 * @ctxt: the XPath Parser context
3769 *
3770 * [26] MultiplicativeExpr ::= UnaryExpr
3771 * | MultiplicativeExpr MultiplyOperator UnaryExpr
3772 * | MultiplicativeExpr 'div' UnaryExpr
3773 * | MultiplicativeExpr 'mod' UnaryExpr
3774 * [34] MultiplyOperator ::= '*'
3775 *
3776 * Parse and evaluate an Additive expression, then push the result on the stack
3777 */
3778
3779void
3780xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
3781 xmlXPathEvalUnaryExpr(ctxt);
3782 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003783 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003784 while ((CUR == '*') ||
3785 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
3786 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
3787 int op = -1;
3788
3789 if (CUR == '*') {
3790 op = 0;
3791 NEXT;
3792 } else if (CUR == 'd') {
3793 op = 1;
3794 SKIP(3);
3795 } else if (CUR == 'm') {
3796 op = 2;
3797 SKIP(3);
3798 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00003799 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003800 xmlXPathEvalUnaryExpr(ctxt);
3801 CHECK_ERROR;
3802 switch (op) {
3803 case 0:
3804 xmlXPathMultValues(ctxt);
3805 break;
3806 case 1:
3807 xmlXPathDivValues(ctxt);
3808 break;
3809 case 2:
3810 xmlXPathModValues(ctxt);
3811 break;
3812 }
3813 }
3814}
3815
3816/**
3817 * xmlXPathEvalAdditiveExpr:
3818 * @ctxt: the XPath Parser context
3819 *
3820 * [25] AdditiveExpr ::= MultiplicativeExpr
3821 * | AdditiveExpr '+' MultiplicativeExpr
3822 * | AdditiveExpr '-' MultiplicativeExpr
3823 *
3824 * Parse and evaluate an Additive expression, then push the result on the stack
3825 */
3826
3827void
3828xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
3829 xmlXPathEvalMultiplicativeExpr(ctxt);
3830 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003831 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003832 while ((CUR == '+') || (CUR == '-')) {
3833 int plus;
3834
3835 if (CUR == '+') plus = 1;
3836 else plus = 0;
3837 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003838 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003839 xmlXPathEvalMultiplicativeExpr(ctxt);
3840 CHECK_ERROR;
3841 if (plus) xmlXPathAddValues(ctxt);
3842 else xmlXPathSubValues(ctxt);
3843 }
3844}
3845
3846/**
3847 * xmlXPathEvalRelationalExpr:
3848 * @ctxt: the XPath Parser context
3849 *
3850 * [24] RelationalExpr ::= AdditiveExpr
3851 * | RelationalExpr '<' AdditiveExpr
3852 * | RelationalExpr '>' AdditiveExpr
3853 * | RelationalExpr '<=' AdditiveExpr
3854 * | RelationalExpr '>=' AdditiveExpr
3855 *
3856 * A <= B > C is allowed ? Answer from James, yes with
3857 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
3858 * which is basically what got implemented.
3859 *
3860 * Parse and evaluate a Relational expression, then push the result
3861 * on the stack
3862 */
3863
3864void
3865xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
3866 xmlXPathEvalAdditiveExpr(ctxt);
3867 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003868 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003869 while ((CUR == '<') ||
3870 (CUR == '>') ||
3871 ((CUR == '<') && (NXT(1) == '=')) ||
3872 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003873 int inf, strict, ret;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003874
3875 if (CUR == '<') inf = 1;
3876 else inf = 0;
3877 if (NXT(1) == '=') strict = 0;
3878 else strict = 1;
3879 NEXT;
3880 if (!strict) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003881 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003882 xmlXPathEvalAdditiveExpr(ctxt);
3883 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003884 ret = xmlXPathCompareValues(ctxt, inf, strict);
3885 valuePush(ctxt, xmlXPathNewBoolean(ret));
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003886 }
3887}
3888
3889/**
3890 * xmlXPathEvalEqualityExpr:
3891 * @ctxt: the XPath Parser context
3892 *
3893 * [23] EqualityExpr ::= RelationalExpr
3894 * | EqualityExpr '=' RelationalExpr
3895 * | EqualityExpr '!=' RelationalExpr
3896 *
3897 * A != B != C is allowed ? Answer from James, yes with
3898 * (RelationalExpr = RelationalExpr) = RelationalExpr
3899 * (RelationalExpr != RelationalExpr) != RelationalExpr
3900 * which is basically what got implemented.
3901 *
3902 * Parse and evaluate an Equality expression, then push the result on the stack
3903 *
3904 */
3905void
3906xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
3907 xmlXPathEvalRelationalExpr(ctxt);
3908 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003909 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003910 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard991e63d1999-08-15 23:32:28 +00003911 xmlXPathObjectPtr res;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003912 int eq, equal;
3913
3914 if (CUR == '=') eq = 1;
3915 else eq = 0;
3916 NEXT;
3917 if (!eq) NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003918 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003919 xmlXPathEvalRelationalExpr(ctxt);
3920 CHECK_ERROR;
Daniel Veillard991e63d1999-08-15 23:32:28 +00003921 equal = xmlXPathEqualValues(ctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003922 if (eq) res = xmlXPathNewBoolean(equal);
3923 else res = xmlXPathNewBoolean(!equal);
3924 valuePush(ctxt, res);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003925 }
3926}
3927
3928/**
3929 * xmlXPathEvalAndExpr:
3930 * @ctxt: the XPath Parser context
3931 *
3932 * [22] AndExpr ::= EqualityExpr
3933 * | AndExpr 'and' EqualityExpr
3934 *
3935 * Parse and evaluate an AND expression, then push the result on the stack
3936 *
3937 */
3938void
3939xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
3940 xmlXPathEvalEqualityExpr(ctxt);
3941 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003942 SKIP_BLANKS;
Daniel Veillardbe803962000-06-28 23:40:59 +00003943 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003944 xmlXPathObjectPtr arg1, arg2;
3945
3946 SKIP(3);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003947 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003948 xmlXPathEvalEqualityExpr(ctxt);
3949 CHECK_ERROR;
3950 arg2 = valuePop(ctxt);
3951 arg1 = valuePop(ctxt);
3952 arg1->boolval &= arg2->boolval;
3953 valuePush(ctxt, arg1);
3954 xmlXPathFreeObject(arg2);
3955 }
3956}
3957
3958/**
3959 * xmlXPathEvalExpr:
3960 * @ctxt: the XPath Parser context
3961 *
3962 * [14] Expr ::= OrExpr
3963 * [21] OrExpr ::= AndExpr
3964 * | OrExpr 'or' AndExpr
3965 *
3966 * Parse and evaluate an expression, then push the result on the stack
3967 *
3968 */
3969void
3970xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
3971 xmlXPathEvalAndExpr(ctxt);
3972 CHECK_ERROR;
Daniel Veillard00fdf371999-10-08 09:40:39 +00003973 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003974 while ((CUR == 'o') && (NXT(1) == 'r')) {
3975 xmlXPathObjectPtr arg1, arg2;
3976
3977 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00003978 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00003979 xmlXPathEvalAndExpr(ctxt);
3980 CHECK_ERROR;
3981 arg2 = valuePop(ctxt);
3982 arg1 = valuePop(ctxt);
3983 arg1->boolval |= arg2->boolval;
3984 valuePush(ctxt, arg1);
3985 xmlXPathFreeObject(arg2);
3986 }
3987}
3988
3989/**
3990 * xmlXPathEvaluatePredicateResult:
3991 * @ctxt: the XPath Parser context
3992 * @res: the Predicate Expression evaluation result
3993 * @index: index of the current node in the current list
3994 *
3995 * Evaluate a predicate result for the current node.
3996 * A PredicateExpr is evaluated by evaluating the Expr and converting
3997 * the result to a boolean. If the result is a number, the result will
3998 * be converted to true if the number is equal to the position of the
3999 * context node in the context node list (as returned by the position
4000 * function) and will be converted to false otherwise; if the result
4001 * is not a number, then the result will be converted as if by a call
4002 * to the boolean function.
4003 */
4004int
4005xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
4006 xmlXPathObjectPtr res, int index) {
4007 if (res == NULL) return(0);
4008 switch (res->type) {
4009 case XPATH_BOOLEAN:
4010 return(res->boolval);
4011 case XPATH_NUMBER:
4012 return(res->floatval == index);
4013 case XPATH_NODESET:
4014 return(res->nodesetval->nodeNr != 0);
4015 case XPATH_STRING:
4016 return((res->stringval != NULL) &&
4017 (xmlStrlen(res->stringval) != 0));
4018 default:
4019 STRANGE
4020 }
4021 return(0);
4022}
4023
4024/**
4025 * xmlXPathEvalPredicate:
4026 * @ctxt: the XPath Parser context
4027 *
4028 * [8] Predicate ::= '[' PredicateExpr ']'
4029 * [9] PredicateExpr ::= Expr
4030 *
4031 * Parse and evaluate a predicate for all the elements of the
4032 * current node list. Then refine the list by removing all
4033 * nodes where the predicate is false.
4034 */
4035void
4036xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004037 const xmlChar *cur;
Daniel Veillardbe803962000-06-28 23:40:59 +00004038 xmlXPathObjectPtr res, listHolder = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004039 xmlNodeSetPtr newset = NULL;
4040 int i;
4041
Daniel Veillard00fdf371999-10-08 09:40:39 +00004042 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004043 if (CUR != '[') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004044 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004045 }
4046 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004047 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004048 if ((ctxt->context->nodelist == NULL) ||
4049 (ctxt->context->nodelist->nodeNr == 0)) {
4050 ctxt->context->node = NULL;
4051 xmlXPathEvalExpr(ctxt);
4052 CHECK_ERROR;
4053 res = valuePop(ctxt);
4054 if (res != NULL)
4055 xmlXPathFreeObject(res);
4056 } else {
4057 cur = ctxt->cur;
4058 newset = xmlXPathNodeSetCreate(NULL);
Daniel Veillardbe803962000-06-28 23:40:59 +00004059
4060 /* Create a copy of the current node set because it is important: */
4061 listHolder = xmlXPathNewNodeSetList(ctxt->context->nodelist);
4062
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004063 for (i = 0; i < ctxt->context->nodelist->nodeNr; i++) {
4064 ctxt->cur = cur;
4065 ctxt->context->node = ctxt->context->nodelist->nodeTab[i];
Daniel Veillardbe803962000-06-28 23:40:59 +00004066
4067 /* This nodeset is useful for the loop but no, longer necessary this iteration: */
4068 if (ctxt->context->nodelist != NULL)
4069 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4070
4071 /* This line was missed out: */
4072 ctxt->context->nodelist = xmlXPathNodeSetCreate(ctxt->context->node);
4073
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004074 xmlXPathEvalExpr(ctxt);
4075 CHECK_ERROR;
4076 res = valuePop(ctxt);
4077 if (xmlXPathEvaluatePredicateResult(ctxt, res, i + 1))
Daniel Veillardbe803962000-06-28 23:40:59 +00004078 {
4079 /* Add the current node as the result has proven correct: */
4080 xmlXPathNodeSetAdd(newset, listHolder->nodesetval->nodeTab[i]);
4081 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004082 if (res != NULL)
4083 xmlXPathFreeObject(res);
Daniel Veillardbe803962000-06-28 23:40:59 +00004084
4085 /* Copy the contents of the temporary list back to the node list for the next round: */
4086 ctxt->context->nodelist = xmlXPathNewNodeSetList(listHolder->nodesetval)->nodesetval;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004087 }
4088 if (ctxt->context->nodelist != NULL)
4089 xmlXPathFreeNodeSet(ctxt->context->nodelist);
Daniel Veillardbe803962000-06-28 23:40:59 +00004090
4091 /* Clean up after temporary variable holder: */
4092 if (listHolder != NULL)
4093 xmlXPathFreeObject(listHolder);
4094
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004095 ctxt->context->nodelist = newset;
4096 ctxt->context->node = NULL;
4097 }
4098 if (CUR != ']') {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004099 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004100 }
4101 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004102 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004103#ifdef DEBUG_STEP
4104 fprintf(xmlXPathDebug, "After predicate : ");
4105 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4106#endif
4107}
4108
4109/**
4110 * xmlXPathEvalBasis:
4111 * @ctxt: the XPath Parser context
4112 *
4113 * [5] Basis ::= AxisName '::' NodeTest
4114 * | AbbreviatedBasis
4115 * [13] AbbreviatedBasis ::= NodeTest
4116 * | '@' NodeTest
4117 * [7] NodeTest ::= WildcardName
4118 * | NodeType '(' ')'
4119 * | 'processing-instruction' '(' Literal ')'
4120 * [37] WildcardName ::= '*'
4121 * | NCName ':' '*'
4122 * | QName
4123 *
4124 * Evaluate one step in a Location Path
4125 */
4126void
4127xmlXPathEvalBasis(xmlXPathParserContextPtr ctxt) {
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004128 xmlChar *name = NULL;
4129 xmlChar *prefix = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004130 int type = 0;
4131 int axis = AXIS_CHILD; /* the default on abbreviated syntax */
4132 int nodetest = NODE_TEST_NONE;
4133 int nodetype = 0;
4134 xmlNodeSetPtr newset = NULL;
4135
4136 if (CUR == '@') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004137 NEXT;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004138 axis = AXIS_ATTRIBUTE;
4139 goto parse_NodeTest;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004140 } else if (CUR == '*') {
4141 NEXT;
4142 nodetest = NODE_TEST_ALL;
4143 } else {
4144 name = xmlXPathParseNCName(ctxt);
4145 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004146 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004147 }
4148 type = xmlXPathGetNameType(ctxt, name);
4149 switch (type) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004150 case IS_FUNCTION: {
4151 xmlXPathFunction func;
4152 int nbargs = 0;
4153 xmlXPathObjectPtr top;
4154
4155 top = ctxt->value;
4156 func = xmlXPathIsFunction(ctxt, name);
4157 if (func == NULL) {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004158 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004159 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004160 }
4161#ifdef DEBUG_EXPR
4162 fprintf(xmlXPathDebug, "Calling function %s\n", name);
4163#endif
4164
4165 if (CUR != '(') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004166 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004167 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004168 }
4169 NEXT;
4170
4171 while (CUR != ')') {
4172 xmlXPathEvalExpr(ctxt);
4173 nbargs++;
4174 if (CUR == ')') break;
4175 if (CUR != ',') {
Daniel Veillard6454aec1999-09-02 22:04:43 +00004176 xmlFree(name);
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004177 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004178 }
4179 NEXT;
4180 }
4181 NEXT;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004182 xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004183 func(ctxt, nbargs);
4184 if ((ctxt->value != top) &&
4185 (ctxt->value != NULL) &&
4186 (ctxt->value->type == XPATH_NODESET)) {
4187 xmlXPathObjectPtr cur;
4188
4189 cur = valuePop(ctxt);
4190 ctxt->context->nodelist = cur->nodesetval;
4191 ctxt->context->node = NULL;
4192 cur->nodesetval = NULL;
4193 xmlXPathFreeObject(cur);
4194 }
4195 return;
4196 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004197 /*
4198 * Simple case: no axis seach all given node types.
4199 */
4200 case NODE_TYPE_COMMENT:
4201 if ((CUR != '(') || (NXT(1) != ')')) break;
4202 SKIP(2);
4203 nodetest = NODE_TEST_TYPE;
4204 nodetype = XML_COMMENT_NODE;
4205 goto search_nodes;
4206 case NODE_TYPE_TEXT:
4207 if ((CUR != '(') || (NXT(1) != ')')) break;
4208 SKIP(2);
4209 nodetest = NODE_TEST_TYPE;
4210 nodetype = XML_TEXT_NODE;
4211 goto search_nodes;
4212 case NODE_TYPE_NODE:
4213 if ((CUR != '(') || (NXT(1) != ')')) {
4214 nodetest = NODE_TEST_NAME;
4215 break;
4216 }
4217 SKIP(2);
4218 nodetest = NODE_TEST_TYPE;
4219 nodetype = XML_ELEMENT_NODE;
4220 goto search_nodes;
4221 case NODE_TYPE_PI:
4222 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004223 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004224 name = NULL;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004225 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004226 xmlXPathObjectPtr cur;
4227
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004228 /*
4229 * Specific case: search a PI by name.
4230 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004231 NEXT;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004232 nodetest = NODE_TEST_PI;
4233 xmlXPathEvalLiteral(ctxt);
4234 CHECK_ERROR;
4235 if (CUR != ')')
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004236 XP_ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004237 NEXT;
4238 xmlXPathStringFunction(ctxt, 1);
4239 CHECK_ERROR;
4240 cur = valuePop(ctxt);
4241 name = xmlStrdup(cur->stringval);
4242 xmlXPathFreeObject(cur);
4243 } else
4244 SKIP(2);
4245 nodetest = NODE_TEST_PI;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004246 goto search_nodes;
4247
4248 /*
4249 * Handling of the compund form: got the axis.
4250 */
4251 case AXIS_ANCESTOR:
4252 case AXIS_ANCESTOR_OR_SELF:
4253 case AXIS_ATTRIBUTE:
4254 case AXIS_CHILD:
4255 case AXIS_DESCENDANT:
4256 case AXIS_DESCENDANT_OR_SELF:
4257 case AXIS_FOLLOWING:
4258 case AXIS_FOLLOWING_SIBLING:
4259 case AXIS_NAMESPACE:
4260 case AXIS_PARENT:
4261 case AXIS_PRECEDING:
4262 case AXIS_PRECEDING_SIBLING:
4263 case AXIS_SELF:
4264 if ((CUR != ':') || (NXT(1) != ':')) {
4265 nodetest = NODE_TEST_NAME;
4266 break;
4267 }
4268 SKIP(2);
4269 axis = type;
4270 break;
4271
4272 /*
4273 * Default: abbreviated syntax the axis is AXIS_CHILD
4274 */
4275 default:
4276 nodetest = NODE_TEST_NAME;
4277 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004278parse_NodeTest:
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004279 if (nodetest == NODE_TEST_NONE) {
4280 if (CUR == '*') {
4281 NEXT;
4282 nodetest = NODE_TEST_ALL;
4283 } else {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004284 if (name != NULL)
Daniel Veillard6454aec1999-09-02 22:04:43 +00004285 xmlFree(name);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004286 name = xmlXPathParseQName(ctxt, &prefix);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004287 if (name == NULL) {
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004288 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillardb05deb71999-08-10 19:04:08 +00004289 }
4290 type = xmlXPathGetNameType(ctxt, name);
4291 switch (type) {
4292 /*
4293 * Simple case: no axis seach all given node types.
4294 */
4295 case NODE_TYPE_COMMENT:
4296 if ((CUR != '(') || (NXT(1) != ')')) break;
4297 SKIP(2);
4298 nodetest = NODE_TEST_TYPE;
4299 nodetype = XML_COMMENT_NODE;
4300 goto search_nodes;
4301 case NODE_TYPE_TEXT:
4302 if ((CUR != '(') || (NXT(1) != ')')) break;
4303 SKIP(2);
4304 nodetest = NODE_TEST_TYPE;
4305 nodetype = XML_TEXT_NODE;
4306 goto search_nodes;
4307 case NODE_TYPE_NODE:
4308 if ((CUR != '(') || (NXT(1) != ')')) {
4309 nodetest = NODE_TEST_NAME;
4310 break;
4311 }
4312 SKIP(2);
4313 nodetest = NODE_TEST_TYPE;
4314 nodetype = XML_ELEMENT_NODE;
4315 goto search_nodes;
4316 case NODE_TYPE_PI:
4317 if (CUR != '(') break;
Daniel Veillard6454aec1999-09-02 22:04:43 +00004318 if (name != NULL) xmlFree(name);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004319 name = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004320 if (NXT(1) != ')') {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004321 xmlXPathObjectPtr cur;
4322
Daniel Veillardb05deb71999-08-10 19:04:08 +00004323 /*
4324 * Specific case: search a PI by name.
4325 */
Daniel Veillardb96e6431999-08-29 21:02:19 +00004326 NEXT;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004327 nodetest = NODE_TEST_PI;
4328 xmlXPathEvalLiteral(ctxt);
4329 CHECK_ERROR;
4330 if (CUR != ')')
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004331 XP_ERROR(XPATH_UNCLOSED_ERROR);
Daniel Veillardb96e6431999-08-29 21:02:19 +00004332 NEXT;
4333 xmlXPathStringFunction(ctxt, 1);
4334 CHECK_ERROR;
4335 cur = valuePop(ctxt);
4336 name = xmlStrdup(cur->stringval);
4337 xmlXPathFreeObject(cur);
4338 } else
4339 SKIP(2);
4340 nodetest = NODE_TEST_PI;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004341 goto search_nodes;
4342 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004343 nodetest = NODE_TEST_NAME;
4344 }
4345 } else if ((CUR == ':') && (nodetest == NODE_TEST_NAME)) {
4346 NEXT;
4347 prefix = name;
4348 if (CUR == '*') {
4349 NEXT;
4350 nodetest = NODE_TEST_ALL;
4351 } else
4352 name = xmlXPathParseNCName(ctxt);
4353 } else if (name == NULL)
Daniel Veillard3f6f7f62000-06-30 17:58:25 +00004354 XP_ERROR(XPATH_EXPR_ERROR);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004355 }
4356
4357search_nodes:
4358
4359#ifdef DEBUG_STEP
4360 fprintf(xmlXPathDebug, "Basis : computing new set\n");
4361#endif
4362 newset = xmlXPathNodeCollectAndTest(ctxt, axis, nodetest, nodetype,
4363 prefix, name);
4364 if (ctxt->context->nodelist != NULL)
4365 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4366 ctxt->context->nodelist = newset;
4367 ctxt->context->node = NULL;
4368#ifdef DEBUG_STEP
4369 fprintf(xmlXPathDebug, "Basis : ");
4370 xmlXPathDebugNodeSet(stdout, ctxt->context->nodelist);
4371#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +00004372 if (name != NULL) xmlFree(name);
4373 if (prefix != NULL) xmlFree(prefix);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004374}
4375
4376/**
4377 * xmlXPathEvalStep:
4378 * @ctxt: the XPath Parser context
4379 *
4380 * [4] Step ::= Basis Predicate*
4381 * | AbbreviatedStep
4382 * [12] AbbreviatedStep ::= '.'
4383 * | '..'
4384 *
4385 * Evaluate one step in a Location Path
4386 * A location step of . is short for self::node(). This is
4387 * particularly useful in conjunction with //. For example, the
4388 * location path .//para is short for
4389 * self::node()/descendant-or-self::node()/child::para
4390 * and so will select all para descendant elements of the context
4391 * node.
4392 * Similarly, a location step of .. is short for parent::node().
4393 * For example, ../title is short for parent::node()/child::title
4394 * and so will select the title children of the parent of the context
4395 * node.
4396 */
4397void
4398xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
4399 xmlNodeSetPtr newset = NULL;
4400
Daniel Veillard00fdf371999-10-08 09:40:39 +00004401 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004402 if ((CUR == '.') && (NXT(1) == '.')) {
4403 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004404 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004405 if (ctxt->context->nodelist == NULL) {
4406 STRANGE
4407 xmlXPathRoot(ctxt);
4408 }
4409 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
4410 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4411 if (ctxt->context->nodelist != NULL)
4412 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4413 ctxt->context->nodelist = newset;
4414 ctxt->context->node = NULL;
4415 } else if (CUR == '.') {
4416 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004417 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004418 } else {
4419 xmlXPathEvalBasis(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004420 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004421 while (CUR == '[') {
4422 xmlXPathEvalPredicate(ctxt);
4423 }
Daniel Veillardbe803962000-06-28 23:40:59 +00004424
4425 while (CUR == '@') {
4426 xmlXPathEvalBasis(ctxt);
4427 ctxt->context->node = NULL;
4428 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004429 }
4430#ifdef DEBUG_STEP
4431 fprintf(xmlXPathDebug, "Step : ");
4432 xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->context->nodelist);
4433#endif
4434}
4435
4436/**
4437 * xmlXPathEvalRelativeLocationPath:
4438 * @ctxt: the XPath Parser context
4439 *
4440 * [3] RelativeLocationPath ::= Step
4441 * | RelativeLocationPath '/' Step
4442 * | AbbreviatedRelativeLocationPath
4443 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
4444 *
4445 */
4446void
4447xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
4448 xmlNodeSetPtr newset = NULL;
4449
Daniel Veillard00fdf371999-10-08 09:40:39 +00004450 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004451 xmlXPathEvalStep(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004452 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004453 while (CUR == '/') {
4454 if ((CUR == '/') && (NXT(1) == '/')) {
4455 SKIP(2);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004456 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004457 if (ctxt->context->nodelist == NULL) {
4458 STRANGE
4459 xmlXPathRoot(ctxt);
4460 }
4461 newset = xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
4462 NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4463 if (ctxt->context->nodelist != NULL)
4464 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4465 ctxt->context->nodelist = newset;
4466 ctxt->context->node = NULL;
4467 xmlXPathEvalStep(ctxt);
4468 } else if (CUR == '/') {
4469 NEXT;
Daniel Veillard00fdf371999-10-08 09:40:39 +00004470 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004471 xmlXPathEvalStep(ctxt);
4472 }
Daniel Veillard00fdf371999-10-08 09:40:39 +00004473 SKIP_BLANKS;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004474 }
4475}
4476
4477/**
4478 * xmlXPathEvalLocationPath:
4479 * @ctxt: the XPath Parser context
4480 *
4481 * [1] LocationPath ::= RelativeLocationPath
4482 * | AbsoluteLocationPath
4483 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
4484 * | AbbreviatedAbsoluteLocationPath
4485 * [10] AbbreviatedAbsoluteLocationPath ::=
4486 * '//' RelativeLocationPath
4487 *
4488 * // is short for /descendant-or-self::node()/. For example,
4489 * //para is short for /descendant-or-self::node()/child::para and
4490 * so will select any para element in the document (even a para element
4491 * that is a document element will be selected by //para since the
4492 * document element node is a child of the root node); div//para is
4493 * short for div/descendant-or-self::node()/child::para and so will
4494 * select all para descendants of div children.
4495 */
4496void
4497xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
4498 xmlNodeSetPtr newset = NULL;
4499
Daniel Veillard00fdf371999-10-08 09:40:39 +00004500 SKIP_BLANKS;
4501 if (CUR != '/') {
4502 xmlXPathEvalRelativeLocationPath(ctxt);
4503 } else {
4504 while (CUR == '/') {
4505 if ((CUR == '/') && (NXT(1) == '/')) {
4506 SKIP(2);
4507 SKIP_BLANKS;
4508 if (ctxt->context->nodelist == NULL)
4509 xmlXPathRoot(ctxt);
4510 newset = xmlXPathNodeCollectAndTest(ctxt,
4511 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
4512 XML_ELEMENT_NODE, NULL, NULL);
4513 if (ctxt->context->nodelist != NULL)
4514 xmlXPathFreeNodeSet(ctxt->context->nodelist);
4515 ctxt->context->nodelist = newset;
4516 ctxt->context->node = NULL;
Daniel Veillardb05deb71999-08-10 19:04:08 +00004517 xmlXPathEvalRelativeLocationPath(ctxt);
Daniel Veillard00fdf371999-10-08 09:40:39 +00004518 } else if (CUR == '/') {
4519 NEXT;
4520 SKIP_BLANKS;
4521 xmlXPathRoot(ctxt);
4522 if (CUR != 0)
4523 xmlXPathEvalRelativeLocationPath(ctxt);
4524 } else {
4525 xmlXPathEvalRelativeLocationPath(ctxt);
4526 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004527 }
4528 }
4529}
4530
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004531/**
4532 * xmlXPathEval:
4533 * @str: the XPath expression
4534 * @ctxt: the XPath context
4535 *
4536 * Evaluate the XPath Location Path in the given context.
4537 *
4538 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
4539 * the caller has to free the object.
4540 */
4541xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004542xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004543 xmlXPathParserContextPtr pctxt;
Daniel Veillardb96e6431999-08-29 21:02:19 +00004544 xmlXPathObjectPtr res = NULL, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004545 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004546
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004547 xmlXPathInit();
4548
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004549 CHECK_CONTEXT
4550
4551 if (xmlXPathDebug == NULL)
4552 xmlXPathDebug = stderr;
4553 pctxt = xmlXPathNewParserContext(str, ctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004554 if (str[0] == '/')
4555 xmlXPathRoot(pctxt);
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004556 xmlXPathEvalLocationPath(pctxt);
4557
Daniel Veillardb96e6431999-08-29 21:02:19 +00004558 /* TODO: cleanup nodelist, res = valuePop(pctxt); */
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004559 do {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004560 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004561 if (tmp != NULL) {
Daniel Veillardb96e6431999-08-29 21:02:19 +00004562 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004563 stack++;
4564 }
Daniel Veillardb96e6431999-08-29 21:02:19 +00004565 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004566 if (stack != 0) {
4567 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4568 stack);
4569 }
4570 if (pctxt->error == XPATH_EXPRESSION_OK)
Daniel Veillardb96e6431999-08-29 21:02:19 +00004571 res = xmlXPathNewNodeSetList(pctxt->context->nodelist);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004572 else
4573 res = NULL;
Daniel Veillardbe803962000-06-28 23:40:59 +00004574
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004575 xmlXPathFreeParserContext(pctxt);
4576 return(res);
4577}
4578
4579/**
4580 * xmlXPathEvalExpression:
4581 * @str: the XPath expression
4582 * @ctxt: the XPath context
4583 *
4584 * Evaluate the XPath expression in the given context.
4585 *
Daniel Veillardb96e6431999-08-29 21:02:19 +00004586 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004587 * the caller has to free the object.
4588 */
4589xmlXPathObjectPtr
Daniel Veillarddd6b3671999-09-23 22:19:22 +00004590xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004591 xmlXPathParserContextPtr pctxt;
4592 xmlXPathObjectPtr res, tmp;
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004593 int stack = 0;
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004594
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004595 xmlXPathInit();
4596
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004597 CHECK_CONTEXT
4598
4599 if (xmlXPathDebug == NULL)
4600 xmlXPathDebug = stderr;
4601 pctxt = xmlXPathNewParserContext(str, ctxt);
4602 xmlXPathEvalExpr(pctxt);
4603
4604 res = valuePop(pctxt);
4605 do {
4606 tmp = valuePop(pctxt);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004607 if (tmp != NULL) {
Daniel Veillarde2d034d1999-07-27 19:52:06 +00004608 xmlXPathFreeObject(tmp);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004609 stack++;
4610 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004611 } while (tmp != NULL);
Daniel Veillarddbfd6411999-12-28 16:35:14 +00004612 if (stack != 0) {
4613 fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
4614 stack);
4615 }
Daniel Veillard1566d3a1999-07-15 14:24:29 +00004616 xmlXPathFreeParserContext(pctxt);
4617 return(res);
4618}
4619
Daniel Veillard361d8452000-04-03 19:48:13 +00004620#endif /* LIBXML_XPATH_ENABLED */