blob: 3dee3e8767eba6e0c5696f1fad1eb0c709cd183b [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +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 Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
8 * Public reference:
9 * http://www.w3.org/TR/xpath
10 *
11 * See COPYRIGHT for the status of this software
12 *
13 * Author: Daniel.Veillard@w3.org
14 *
15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
16 * for VMS
17 */
18
Bjorn Reese70a9da52001-04-21 16:57:29 +000019#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000020#ifdef LIBXML_XPATH_ENABLED
21
Owen Taylor3473f882001-02-23 17:55:21 +000022#include <string.h>
23
24#ifdef HAVE_SYS_TYPES_H
25#include <sys/types.h>
26#endif
27#ifdef HAVE_MATH_H
28#include <math.h>
29#endif
30#ifdef HAVE_FLOAT_H
31#include <float.h>
32#endif
33#ifdef HAVE_IEEEFP_H
34#include <ieeefp.h>
35#endif
36#ifdef HAVE_NAN_H
37#include <nan.h>
38#endif
39#ifdef HAVE_CTYPE_H
40#include <ctype.h>
41#endif
Daniel Veillard5792e162001-04-30 17:44:45 +000042#ifdef HAVE_SIGNAL_H
Daniel Veillardb45c43b2001-04-28 17:02:11 +000043#include <signal.h>
Daniel Veillardb45c43b2001-04-28 17:02:11 +000044#endif
Owen Taylor3473f882001-02-23 17:55:21 +000045
46#include <libxml/xmlmemory.h>
47#include <libxml/tree.h>
48#include <libxml/valid.h>
49#include <libxml/xpath.h>
50#include <libxml/xpathInternals.h>
51#include <libxml/parserInternals.h>
52#include <libxml/hash.h>
53#ifdef LIBXML_XPTR_ENABLED
54#include <libxml/xpointer.h>
55#endif
56#ifdef LIBXML_DEBUG_ENABLED
57#include <libxml/debugXML.h>
58#endif
59#include <libxml/xmlerror.h>
60
61/* #define DEBUG */
62/* #define DEBUG_STEP */
63/* #define DEBUG_EXPR */
64
65void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
66double xmlXPathStringEvalNumber(const xmlChar *str);
Daniel Veillard5792e162001-04-30 17:44:45 +000067double xmlXPathDivideBy(double f, double fzero);
Owen Taylor3473f882001-02-23 17:55:21 +000068
Daniel Veillard9e7160d2001-03-18 23:17:47 +000069/************************************************************************
70 * *
71 * Floating point stuff *
72 * *
73 ************************************************************************/
74
Owen Taylor3473f882001-02-23 17:55:21 +000075/*
Owen Taylor3473f882001-02-23 17:55:21 +000076 * The lack of portability of this section of the libc is annoying !
77 */
78double xmlXPathNAN = 0;
79double xmlXPathPINF = 1;
80double xmlXPathNINF = -1;
81
82#ifndef isinf
83#ifndef HAVE_ISINF
84
85#if HAVE_FPCLASS
86
87int isinf(double d) {
88 fpclass_t type = fpclass(d);
89 switch (type) {
90 case FP_NINF:
91 return(-1);
92 case FP_PINF:
93 return(1);
94 }
95 return(0);
96}
97
98#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
99
100#if HAVE_FP_CLASS_H
101#include <fp_class.h>
102#endif
103
104int isinf(double d) {
105#if HAVE_FP_CLASS
106 int fpclass = fp_class(d);
107#else
108 int fpclass = fp_class_d(d);
109#endif
110 if (fpclass == FP_POS_INF)
111 return(1);
112 if (fpclass == FP_NEG_INF)
113 return(-1);
114 return(0);
115}
116
117#elif defined(HAVE_CLASS)
118
119int isinf(double d) {
120 int fpclass = class(d);
121 if (fpclass == FP_PLUS_INF)
122 return(1);
123 if (fpclass == FP_MINUS_INF)
124 return(-1);
125 return(0);
126}
127#elif defined(finite) || defined(HAVE_FINITE)
128int isinf(double x) { return !finite(x) && x==x; }
129#elif defined(HUGE_VAL)
130int isinf(double x)
131{
132 if (x == HUGE_VAL)
133 return(1);
134 if (x == -HUGE_VAL)
135 return(-1);
136 return(0);
137}
138#endif
139
140#endif /* ! HAVE_ISINF */
141#endif /* ! defined(isinf) */
142
143#ifndef isnan
144#ifndef HAVE_ISNAN
145
146#ifdef HAVE_ISNAND
147#define isnan(f) isnand(f)
148#endif /* HAVE_iSNAND */
149
150#endif /* ! HAVE_iSNAN */
151#endif /* ! defined(isnan) */
152
Daniel Veillard5792e162001-04-30 17:44:45 +0000153
154/**
155 * xmlXPathDivideBy:
156 *
157 * The best way found so far to generate the NAN, +-INF
158 * without hitting a compiler bug or optimization :-\
159 *
160 * Returns the double resulting from the division
161 */
162double
163xmlXPathDivideBy(double f, double fzero) {
Daniel Veillard81418e32001-05-22 15:08:55 +0000164 double ret;
Daniel Veillard5792e162001-04-30 17:44:45 +0000165#ifdef HAVE_SIGNAL
166#ifdef SIGFPE
167#ifdef SIG_IGN
168 void (*sighandler)(int);
169 sighandler = signal(SIGFPE, SIG_IGN);
170#endif
171#endif
172#endif
173 ret = f / fzero;
174#ifdef HAVE_SIGNAL
175#ifdef SIGFPE
176#ifdef SIG_IGN
177 signal(SIGFPE, sighandler);
178#endif
179#endif
180#endif
181 return(ret);
182}
183
Owen Taylor3473f882001-02-23 17:55:21 +0000184/**
185 * xmlXPathInit:
186 *
187 * Initialize the XPath environment
188 */
189void
190xmlXPathInit(void) {
191 static int initialized = 0;
192
193 if (initialized) return;
194
Daniel Veillard5792e162001-04-30 17:44:45 +0000195 xmlXPathNAN = xmlXPathDivideBy(0.0, 0.0);
196 xmlXPathPINF = xmlXPathDivideBy(1.0, 0.0);
197 xmlXPathPINF = xmlXPathDivideBy(-1.0, 0.0);
Owen Taylor3473f882001-02-23 17:55:21 +0000198
199 initialized = 1;
200}
201
202/************************************************************************
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000203 * *
204 * Parser Types *
205 * *
206 ************************************************************************/
207
208/*
209 * Types are private:
210 */
211
212typedef enum {
213 XPATH_OP_END=0,
214 XPATH_OP_AND,
215 XPATH_OP_OR,
216 XPATH_OP_EQUAL,
217 XPATH_OP_CMP,
218 XPATH_OP_PLUS,
219 XPATH_OP_MULT,
220 XPATH_OP_UNION,
221 XPATH_OP_ROOT,
222 XPATH_OP_NODE,
223 XPATH_OP_RESET,
224 XPATH_OP_COLLECT,
225 XPATH_OP_VALUE,
226 XPATH_OP_VARIABLE,
227 XPATH_OP_FUNCTION,
228 XPATH_OP_ARG,
229 XPATH_OP_PREDICATE,
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000230 XPATH_OP_FILTER,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000231 XPATH_OP_SORT
232#ifdef LIBXML_XPTR_ENABLED
233 ,XPATH_OP_RANGETO
234#endif
235} xmlXPathOp;
236
237typedef enum {
238 AXIS_ANCESTOR = 1,
239 AXIS_ANCESTOR_OR_SELF,
240 AXIS_ATTRIBUTE,
241 AXIS_CHILD,
242 AXIS_DESCENDANT,
243 AXIS_DESCENDANT_OR_SELF,
244 AXIS_FOLLOWING,
245 AXIS_FOLLOWING_SIBLING,
246 AXIS_NAMESPACE,
247 AXIS_PARENT,
248 AXIS_PRECEDING,
249 AXIS_PRECEDING_SIBLING,
250 AXIS_SELF
251} xmlXPathAxisVal;
252
253typedef enum {
254 NODE_TEST_NONE = 0,
255 NODE_TEST_TYPE = 1,
256 NODE_TEST_PI = 2,
257 NODE_TEST_ALL = 3,
258 NODE_TEST_NS = 4,
259 NODE_TEST_NAME = 5
260} xmlXPathTestVal;
261
262typedef enum {
263 NODE_TYPE_NODE = 0,
264 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
265 NODE_TYPE_TEXT = XML_TEXT_NODE,
266 NODE_TYPE_PI = XML_PI_NODE
267} xmlXPathTypeVal;
268
269
270typedef struct _xmlXPathStepOp xmlXPathStepOp;
271typedef xmlXPathStepOp *xmlXPathStepOpPtr;
272struct _xmlXPathStepOp {
273 xmlXPathOp op;
274 int ch1;
275 int ch2;
276 int value;
277 int value2;
278 int value3;
279 void *value4;
280 void *value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000281 void *cache;
Daniel Veillard42596ad2001-05-22 16:57:14 +0000282 void *cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000283};
284
285struct _xmlXPathCompExpr {
286 int nbStep;
287 int maxStep;
288 xmlXPathStepOp *steps; /* ops for computation */
289 int last;
290};
291
292/************************************************************************
293 * *
294 * Parser Type functions *
295 * *
296 ************************************************************************/
297
298/**
299 * xmlXPathNewCompExpr:
300 *
301 * Create a new Xpath component
302 *
303 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
304 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000305static xmlXPathCompExprPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000306xmlXPathNewCompExpr(void) {
307 xmlXPathCompExprPtr cur;
308
309 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
310 if (cur == NULL) {
311 xmlGenericError(xmlGenericErrorContext,
312 "xmlXPathNewCompExpr : malloc failed\n");
313 return(NULL);
314 }
315 memset(cur, 0, sizeof(xmlXPathCompExpr));
316 cur->maxStep = 10;
317 cur->nbStep = 0;
318 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
319 sizeof(xmlXPathStepOp));
320 if (cur->steps == NULL) {
321 xmlGenericError(xmlGenericErrorContext,
322 "xmlXPathNewCompExpr : malloc failed\n");
323 xmlFree(cur);
324 return(NULL);
325 }
326 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
327 cur->last = -1;
328 return(cur);
329}
330
331/**
332 * xmlXPathFreeCompExpr:
333 * @comp: an XPATH comp
334 *
335 * Free up the memory allocated by @comp
336 */
337void
338xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) {
339 xmlXPathStepOpPtr op;
340 int i;
341
342 if (comp == NULL)
343 return;
344 for (i = 0;i < comp->nbStep;i++) {
345 op = &comp->steps[i];
346 if (op->value4 != NULL) {
347 if (op->op == XPATH_OP_VALUE)
348 xmlXPathFreeObject(op->value4);
349 else
350 xmlFree(op->value4);
351 }
352 if (op->value5 != NULL)
353 xmlFree(op->value5);
354 }
355 if (comp->steps != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000356 xmlFree(comp->steps);
357 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000358 xmlFree(comp);
359}
360
361/**
362 * xmlXPathCompExprAdd:
363 * @comp: the compiled expression
364 * @ch1: first child index
365 * @ch2: second child index
366 * @op: an op
367 * @value: the first int value
368 * @value2: the second int value
369 * @value3: the third int value
370 * @value4: the first string value
371 * @value5: the second string value
372 *
373 * Add an step to an XPath Compiled Expression
374 *
375 * Returns -1 in case of failure, the index otherwise
376 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000377static int
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000378xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
379 xmlXPathOp op, int value,
380 int value2, int value3, void *value4, void *value5) {
381 if (comp->nbStep >= comp->maxStep) {
382 xmlXPathStepOp *real;
383
384 comp->maxStep *= 2;
385 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
386 comp->maxStep * sizeof(xmlXPathStepOp));
387 if (real == NULL) {
388 comp->maxStep /= 2;
389 xmlGenericError(xmlGenericErrorContext,
390 "xmlXPathCompExprAdd : realloc failed\n");
391 return(-1);
392 }
393 comp->steps = real;
394 }
395 comp->last = comp->nbStep;
396 comp->steps[comp->nbStep].ch1 = ch1;
397 comp->steps[comp->nbStep].ch2 = ch2;
398 comp->steps[comp->nbStep].op = op;
399 comp->steps[comp->nbStep].value = value;
400 comp->steps[comp->nbStep].value2 = value2;
401 comp->steps[comp->nbStep].value3 = value3;
402 comp->steps[comp->nbStep].value4 = value4;
403 comp->steps[comp->nbStep].value5 = value5;
Daniel Veillarde39a93d2001-04-28 14:35:02 +0000404 comp->steps[comp->nbStep].cache = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000405 return(comp->nbStep++);
406}
407
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000408#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
409 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
410 (op), (val), (val2), (val3), (val4), (val5))
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000411#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
412 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
413 (op), (val), (val2), (val3), (val4), (val5))
414
415#define PUSH_LEAVE_EXPR(op, val, val2) \
416xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
417
418#define PUSH_UNARY_EXPR(op, ch, val, val2) \
419xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
420
421#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
422xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
423
424/************************************************************************
Owen Taylor3473f882001-02-23 17:55:21 +0000425 * *
426 * Debugging related functions *
427 * *
428 ************************************************************************/
429
430#define TODO \
431 xmlGenericError(xmlGenericErrorContext, \
432 "Unimplemented block at %s:%d\n", \
433 __FILE__, __LINE__);
434
435#define STRANGE \
436 xmlGenericError(xmlGenericErrorContext, \
437 "Internal error at %s:%d\n", \
438 __FILE__, __LINE__);
439
440#ifdef LIBXML_DEBUG_ENABLED
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000441static void
442xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000443 int i;
444 char shift[100];
445
446 for (i = 0;((i < depth) && (i < 25));i++)
447 shift[2 * i] = shift[2 * i + 1] = ' ';
448 shift[2 * i] = shift[2 * i + 1] = 0;
449 if (cur == NULL) {
450 fprintf(output, shift);
451 fprintf(output, "Node is NULL !\n");
452 return;
453
454 }
455
456 if ((cur->type == XML_DOCUMENT_NODE) ||
457 (cur->type == XML_HTML_DOCUMENT_NODE)) {
458 fprintf(output, shift);
459 fprintf(output, " /\n");
460 } else if (cur->type == XML_ATTRIBUTE_NODE)
461 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
462 else
463 xmlDebugDumpOneNode(output, cur, depth);
464}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000465static void
466xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000467 xmlNodePtr tmp;
468 int i;
469 char shift[100];
470
471 for (i = 0;((i < depth) && (i < 25));i++)
472 shift[2 * i] = shift[2 * i + 1] = ' ';
473 shift[2 * i] = shift[2 * i + 1] = 0;
474 if (cur == NULL) {
475 fprintf(output, shift);
476 fprintf(output, "Node is NULL !\n");
477 return;
478
479 }
480
481 while (cur != NULL) {
482 tmp = cur;
483 cur = cur->next;
484 xmlDebugDumpOneNode(output, tmp, depth);
485 }
486}
Owen Taylor3473f882001-02-23 17:55:21 +0000487
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000488static void
489xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000490 int i;
491 char shift[100];
492
493 for (i = 0;((i < depth) && (i < 25));i++)
494 shift[2 * i] = shift[2 * i + 1] = ' ';
495 shift[2 * i] = shift[2 * i + 1] = 0;
496
497 if (cur == NULL) {
498 fprintf(output, shift);
499 fprintf(output, "NodeSet is NULL !\n");
500 return;
501
502 }
503
Daniel Veillard911f49a2001-04-07 15:39:35 +0000504 if (cur != NULL) {
505 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
506 for (i = 0;i < cur->nodeNr;i++) {
507 fprintf(output, shift);
508 fprintf(output, "%d", i + 1);
509 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
510 }
Owen Taylor3473f882001-02-23 17:55:21 +0000511 }
512}
513
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000514static void
515xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000516 int i;
517 char shift[100];
518
519 for (i = 0;((i < depth) && (i < 25));i++)
520 shift[2 * i] = shift[2 * i + 1] = ' ';
521 shift[2 * i] = shift[2 * i + 1] = 0;
522
523 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
524 fprintf(output, shift);
525 fprintf(output, "Value Tree is NULL !\n");
526 return;
527
528 }
529
530 fprintf(output, shift);
531 fprintf(output, "%d", i + 1);
532 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
533}
Owen Taylor3473f882001-02-23 17:55:21 +0000534#if defined(LIBXML_XPTR_ENABLED)
535void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000536static void
537xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000538 int i;
539 char shift[100];
540
541 for (i = 0;((i < depth) && (i < 25));i++)
542 shift[2 * i] = shift[2 * i + 1] = ' ';
543 shift[2 * i] = shift[2 * i + 1] = 0;
544
545 if (cur == NULL) {
546 fprintf(output, shift);
547 fprintf(output, "LocationSet is NULL !\n");
548 return;
549
550 }
551
552 for (i = 0;i < cur->locNr;i++) {
553 fprintf(output, shift);
554 fprintf(output, "%d : ", i + 1);
555 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
556 }
557}
558#endif
559
Daniel Veillardafcbe1c2001-03-19 10:57:13 +0000560/**
561 * xmlXPathDebugDumpObject:
562 * @output: the FILE * to dump the output
563 * @cur: the object to inspect
564 * @depth: indentation level
565 *
566 * Dump the content of the object for debugging purposes
567 */
568void
569xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
Owen Taylor3473f882001-02-23 17:55:21 +0000570 int i;
571 char shift[100];
572
573 for (i = 0;((i < depth) && (i < 25));i++)
574 shift[2 * i] = shift[2 * i + 1] = ' ';
575 shift[2 * i] = shift[2 * i + 1] = 0;
576
577 fprintf(output, shift);
578
579 if (cur == NULL) {
580 fprintf(output, "Object is empty (NULL)\n");
581 return;
582 }
583 switch(cur->type) {
584 case XPATH_UNDEFINED:
585 fprintf(output, "Object is uninitialized\n");
586 break;
587 case XPATH_NODESET:
588 fprintf(output, "Object is a Node Set :\n");
589 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
590 break;
591 case XPATH_XSLT_TREE:
592 fprintf(output, "Object is an XSLT value tree :\n");
Daniel Veillardf7cd4812001-02-23 18:44:52 +0000593 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
Owen Taylor3473f882001-02-23 17:55:21 +0000594 break;
595 case XPATH_BOOLEAN:
596 fprintf(output, "Object is a Boolean : ");
597 if (cur->boolval) fprintf(output, "true\n");
598 else fprintf(output, "false\n");
599 break;
600 case XPATH_NUMBER:
Daniel Veillard357c9602001-05-03 10:49:20 +0000601 switch (isinf(cur->floatval)) {
602 case 1:
603 fprintf(output, "Object is a number : +Infinity\n");
604 break;
605 case -1:
606 fprintf(output, "Object is a number : -Infinity\n");
607 break;
608 default:
609 if (isnan(cur->floatval)) {
610 fprintf(output, "Object is a number : NaN\n");
611 } else {
612 fprintf(output, "Object is a number : %0g\n", cur->floatval);
613 }
614 }
Owen Taylor3473f882001-02-23 17:55:21 +0000615 break;
616 case XPATH_STRING:
617 fprintf(output, "Object is a string : ");
618 xmlDebugDumpString(output, cur->stringval);
619 fprintf(output, "\n");
620 break;
621 case XPATH_POINT:
622 fprintf(output, "Object is a point : index %d in node", cur->index);
623 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
624 fprintf(output, "\n");
625 break;
626 case XPATH_RANGE:
627 if ((cur->user2 == NULL) ||
628 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
629 fprintf(output, "Object is a collapsed range :\n");
630 fprintf(output, shift);
631 if (cur->index >= 0)
632 fprintf(output, "index %d in ", cur->index);
633 fprintf(output, "node\n");
634 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
635 depth + 1);
636 } else {
637 fprintf(output, "Object is a range :\n");
638 fprintf(output, shift);
639 fprintf(output, "From ");
640 if (cur->index >= 0)
641 fprintf(output, "index %d in ", cur->index);
642 fprintf(output, "node\n");
643 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
644 depth + 1);
645 fprintf(output, shift);
646 fprintf(output, "To ");
647 if (cur->index2 >= 0)
648 fprintf(output, "index %d in ", cur->index2);
649 fprintf(output, "node\n");
650 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
651 depth + 1);
652 fprintf(output, "\n");
653 }
654 break;
655 case XPATH_LOCATIONSET:
656#if defined(LIBXML_XPTR_ENABLED)
657 fprintf(output, "Object is a Location Set:\n");
658 xmlXPathDebugDumpLocationSet(output,
659 (xmlLocationSetPtr) cur->user, depth);
660#endif
661 break;
662 case XPATH_USERS:
663 fprintf(output, "Object is user defined\n");
664 break;
665 }
666}
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000667
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000668static void
669xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000670 xmlXPathStepOpPtr op, int depth) {
671 int i;
672 char shift[100];
673
674 for (i = 0;((i < depth) && (i < 25));i++)
675 shift[2 * i] = shift[2 * i + 1] = ' ';
676 shift[2 * i] = shift[2 * i + 1] = 0;
677
678 fprintf(output, shift);
679 if (op == NULL) {
680 fprintf(output, "Step is NULL\n");
681 return;
682 }
683 switch (op->op) {
684 case XPATH_OP_END:
685 fprintf(output, "END"); break;
686 case XPATH_OP_AND:
687 fprintf(output, "AND"); break;
688 case XPATH_OP_OR:
689 fprintf(output, "OR"); break;
690 case XPATH_OP_EQUAL:
691 if (op->value)
692 fprintf(output, "EQUAL =");
693 else
694 fprintf(output, "EQUAL !=");
695 break;
696 case XPATH_OP_CMP:
697 if (op->value)
698 fprintf(output, "CMP <");
699 else
700 fprintf(output, "CMP >");
701 if (!op->value2)
702 fprintf(output, "=");
703 break;
704 case XPATH_OP_PLUS:
705 if (op->value == 0)
706 fprintf(output, "PLUS -");
707 else if (op->value == 1)
708 fprintf(output, "PLUS +");
709 else if (op->value == 2)
710 fprintf(output, "PLUS unary -");
711 else if (op->value == 3)
712 fprintf(output, "PLUS unary - -");
713 break;
714 case XPATH_OP_MULT:
715 if (op->value == 0)
716 fprintf(output, "MULT *");
717 else if (op->value == 1)
718 fprintf(output, "MULT div");
719 else
720 fprintf(output, "MULT mod");
721 break;
722 case XPATH_OP_UNION:
723 fprintf(output, "UNION"); break;
724 case XPATH_OP_ROOT:
725 fprintf(output, "ROOT"); break;
726 case XPATH_OP_NODE:
727 fprintf(output, "NODE"); break;
728 case XPATH_OP_RESET:
729 fprintf(output, "RESET"); break;
730 case XPATH_OP_SORT:
731 fprintf(output, "SORT"); break;
732 case XPATH_OP_COLLECT: {
733 xmlXPathAxisVal axis = op->value;
734 xmlXPathTestVal test = op->value2;
735 xmlXPathTypeVal type = op->value3;
736 const xmlChar *prefix = op->value4;
737 const xmlChar *name = op->value5;
738
739 fprintf(output, "COLLECT ");
740 switch (axis) {
741 case AXIS_ANCESTOR:
742 fprintf(output, " 'ancestors' "); break;
743 case AXIS_ANCESTOR_OR_SELF:
744 fprintf(output, " 'ancestors-or-self' "); break;
745 case AXIS_ATTRIBUTE:
746 fprintf(output, " 'attributes' "); break;
747 case AXIS_CHILD:
748 fprintf(output, " 'child' "); break;
749 case AXIS_DESCENDANT:
750 fprintf(output, " 'descendant' "); break;
751 case AXIS_DESCENDANT_OR_SELF:
752 fprintf(output, " 'descendant-or-self' "); break;
753 case AXIS_FOLLOWING:
754 fprintf(output, " 'following' "); break;
755 case AXIS_FOLLOWING_SIBLING:
756 fprintf(output, " 'following-siblings' "); break;
757 case AXIS_NAMESPACE:
758 fprintf(output, " 'namespace' "); break;
759 case AXIS_PARENT:
760 fprintf(output, " 'parent' "); break;
761 case AXIS_PRECEDING:
762 fprintf(output, " 'preceding' "); break;
763 case AXIS_PRECEDING_SIBLING:
764 fprintf(output, " 'preceding-sibling' "); break;
765 case AXIS_SELF:
766 fprintf(output, " 'self' "); break;
767 }
768 switch (test) {
769 case NODE_TEST_NONE:
770 fprintf(output, "'none' "); break;
771 case NODE_TEST_TYPE:
772 fprintf(output, "'type' "); break;
773 case NODE_TEST_PI:
774 fprintf(output, "'PI' "); break;
775 case NODE_TEST_ALL:
776 fprintf(output, "'all' "); break;
777 case NODE_TEST_NS:
778 fprintf(output, "'namespace' "); break;
779 case NODE_TEST_NAME:
780 fprintf(output, "'name' "); break;
781 }
782 switch (type) {
783 case NODE_TYPE_NODE:
784 fprintf(output, "'node' "); break;
785 case NODE_TYPE_COMMENT:
786 fprintf(output, "'comment' "); break;
787 case NODE_TYPE_TEXT:
788 fprintf(output, "'text' "); break;
789 case NODE_TYPE_PI:
790 fprintf(output, "'PI' "); break;
791 }
792 if (prefix != NULL)
793 fprintf(output, "%s:", prefix);
794 if (name != NULL)
795 fprintf(output, "%s", name);
796 break;
797
798 }
799 case XPATH_OP_VALUE: {
800 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
801
802 fprintf(output, "ELEM ");
803 xmlXPathDebugDumpObject(output, object, 0);
804 goto finish;
805 }
806 case XPATH_OP_VARIABLE: {
807 const xmlChar *prefix = op->value5;
808 const xmlChar *name = op->value4;
809
810 if (prefix != NULL)
811 fprintf(output, "VARIABLE %s:%s", prefix, name);
812 else
813 fprintf(output, "VARIABLE %s", name);
814 break;
815 }
816 case XPATH_OP_FUNCTION: {
817 int nbargs = op->value;
818 const xmlChar *prefix = op->value5;
819 const xmlChar *name = op->value4;
820
821 if (prefix != NULL)
822 fprintf(output, "FUNCTION %s:%s(%d args)",
823 prefix, name, nbargs);
824 else
825 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
826 break;
827 }
828 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
829 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
Daniel Veillardd8df6c02001-04-05 16:54:14 +0000830 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +0000831#ifdef LIBXML_XPTR_ENABLED
832 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
833#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000834 default:
835 fprintf(output, "UNKNOWN %d\n", op->op); return;
836 }
837 fprintf(output, "\n");
838finish:
839 if (op->ch1 >= 0)
840 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
841 if (op->ch2 >= 0)
842 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
843}
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000844
845void
846xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
847 int depth) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +0000848 int i;
849 char shift[100];
850
851 for (i = 0;((i < depth) && (i < 25));i++)
852 shift[2 * i] = shift[2 * i + 1] = ' ';
853 shift[2 * i] = shift[2 * i + 1] = 0;
854
855 fprintf(output, shift);
856
857 if (comp == NULL) {
858 fprintf(output, "Compiled Expression is NULL\n");
859 return;
860 }
861 fprintf(output, "Compiled Expression : %d elements\n",
862 comp->nbStep);
863 i = comp->last;
864 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
865}
Owen Taylor3473f882001-02-23 17:55:21 +0000866#endif
867
868/************************************************************************
869 * *
870 * Parser stacks related functions and macros *
871 * *
872 ************************************************************************/
873
874/*
875 * Generic function for accessing stacks in the Parser Context
876 */
877
878#define PUSH_AND_POP(type, name) \
879extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
880 if (ctxt->name##Nr >= ctxt->name##Max) { \
881 ctxt->name##Max *= 2; \
882 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
883 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
884 if (ctxt->name##Tab == NULL) { \
885 xmlGenericError(xmlGenericErrorContext, \
886 "realloc failed !\n"); \
887 return(0); \
888 } \
889 } \
890 ctxt->name##Tab[ctxt->name##Nr] = value; \
891 ctxt->name = value; \
892 return(ctxt->name##Nr++); \
893} \
894extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
895 type ret; \
896 if (ctxt->name##Nr <= 0) return(0); \
897 ctxt->name##Nr--; \
898 if (ctxt->name##Nr > 0) \
899 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
900 else \
901 ctxt->name = NULL; \
902 ret = ctxt->name##Tab[ctxt->name##Nr]; \
903 ctxt->name##Tab[ctxt->name##Nr] = 0; \
904 return(ret); \
905} \
906
907PUSH_AND_POP(xmlXPathObjectPtr, value)
908
909/*
910 * Macros for accessing the content. Those should be used only by the parser,
911 * and not exported.
912 *
913 * Dirty macros, i.e. one need to make assumption on the context to use them
914 *
915 * CUR_PTR return the current pointer to the xmlChar to be parsed.
916 * CUR returns the current xmlChar value, i.e. a 8 bit value
917 * in ISO-Latin or UTF-8.
918 * This should be used internally by the parser
919 * only to compare to ASCII values otherwise it would break when
920 * running with UTF-8 encoding.
921 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
922 * to compare on ASCII based substring.
923 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
924 * strings within the parser.
925 * CURRENT Returns the current char value, with the full decoding of
926 * UTF-8 if we are using this mode. It returns an int.
927 * NEXT Skip to the next character, this does the proper decoding
928 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
929 * It returns the pointer to the current xmlChar.
930 */
931
932#define CUR (*ctxt->cur)
933#define SKIP(val) ctxt->cur += (val)
934#define NXT(val) ctxt->cur[(val)]
935#define CUR_PTR ctxt->cur
Daniel Veillard61d80a22001-04-27 17:13:01 +0000936#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
937
938#define COPY_BUF(l,b,i,v) \
939 if (l == 1) b[i++] = (xmlChar) v; \
940 else i += xmlCopyChar(l,&b[i],v)
941
942#define NEXTL(l) ctxt->cur += l
Owen Taylor3473f882001-02-23 17:55:21 +0000943
944#define SKIP_BLANKS \
945 while (IS_BLANK(*(ctxt->cur))) NEXT
946
947#define CURRENT (*ctxt->cur)
948#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
949
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000950
951#ifndef DBL_DIG
952#define DBL_DIG 16
953#endif
954#ifndef DBL_EPSILON
955#define DBL_EPSILON 1E-9
956#endif
957
958#define UPPER_DOUBLE 1E9
959#define LOWER_DOUBLE 1E-5
960
961#define INTEGER_DIGITS DBL_DIG
962#define FRACTION_DIGITS (DBL_DIG + 1)
963#define EXPONENT_DIGITS (3 + 2)
964
965/**
966 * xmlXPathFormatNumber:
967 * @number: number to format
968 * @buffer: output buffer
969 * @buffersize: size of output buffer
970 *
971 * Convert the number into a string representation.
972 */
973static void
974xmlXPathFormatNumber(double number, char buffer[], int buffersize)
975{
976 switch (isinf(number)) {
977 case 1:
978 if (buffersize > (int)sizeof("+Infinity"))
979 sprintf(buffer, "+Infinity");
980 break;
981 case -1:
982 if (buffersize > (int)sizeof("-Infinity"))
983 sprintf(buffer, "-Infinity");
984 break;
985 default:
986 if (isnan(number)) {
987 if (buffersize > (int)sizeof("NaN"))
988 sprintf(buffer, "NaN");
989 } else {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000990 /* 3 is sign, decimal point, and terminating zero */
991 char work[DBL_DIG + EXPONENT_DIGITS + 3];
992 int integer_place, fraction_place;
993 char *ptr;
994 char *after_fraction;
995 double absolute_value;
996 int size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000997
Bjorn Reese70a9da52001-04-21 16:57:29 +0000998 absolute_value = fabs(number);
Bjorn Reesee1dc0112001-03-03 12:09:03 +0000999
Bjorn Reese70a9da52001-04-21 16:57:29 +00001000 /*
1001 * First choose format - scientific or regular floating point.
1002 * In either case, result is in work, and after_fraction points
1003 * just past the fractional part.
1004 */
1005 if ( ((absolute_value > UPPER_DOUBLE) ||
1006 (absolute_value < LOWER_DOUBLE)) &&
1007 (absolute_value != 0.0) ) {
1008 /* Use scientific notation */
1009 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1010 fraction_place = DBL_DIG - 1;
1011 snprintf(work, sizeof(work),"%*.*e",
1012 integer_place, fraction_place, number);
1013 after_fraction = strchr(work + DBL_DIG, 'e');
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001014 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00001015 else {
1016 /* Use regular notation */
1017 integer_place = 1 + (int)log10(absolute_value);
1018 fraction_place = (integer_place > 0)
1019 ? DBL_DIG - integer_place
1020 : DBL_DIG;
1021 size = snprintf(work, sizeof(work), "%0.*f",
1022 fraction_place, number);
1023 after_fraction = work + size;
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001024 }
1025
Bjorn Reese70a9da52001-04-21 16:57:29 +00001026 /* Remove fractional trailing zeroes */
1027 ptr = after_fraction;
1028 while (*(--ptr) == '0')
1029 ;
1030 if (*ptr != '.')
1031 ptr++;
1032 strcpy(ptr, after_fraction);
1033
1034 /* Finally copy result back to caller */
1035 size = strlen(work) + 1;
1036 if (size > buffersize) {
1037 work[buffersize - 1] = 0;
1038 size = buffersize;
1039 }
1040 memcpy(buffer, work, size);
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001041 }
1042 break;
1043 }
1044}
1045
Owen Taylor3473f882001-02-23 17:55:21 +00001046/************************************************************************
1047 * *
1048 * Error handling routines *
1049 * *
1050 ************************************************************************/
1051
1052
1053const char *xmlXPathErrorMessages[] = {
1054 "Ok",
1055 "Number encoding",
1056 "Unfinished litteral",
1057 "Start of litteral",
1058 "Expected $ for variable reference",
1059 "Undefined variable",
1060 "Invalid predicate",
1061 "Invalid expression",
1062 "Missing closing curly brace",
1063 "Unregistered function",
1064 "Invalid operand",
1065 "Invalid type",
1066 "Invalid number of arguments",
1067 "Invalid context size",
1068 "Invalid context position",
1069 "Memory allocation error",
1070 "Syntax error",
1071 "Resource error",
1072 "Sub resource error",
Daniel Veillard61d80a22001-04-27 17:13:01 +00001073 "Undefined namespace prefix",
1074 "Encoding error",
1075 "Char out of XML range"
Owen Taylor3473f882001-02-23 17:55:21 +00001076};
1077
1078/**
1079 * xmlXPathError:
1080 * @ctxt: the XPath Parser context
1081 * @file: the file name
1082 * @line: the line number
1083 * @no: the error number
1084 *
1085 * Create a new xmlNodeSetPtr of type double and of value @val
1086 *
1087 * Returns the newly created object.
1088 */
1089void
1090xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
1091 int line, int no) {
1092 int n;
1093 const xmlChar *cur;
1094 const xmlChar *base;
1095
1096 xmlGenericError(xmlGenericErrorContext,
1097 "Error %s:%d: %s\n", file, line,
1098 xmlXPathErrorMessages[no]);
1099
1100 cur = ctxt->cur;
1101 base = ctxt->base;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001102 if ((cur == NULL) || (base == NULL))
1103 return;
1104
Owen Taylor3473f882001-02-23 17:55:21 +00001105 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1106 cur--;
1107 }
1108 n = 0;
1109 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1110 cur--;
1111 if ((*cur == '\n') || (*cur == '\r')) cur++;
1112 base = cur;
1113 n = 0;
1114 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1115 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1116 n++;
1117 }
1118 xmlGenericError(xmlGenericErrorContext, "\n");
1119 cur = ctxt->cur;
1120 while ((*cur == '\n') || (*cur == '\r'))
1121 cur--;
1122 n = 0;
1123 while ((cur != base) && (n++ < 80)) {
1124 xmlGenericError(xmlGenericErrorContext, " ");
1125 base++;
1126 }
1127 xmlGenericError(xmlGenericErrorContext,"^\n");
1128}
1129
1130
1131/************************************************************************
1132 * *
1133 * Routines to handle NodeSets *
1134 * *
1135 ************************************************************************/
1136
1137/**
1138 * xmlXPathCmpNodes:
1139 * @node1: the first node
1140 * @node2: the second node
1141 *
1142 * Compare two nodes w.r.t document order
1143 *
1144 * Returns -2 in case of error 1 if first point < second point, 0 if
1145 * that's the same node, -1 otherwise
1146 */
1147int
1148xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1149 int depth1, depth2;
1150 xmlNodePtr cur, root;
1151
1152 if ((node1 == NULL) || (node2 == NULL))
1153 return(-2);
1154 /*
1155 * a couple of optimizations which will avoid computations in most cases
1156 */
1157 if (node1 == node2)
1158 return(0);
Daniel Veillardb33c2012001-04-25 12:59:04 +00001159 if ((node1->type == XML_NAMESPACE_DECL) ||
1160 (node2->type == XML_NAMESPACE_DECL))
1161 return(1);
Owen Taylor3473f882001-02-23 17:55:21 +00001162 if (node1 == node2->prev)
1163 return(1);
1164 if (node1 == node2->next)
1165 return(-1);
1166
1167 /*
1168 * compute depth to root
1169 */
1170 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1171 if (cur == node1)
1172 return(1);
1173 depth2++;
1174 }
1175 root = cur;
1176 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1177 if (cur == node2)
1178 return(-1);
1179 depth1++;
1180 }
1181 /*
1182 * Distinct document (or distinct entities :-( ) case.
1183 */
1184 if (root != cur) {
1185 return(-2);
1186 }
1187 /*
1188 * get the nearest common ancestor.
1189 */
1190 while (depth1 > depth2) {
1191 depth1--;
1192 node1 = node1->parent;
1193 }
1194 while (depth2 > depth1) {
1195 depth2--;
1196 node2 = node2->parent;
1197 }
1198 while (node1->parent != node2->parent) {
1199 node1 = node1->parent;
1200 node2 = node2->parent;
1201 /* should not happen but just in case ... */
1202 if ((node1 == NULL) || (node2 == NULL))
1203 return(-2);
1204 }
1205 /*
1206 * Find who's first.
1207 */
1208 if (node1 == node2->next)
1209 return(-1);
1210 for (cur = node1->next;cur != NULL;cur = cur->next)
1211 if (cur == node2)
1212 return(1);
1213 return(-1); /* assume there is no sibling list corruption */
1214}
1215
1216/**
1217 * xmlXPathNodeSetSort:
1218 * @set: the node set
1219 *
1220 * Sort the node set in document order
1221 */
1222void
1223xmlXPathNodeSetSort(xmlNodeSetPtr set) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001224 int i, j, incr, len;
Owen Taylor3473f882001-02-23 17:55:21 +00001225 xmlNodePtr tmp;
1226
1227 if (set == NULL)
1228 return;
1229
1230 /* Use Shell's sort to sort the node-set */
1231 len = set->nodeNr;
1232 for (incr = len / 2; incr > 0; incr /= 2) {
1233 for (i = incr; i < len; i++) {
1234 j = i - incr;
1235 while (j >= 0) {
Bjorn Reesee1dc0112001-03-03 12:09:03 +00001236 if (xmlXPathCmpNodes(set->nodeTab[j],
1237 set->nodeTab[j + incr]) == -1) {
Owen Taylor3473f882001-02-23 17:55:21 +00001238 tmp = set->nodeTab[j];
1239 set->nodeTab[j] = set->nodeTab[j + incr];
1240 set->nodeTab[j + incr] = tmp;
1241 j -= incr;
1242 } else
1243 break;
1244 }
1245 }
1246 }
1247}
1248
1249#define XML_NODESET_DEFAULT 10
1250/**
1251 * xmlXPathNodeSetCreate:
1252 * @val: an initial xmlNodePtr, or NULL
1253 *
1254 * Create a new xmlNodeSetPtr of type double and of value @val
1255 *
1256 * Returns the newly created object.
1257 */
1258xmlNodeSetPtr
1259xmlXPathNodeSetCreate(xmlNodePtr val) {
1260 xmlNodeSetPtr ret;
1261
1262 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1263 if (ret == NULL) {
1264 xmlGenericError(xmlGenericErrorContext,
1265 "xmlXPathNewNodeSet: out of memory\n");
1266 return(NULL);
1267 }
1268 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1269 if (val != NULL) {
1270 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1271 sizeof(xmlNodePtr));
1272 if (ret->nodeTab == NULL) {
1273 xmlGenericError(xmlGenericErrorContext,
1274 "xmlXPathNewNodeSet: out of memory\n");
1275 return(NULL);
1276 }
1277 memset(ret->nodeTab, 0 ,
1278 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1279 ret->nodeMax = XML_NODESET_DEFAULT;
1280 ret->nodeTab[ret->nodeNr++] = val;
1281 }
1282 return(ret);
1283}
1284
1285/**
1286 * xmlXPathNodeSetAdd:
1287 * @cur: the initial node set
1288 * @val: a new xmlNodePtr
1289 *
1290 * add a new xmlNodePtr ot an existing NodeSet
1291 */
1292void
1293xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1294 int i;
1295
1296 if (val == NULL) return;
1297
1298 /*
1299 * check against doublons
1300 */
1301 for (i = 0;i < cur->nodeNr;i++)
1302 if (cur->nodeTab[i] == val) return;
1303
1304 /*
1305 * grow the nodeTab if needed
1306 */
1307 if (cur->nodeMax == 0) {
1308 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1309 sizeof(xmlNodePtr));
1310 if (cur->nodeTab == NULL) {
1311 xmlGenericError(xmlGenericErrorContext,
1312 "xmlXPathNodeSetAdd: out of memory\n");
1313 return;
1314 }
1315 memset(cur->nodeTab, 0 ,
1316 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1317 cur->nodeMax = XML_NODESET_DEFAULT;
1318 } else if (cur->nodeNr == cur->nodeMax) {
1319 xmlNodePtr *temp;
1320
1321 cur->nodeMax *= 2;
1322 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1323 sizeof(xmlNodePtr));
1324 if (temp == NULL) {
1325 xmlGenericError(xmlGenericErrorContext,
1326 "xmlXPathNodeSetAdd: out of memory\n");
1327 return;
1328 }
1329 cur->nodeTab = temp;
1330 }
1331 cur->nodeTab[cur->nodeNr++] = val;
1332}
1333
1334/**
1335 * xmlXPathNodeSetAddUnique:
1336 * @cur: the initial node set
1337 * @val: a new xmlNodePtr
1338 *
1339 * add a new xmlNodePtr ot an existing NodeSet, optimized version
1340 * when we are sure the node is not already in the set.
1341 */
1342void
1343xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1344 if (val == NULL) return;
1345
1346 /*
1347 * grow the nodeTab if needed
1348 */
1349 if (cur->nodeMax == 0) {
1350 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1351 sizeof(xmlNodePtr));
1352 if (cur->nodeTab == NULL) {
1353 xmlGenericError(xmlGenericErrorContext,
1354 "xmlXPathNodeSetAddUnique: out of memory\n");
1355 return;
1356 }
1357 memset(cur->nodeTab, 0 ,
1358 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1359 cur->nodeMax = XML_NODESET_DEFAULT;
1360 } else if (cur->nodeNr == cur->nodeMax) {
1361 xmlNodePtr *temp;
1362
1363 cur->nodeMax *= 2;
1364 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1365 sizeof(xmlNodePtr));
1366 if (temp == NULL) {
1367 xmlGenericError(xmlGenericErrorContext,
1368 "xmlXPathNodeSetAddUnique: out of memory\n");
1369 return;
1370 }
1371 cur->nodeTab = temp;
1372 }
1373 cur->nodeTab[cur->nodeNr++] = val;
1374}
1375
1376/**
1377 * xmlXPathNodeSetMerge:
1378 * @val1: the first NodeSet or NULL
1379 * @val2: the second NodeSet
1380 *
1381 * Merges two nodesets, all nodes from @val2 are added to @val1
1382 * if @val1 is NULL, a new set is created and copied from @val2
1383 *
1384 * Returns val1 once extended or NULL in case of error.
1385 */
1386xmlNodeSetPtr
1387xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001388 int i, j, initNr, skip;
Owen Taylor3473f882001-02-23 17:55:21 +00001389
1390 if (val2 == NULL) return(val1);
1391 if (val1 == NULL) {
1392 val1 = xmlXPathNodeSetCreate(NULL);
1393 }
1394
1395 initNr = val1->nodeNr;
1396
1397 for (i = 0;i < val2->nodeNr;i++) {
1398 /*
1399 * check against doublons
1400 */
Daniel Veillardd8df6c02001-04-05 16:54:14 +00001401 skip = 0;
1402 for (j = 0; j < initNr; j++) {
1403 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1404 skip = 1;
1405 break;
1406 }
1407 }
1408 if (skip)
1409 continue;
Owen Taylor3473f882001-02-23 17:55:21 +00001410
1411 /*
1412 * grow the nodeTab if needed
1413 */
1414 if (val1->nodeMax == 0) {
1415 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1416 sizeof(xmlNodePtr));
1417 if (val1->nodeTab == NULL) {
1418 xmlGenericError(xmlGenericErrorContext,
1419 "xmlXPathNodeSetMerge: out of memory\n");
1420 return(NULL);
1421 }
1422 memset(val1->nodeTab, 0 ,
1423 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1424 val1->nodeMax = XML_NODESET_DEFAULT;
1425 } else if (val1->nodeNr == val1->nodeMax) {
1426 xmlNodePtr *temp;
1427
1428 val1->nodeMax *= 2;
1429 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1430 sizeof(xmlNodePtr));
1431 if (temp == NULL) {
1432 xmlGenericError(xmlGenericErrorContext,
1433 "xmlXPathNodeSetMerge: out of memory\n");
1434 return(NULL);
1435 }
1436 val1->nodeTab = temp;
1437 }
1438 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1439 }
1440
1441 return(val1);
1442}
1443
1444/**
1445 * xmlXPathNodeSetDel:
1446 * @cur: the initial node set
1447 * @val: an xmlNodePtr
1448 *
1449 * Removes an xmlNodePtr from an existing NodeSet
1450 */
1451void
1452xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
1453 int i;
1454
1455 if (cur == NULL) return;
1456 if (val == NULL) return;
1457
1458 /*
1459 * check against doublons
1460 */
1461 for (i = 0;i < cur->nodeNr;i++)
1462 if (cur->nodeTab[i] == val) break;
1463
1464 if (i >= cur->nodeNr) {
1465#ifdef DEBUG
1466 xmlGenericError(xmlGenericErrorContext,
1467 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
1468 val->name);
1469#endif
1470 return;
1471 }
1472 cur->nodeNr--;
1473 for (;i < cur->nodeNr;i++)
1474 cur->nodeTab[i] = cur->nodeTab[i + 1];
1475 cur->nodeTab[cur->nodeNr] = NULL;
1476}
1477
1478/**
1479 * xmlXPathNodeSetRemove:
1480 * @cur: the initial node set
1481 * @val: the index to remove
1482 *
1483 * Removes an entry from an existing NodeSet list.
1484 */
1485void
1486xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
1487 if (cur == NULL) return;
1488 if (val >= cur->nodeNr) return;
1489 cur->nodeNr--;
1490 for (;val < cur->nodeNr;val++)
1491 cur->nodeTab[val] = cur->nodeTab[val + 1];
1492 cur->nodeTab[cur->nodeNr] = NULL;
1493}
1494
1495/**
1496 * xmlXPathFreeNodeSet:
1497 * @obj: the xmlNodeSetPtr to free
1498 *
1499 * Free the NodeSet compound (not the actual nodes !).
1500 */
1501void
1502xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
1503 if (obj == NULL) return;
1504 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001505 xmlFree(obj->nodeTab);
1506 }
Owen Taylor3473f882001-02-23 17:55:21 +00001507 xmlFree(obj);
1508}
1509
1510/**
1511 * xmlXPathFreeValueTree:
1512 * @obj: the xmlNodeSetPtr to free
1513 *
1514 * Free the NodeSet compound and the actual tree, this is different
1515 * from xmlXPathFreeNodeSet()
1516 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001517static void
Owen Taylor3473f882001-02-23 17:55:21 +00001518xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
1519 int i;
1520
1521 if (obj == NULL) return;
1522 for (i = 0;i < obj->nodeNr;i++)
1523 if (obj->nodeTab[i] != NULL)
Daniel Veillardbbd51d52001-02-24 03:07:03 +00001524 xmlFreeNodeList(obj->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00001525
1526 if (obj->nodeTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00001527 xmlFree(obj->nodeTab);
1528 }
Owen Taylor3473f882001-02-23 17:55:21 +00001529 xmlFree(obj);
1530}
1531
1532#if defined(DEBUG) || defined(DEBUG_STEP)
1533/**
1534 * xmlGenericErrorContextNodeSet:
1535 * @output: a FILE * for the output
1536 * @obj: the xmlNodeSetPtr to free
1537 *
1538 * Quick display of a NodeSet
1539 */
1540void
1541xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
1542 int i;
1543
1544 if (output == NULL) output = xmlGenericErrorContext;
1545 if (obj == NULL) {
1546 fprintf(output, "NodeSet == NULL !\n");
1547 return;
1548 }
1549 if (obj->nodeNr == 0) {
1550 fprintf(output, "NodeSet is empty\n");
1551 return;
1552 }
1553 if (obj->nodeTab == NULL) {
1554 fprintf(output, " nodeTab == NULL !\n");
1555 return;
1556 }
1557 for (i = 0; i < obj->nodeNr; i++) {
1558 if (obj->nodeTab[i] == NULL) {
1559 fprintf(output, " NULL !\n");
1560 return;
1561 }
1562 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
1563 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1564 fprintf(output, " /");
1565 else if (obj->nodeTab[i]->name == NULL)
1566 fprintf(output, " noname!");
1567 else fprintf(output, " %s", obj->nodeTab[i]->name);
1568 }
1569 fprintf(output, "\n");
1570}
1571#endif
1572
1573/**
1574 * xmlXPathNewNodeSet:
1575 * @val: the NodePtr value
1576 *
1577 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1578 * it with the single Node @val
1579 *
1580 * Returns the newly created object.
1581 */
1582xmlXPathObjectPtr
1583xmlXPathNewNodeSet(xmlNodePtr val) {
1584 xmlXPathObjectPtr ret;
1585
1586 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1587 if (ret == NULL) {
1588 xmlGenericError(xmlGenericErrorContext,
1589 "xmlXPathNewNodeSet: out of memory\n");
1590 return(NULL);
1591 }
1592 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1593 ret->type = XPATH_NODESET;
Daniel Veillard77851712001-02-27 21:54:07 +00001594 ret->boolval = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001595 ret->nodesetval = xmlXPathNodeSetCreate(val);
1596 return(ret);
1597}
1598
1599/**
1600 * xmlXPathNewValueTree:
1601 * @val: the NodePtr value
1602 *
1603 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
1604 * it with the tree root @val
1605 *
1606 * Returns the newly created object.
1607 */
1608xmlXPathObjectPtr
1609xmlXPathNewValueTree(xmlNodePtr val) {
1610 xmlXPathObjectPtr ret;
1611
1612 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1613 if (ret == NULL) {
1614 xmlGenericError(xmlGenericErrorContext,
1615 "xmlXPathNewNodeSet: out of memory\n");
1616 return(NULL);
1617 }
1618 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1619 ret->type = XPATH_XSLT_TREE;
1620 ret->nodesetval = xmlXPathNodeSetCreate(val);
1621 return(ret);
1622}
1623
1624/**
1625 * xmlXPathNewNodeSetList:
1626 * @val: an existing NodeSet
1627 *
1628 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
1629 * it with the Nodeset @val
1630 *
1631 * Returns the newly created object.
1632 */
1633xmlXPathObjectPtr
1634xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
1635 xmlXPathObjectPtr ret;
1636 int i;
1637
1638 if (val == NULL)
1639 ret = NULL;
1640 else if (val->nodeTab == NULL)
1641 ret = xmlXPathNewNodeSet(NULL);
1642 else
1643 {
1644 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
1645 for (i = 1; i < val->nodeNr; ++i)
1646 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
1647 }
1648
1649 return(ret);
1650}
1651
1652/**
1653 * xmlXPathWrapNodeSet:
1654 * @val: the NodePtr value
1655 *
1656 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
1657 *
1658 * Returns the newly created object.
1659 */
1660xmlXPathObjectPtr
1661xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
1662 xmlXPathObjectPtr ret;
1663
1664 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1665 if (ret == NULL) {
1666 xmlGenericError(xmlGenericErrorContext,
1667 "xmlXPathWrapNodeSet: out of memory\n");
1668 return(NULL);
1669 }
1670 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1671 ret->type = XPATH_NODESET;
1672 ret->nodesetval = val;
1673 return(ret);
1674}
1675
1676/**
1677 * xmlXPathFreeNodeSetList:
1678 * @obj: an existing NodeSetList object
1679 *
1680 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
1681 * the list contrary to xmlXPathFreeObject().
1682 */
1683void
1684xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
1685 if (obj == NULL) return;
Owen Taylor3473f882001-02-23 17:55:21 +00001686 xmlFree(obj);
1687}
1688
1689/************************************************************************
1690 * *
1691 * Routines to handle extra functions *
1692 * *
1693 ************************************************************************/
1694
1695/**
1696 * xmlXPathRegisterFunc:
1697 * @ctxt: the XPath context
1698 * @name: the function name
1699 * @f: the function implementation or NULL
1700 *
1701 * Register a new function. If @f is NULL it unregisters the function
1702 *
1703 * Returns 0 in case of success, -1 in case of error
1704 */
1705int
1706xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
1707 xmlXPathFunction f) {
1708 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
1709}
1710
1711/**
1712 * xmlXPathRegisterFuncNS:
1713 * @ctxt: the XPath context
1714 * @name: the function name
1715 * @ns_uri: the function namespace URI
1716 * @f: the function implementation or NULL
1717 *
1718 * Register a new function. If @f is NULL it unregisters the function
1719 *
1720 * Returns 0 in case of success, -1 in case of error
1721 */
1722int
1723xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1724 const xmlChar *ns_uri, xmlXPathFunction f) {
1725 if (ctxt == NULL)
1726 return(-1);
1727 if (name == NULL)
1728 return(-1);
1729
1730 if (ctxt->funcHash == NULL)
1731 ctxt->funcHash = xmlHashCreate(0);
1732 if (ctxt->funcHash == NULL)
1733 return(-1);
1734 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
1735}
1736
1737/**
1738 * xmlXPathFunctionLookup:
1739 * @ctxt: the XPath context
1740 * @name: the function name
1741 *
1742 * Search in the Function array of the context for the given
1743 * function.
1744 *
1745 * Returns the xmlXPathFunction or NULL if not found
1746 */
1747xmlXPathFunction
1748xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1749 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
1750}
1751
1752/**
1753 * xmlXPathFunctionLookupNS:
1754 * @ctxt: the XPath context
1755 * @name: the function name
1756 * @ns_uri: the function namespace URI
1757 *
1758 * Search in the Function array of the context for the given
1759 * function.
1760 *
1761 * Returns the xmlXPathFunction or NULL if not found
1762 */
1763xmlXPathFunction
1764xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1765 const xmlChar *ns_uri) {
1766 if (ctxt == NULL)
1767 return(NULL);
1768 if (ctxt->funcHash == NULL)
1769 return(NULL);
1770 if (name == NULL)
1771 return(NULL);
1772
1773 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
1774}
1775
1776/**
1777 * xmlXPathRegisteredFuncsCleanup:
1778 * @ctxt: the XPath context
1779 *
1780 * Cleanup the XPath context data associated to registered functions
1781 */
1782void
1783xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
1784 if (ctxt == NULL)
1785 return;
1786
1787 xmlHashFree(ctxt->funcHash, NULL);
1788 ctxt->funcHash = NULL;
1789}
1790
1791/************************************************************************
1792 * *
1793 * Routines to handle Variable *
1794 * *
1795 ************************************************************************/
1796
1797/**
1798 * xmlXPathRegisterVariable:
1799 * @ctxt: the XPath context
1800 * @name: the variable name
1801 * @value: the variable value or NULL
1802 *
1803 * Register a new variable value. If @value is NULL it unregisters
1804 * the variable
1805 *
1806 * Returns 0 in case of success, -1 in case of error
1807 */
1808int
1809xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
1810 xmlXPathObjectPtr value) {
1811 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
1812}
1813
1814/**
1815 * xmlXPathRegisterVariableNS:
1816 * @ctxt: the XPath context
1817 * @name: the variable name
1818 * @ns_uri: the variable namespace URI
1819 * @value: the variable value or NULL
1820 *
1821 * Register a new variable value. If @value is NULL it unregisters
1822 * the variable
1823 *
1824 * Returns 0 in case of success, -1 in case of error
1825 */
1826int
1827xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1828 const xmlChar *ns_uri,
1829 xmlXPathObjectPtr value) {
1830 if (ctxt == NULL)
1831 return(-1);
1832 if (name == NULL)
1833 return(-1);
1834
1835 if (ctxt->varHash == NULL)
1836 ctxt->varHash = xmlHashCreate(0);
1837 if (ctxt->varHash == NULL)
1838 return(-1);
1839 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
1840 (void *) value,
1841 (xmlHashDeallocator)xmlXPathFreeObject));
1842}
1843
1844/**
1845 * xmlXPathRegisterVariableLookup:
1846 * @ctxt: the XPath context
1847 * @f: the lookup function
1848 * @data: the lookup data
1849 *
1850 * register an external mechanism to do variable lookup
1851 */
1852void
1853xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
1854 xmlXPathVariableLookupFunc f, void *data) {
1855 if (ctxt == NULL)
1856 return;
1857 ctxt->varLookupFunc = (void *) f;
1858 ctxt->varLookupData = data;
1859}
1860
1861/**
1862 * xmlXPathVariableLookup:
1863 * @ctxt: the XPath context
1864 * @name: the variable name
1865 *
1866 * Search in the Variable array of the context for the given
1867 * variable value.
1868 *
1869 * Returns the value or NULL if not found
1870 */
1871xmlXPathObjectPtr
1872xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
1873 if (ctxt == NULL)
1874 return(NULL);
1875
1876 if (ctxt->varLookupFunc != NULL) {
1877 xmlXPathObjectPtr ret;
1878
1879 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1880 (ctxt->varLookupData, name, NULL);
1881 if (ret != NULL) return(ret);
1882 }
1883 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
1884}
1885
1886/**
1887 * xmlXPathVariableLookupNS:
1888 * @ctxt: the XPath context
1889 * @name: the variable name
1890 * @ns_uri: the variable namespace URI
1891 *
1892 * Search in the Variable array of the context for the given
1893 * variable value.
1894 *
1895 * Returns the value or NULL if not found
1896 */
1897xmlXPathObjectPtr
1898xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
1899 const xmlChar *ns_uri) {
1900 if (ctxt == NULL)
1901 return(NULL);
1902
1903 if (ctxt->varLookupFunc != NULL) {
1904 xmlXPathObjectPtr ret;
1905
1906 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
1907 (ctxt->varLookupData, name, ns_uri);
1908 if (ret != NULL) return(ret);
1909 }
1910
1911 if (ctxt->varHash == NULL)
1912 return(NULL);
1913 if (name == NULL)
1914 return(NULL);
1915
1916 return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
1917}
1918
1919/**
1920 * xmlXPathRegisteredVariablesCleanup:
1921 * @ctxt: the XPath context
1922 *
1923 * Cleanup the XPath context data associated to registered variables
1924 */
1925void
1926xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1927 if (ctxt == NULL)
1928 return;
1929
Daniel Veillard76d66f42001-05-16 21:05:17 +00001930 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
Owen Taylor3473f882001-02-23 17:55:21 +00001931 ctxt->varHash = NULL;
1932}
1933
1934/**
1935 * xmlXPathRegisterNs:
1936 * @ctxt: the XPath context
1937 * @prefix: the namespace prefix
1938 * @ns_uri: the namespace name
1939 *
1940 * Register a new namespace. If @ns_uri is NULL it unregisters
1941 * the namespace
1942 *
1943 * Returns 0 in case of success, -1 in case of error
1944 */
1945int
1946xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
1947 const xmlChar *ns_uri) {
1948 if (ctxt == NULL)
1949 return(-1);
1950 if (prefix == NULL)
1951 return(-1);
1952
1953 if (ctxt->nsHash == NULL)
1954 ctxt->nsHash = xmlHashCreate(10);
1955 if (ctxt->nsHash == NULL)
1956 return(-1);
1957 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
1958 (xmlHashDeallocator)xmlFree));
1959}
1960
1961/**
1962 * xmlXPathNsLookup:
1963 * @ctxt: the XPath context
1964 * @prefix: the namespace prefix value
1965 *
1966 * Search in the namespace declaration array of the context for the given
1967 * namespace name associated to the given prefix
1968 *
1969 * Returns the value or NULL if not found
1970 */
1971const xmlChar *
1972xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
1973 if (ctxt == NULL)
1974 return(NULL);
1975 if (prefix == NULL)
1976 return(NULL);
1977
1978#ifdef XML_XML_NAMESPACE
1979 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
1980 return(XML_XML_NAMESPACE);
1981#endif
1982
Daniel Veillardc8f620b2001-04-30 20:31:33 +00001983 if (ctxt->namespaces != NULL) {
1984 int i;
1985
1986 for (i = 0;i < ctxt->nsNr;i++) {
1987 if ((ctxt->namespaces[i] != NULL) &&
1988 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
1989 return(ctxt->namespaces[i]->href);
1990 }
1991 }
Owen Taylor3473f882001-02-23 17:55:21 +00001992
1993 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
1994}
1995
1996/**
1997 * xmlXPathRegisteredVariablesCleanup:
1998 * @ctxt: the XPath context
1999 *
2000 * Cleanup the XPath context data associated to registered variables
2001 */
2002void
2003xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2004 if (ctxt == NULL)
2005 return;
2006
2007 xmlHashFree(ctxt->nsHash, NULL);
2008 ctxt->nsHash = NULL;
2009}
2010
2011/************************************************************************
2012 * *
2013 * Routines to handle Values *
2014 * *
2015 ************************************************************************/
2016
2017/* Allocations are terrible, one need to optimize all this !!! */
2018
2019/**
2020 * xmlXPathNewFloat:
2021 * @val: the double value
2022 *
2023 * Create a new xmlXPathObjectPtr of type double and of value @val
2024 *
2025 * Returns the newly created object.
2026 */
2027xmlXPathObjectPtr
2028xmlXPathNewFloat(double val) {
2029 xmlXPathObjectPtr ret;
2030
2031 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2032 if (ret == NULL) {
2033 xmlGenericError(xmlGenericErrorContext,
2034 "xmlXPathNewFloat: out of memory\n");
2035 return(NULL);
2036 }
2037 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2038 ret->type = XPATH_NUMBER;
2039 ret->floatval = val;
2040 return(ret);
2041}
2042
2043/**
2044 * xmlXPathNewBoolean:
2045 * @val: the boolean value
2046 *
2047 * Create a new xmlXPathObjectPtr of type boolean and of value @val
2048 *
2049 * Returns the newly created object.
2050 */
2051xmlXPathObjectPtr
2052xmlXPathNewBoolean(int val) {
2053 xmlXPathObjectPtr ret;
2054
2055 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2056 if (ret == NULL) {
2057 xmlGenericError(xmlGenericErrorContext,
2058 "xmlXPathNewBoolean: out of memory\n");
2059 return(NULL);
2060 }
2061 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2062 ret->type = XPATH_BOOLEAN;
2063 ret->boolval = (val != 0);
2064 return(ret);
2065}
2066
2067/**
2068 * xmlXPathNewString:
2069 * @val: the xmlChar * value
2070 *
2071 * Create a new xmlXPathObjectPtr of type string and of value @val
2072 *
2073 * Returns the newly created object.
2074 */
2075xmlXPathObjectPtr
2076xmlXPathNewString(const xmlChar *val) {
2077 xmlXPathObjectPtr ret;
2078
2079 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2080 if (ret == NULL) {
2081 xmlGenericError(xmlGenericErrorContext,
2082 "xmlXPathNewString: out of memory\n");
2083 return(NULL);
2084 }
2085 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2086 ret->type = XPATH_STRING;
2087 if (val != NULL)
2088 ret->stringval = xmlStrdup(val);
2089 else
2090 ret->stringval = xmlStrdup((const xmlChar *)"");
2091 return(ret);
2092}
2093
2094/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002095 * xmlXPathWrapString:
2096 * @val: the xmlChar * value
2097 *
2098 * Wraps the @val string into an XPath object.
2099 *
2100 * Returns the newly created object.
2101 */
2102xmlXPathObjectPtr
2103xmlXPathWrapString (xmlChar *val) {
2104 xmlXPathObjectPtr ret;
2105
2106 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2107 if (ret == NULL) {
2108 xmlGenericError(xmlGenericErrorContext,
2109 "xmlXPathWrapString: out of memory\n");
2110 return(NULL);
2111 }
2112 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2113 ret->type = XPATH_STRING;
2114 ret->stringval = val;
2115 return(ret);
2116}
2117
2118/**
Owen Taylor3473f882001-02-23 17:55:21 +00002119 * xmlXPathNewCString:
2120 * @val: the char * value
2121 *
2122 * Create a new xmlXPathObjectPtr of type string and of value @val
2123 *
2124 * Returns the newly created object.
2125 */
2126xmlXPathObjectPtr
2127xmlXPathNewCString(const char *val) {
2128 xmlXPathObjectPtr ret;
2129
2130 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2131 if (ret == NULL) {
2132 xmlGenericError(xmlGenericErrorContext,
2133 "xmlXPathNewCString: out of memory\n");
2134 return(NULL);
2135 }
2136 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2137 ret->type = XPATH_STRING;
2138 ret->stringval = xmlStrdup(BAD_CAST val);
2139 return(ret);
2140}
2141
2142/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002143 * xmlXPathWrapCString:
2144 * @val: the char * value
2145 *
2146 * Wraps a string into an XPath object.
2147 *
2148 * Returns the newly created object.
2149 */
2150xmlXPathObjectPtr
2151xmlXPathWrapCString (char * val) {
2152 return(xmlXPathWrapString((xmlChar *)(val)));
2153}
2154
2155/**
Owen Taylor3473f882001-02-23 17:55:21 +00002156 * xmlXPathObjectCopy:
2157 * @val: the original object
2158 *
2159 * allocate a new copy of a given object
2160 *
2161 * Returns the newly created object.
2162 */
2163xmlXPathObjectPtr
2164xmlXPathObjectCopy(xmlXPathObjectPtr val) {
2165 xmlXPathObjectPtr ret;
2166
2167 if (val == NULL)
2168 return(NULL);
2169
2170 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2171 if (ret == NULL) {
2172 xmlGenericError(xmlGenericErrorContext,
2173 "xmlXPathObjectCopy: out of memory\n");
2174 return(NULL);
2175 }
2176 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
2177 switch (val->type) {
2178 case XPATH_BOOLEAN:
2179 case XPATH_NUMBER:
2180 case XPATH_POINT:
2181 case XPATH_RANGE:
2182 break;
2183 case XPATH_STRING:
2184 ret->stringval = xmlStrdup(val->stringval);
2185 break;
2186 case XPATH_XSLT_TREE:
2187 if ((val->nodesetval != NULL) &&
2188 (val->nodesetval->nodeTab != NULL))
2189 ret->nodesetval = xmlXPathNodeSetCreate(
2190 xmlCopyNode(val->nodesetval->nodeTab[0], 1));
2191 else
2192 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
2193 break;
2194 case XPATH_NODESET:
2195 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
2196 break;
2197 case XPATH_LOCATIONSET:
2198#ifdef LIBXML_XPTR_ENABLED
2199 {
2200 xmlLocationSetPtr loc = val->user;
2201 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
2202 break;
2203 }
2204#endif
2205 case XPATH_UNDEFINED:
2206 case XPATH_USERS:
2207 xmlGenericError(xmlGenericErrorContext,
2208 "xmlXPathObjectCopy: unsupported type %d\n",
2209 val->type);
2210 break;
2211 }
2212 return(ret);
2213}
2214
2215/**
2216 * xmlXPathFreeObject:
2217 * @obj: the object to free
2218 *
2219 * Free up an xmlXPathObjectPtr object.
2220 */
2221void
2222xmlXPathFreeObject(xmlXPathObjectPtr obj) {
2223 if (obj == NULL) return;
2224 if (obj->type == XPATH_NODESET) {
Daniel Veillard77851712001-02-27 21:54:07 +00002225 if (obj->boolval) {
2226 obj->type = XPATH_XSLT_TREE;
2227 if (obj->nodesetval != NULL)
2228 xmlXPathFreeValueTree(obj->nodesetval);
2229 } else {
2230 if (obj->nodesetval != NULL)
2231 xmlXPathFreeNodeSet(obj->nodesetval);
2232 }
Owen Taylor3473f882001-02-23 17:55:21 +00002233#ifdef LIBXML_XPTR_ENABLED
2234 } else if (obj->type == XPATH_LOCATIONSET) {
2235 if (obj->user != NULL)
2236 xmlXPtrFreeLocationSet(obj->user);
2237#endif
2238 } else if (obj->type == XPATH_STRING) {
2239 if (obj->stringval != NULL)
2240 xmlFree(obj->stringval);
2241 } else if (obj->type == XPATH_XSLT_TREE) {
2242 if (obj->nodesetval != NULL)
2243 xmlXPathFreeValueTree(obj->nodesetval);
2244 }
2245
Owen Taylor3473f882001-02-23 17:55:21 +00002246 xmlFree(obj);
2247}
2248
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002249
2250/************************************************************************
2251 * *
2252 * Type Casting Routines *
2253 * *
2254 ************************************************************************/
2255
2256/**
2257 * xmlXPathCastBooleanToString:
2258 * @val: a boolean
2259 *
2260 * Converts a boolean to its string value.
2261 *
2262 * Returns a newly allocated string.
2263 */
2264xmlChar *
2265xmlXPathCastBooleanToString (int val) {
2266 xmlChar *ret;
2267 if (val)
2268 ret = xmlStrdup((const xmlChar *) "true");
2269 else
2270 ret = xmlStrdup((const xmlChar *) "false");
2271 return(ret);
2272}
2273
2274/**
2275 * xmlXPathCastNumberToString:
2276 * @val: a number
2277 *
2278 * Converts a number to its string value.
2279 *
2280 * Returns a newly allocated string.
2281 */
2282xmlChar *
2283xmlXPathCastNumberToString (double val) {
2284 xmlChar *ret;
2285 switch (isinf(val)) {
2286 case 1:
2287 ret = xmlStrdup((const xmlChar *) "+Infinity");
2288 break;
2289 case -1:
2290 ret = xmlStrdup((const xmlChar *) "-Infinity");
2291 break;
2292 default:
2293 if (isnan(val)) {
2294 ret = xmlStrdup((const xmlChar *) "NaN");
2295 } else {
2296 /* could be improved */
2297 char buf[100];
2298 xmlXPathFormatNumber(val, buf, 100);
2299 ret = xmlStrdup((const xmlChar *) buf);
2300 }
2301 }
2302 return(ret);
2303}
2304
2305/**
2306 * xmlXPathCastNodeToString:
2307 * @node: a node
2308 *
2309 * Converts a node to its string value.
2310 *
2311 * Returns a newly allocated string.
2312 */
2313xmlChar *
2314xmlXPathCastNodeToString (xmlNodePtr node) {
2315 return(xmlNodeGetContent(node));
2316}
2317
2318/**
2319 * xmlXPathCastNodeSetToString:
2320 * @ns: a node-set
2321 *
2322 * Converts a node-set to its string value.
2323 *
2324 * Returns a newly allocated string.
2325 */
2326xmlChar *
2327xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
2328 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
2329 return(xmlStrdup((const xmlChar *) ""));
2330
2331 xmlXPathNodeSetSort(ns);
2332 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
2333}
2334
2335/**
2336 * xmlXPathCastToString:
2337 * @val: an XPath object
2338 *
2339 * Converts an existing object to its string() equivalent
2340 *
2341 * Returns the string value of the object, NULL in case of error.
2342 * A new string is allocated only if needed (val isn't a
2343 * string object).
2344 */
2345xmlChar *
2346xmlXPathCastToString(xmlXPathObjectPtr val) {
2347 xmlChar *ret = NULL;
2348
2349 if (val == NULL)
2350 return(xmlStrdup((const xmlChar *) ""));
2351 switch (val->type) {
2352 case XPATH_UNDEFINED:
2353#ifdef DEBUG_EXPR
2354 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
2355#endif
2356 ret = xmlStrdup((const xmlChar *) "");
2357 break;
2358 case XPATH_XSLT_TREE:
2359 case XPATH_NODESET:
2360 ret = xmlXPathCastNodeSetToString(val->nodesetval);
2361 break;
2362 case XPATH_STRING:
2363 return(val->stringval);
2364 case XPATH_BOOLEAN:
2365 ret = xmlXPathCastBooleanToString(val->boolval);
2366 break;
2367 case XPATH_NUMBER: {
2368 ret = xmlXPathCastNumberToString(val->floatval);
2369 break;
2370 }
2371 case XPATH_USERS:
2372 case XPATH_POINT:
2373 case XPATH_RANGE:
2374 case XPATH_LOCATIONSET:
2375 TODO
2376 ret = xmlStrdup((const xmlChar *) "");
2377 break;
2378 }
2379 return(ret);
2380}
2381
2382/**
2383 * xmlXPathConvertString:
2384 * @val: an XPath object
2385 *
2386 * Converts an existing object to its string() equivalent
2387 *
2388 * Returns the new object, the old one is freed (or the operation
2389 * is done directly on @val)
2390 */
2391xmlXPathObjectPtr
2392xmlXPathConvertString(xmlXPathObjectPtr val) {
2393 xmlChar *res = NULL;
2394
2395 if (val == NULL)
2396 return(xmlXPathNewCString(""));
2397
2398 switch (val->type) {
2399 case XPATH_UNDEFINED:
2400#ifdef DEBUG_EXPR
2401 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2402#endif
2403 break;
2404 case XPATH_XSLT_TREE:
2405 case XPATH_NODESET:
2406 res = xmlXPathCastNodeSetToString(val->nodesetval);
2407 break;
2408 case XPATH_STRING:
2409 return(val);
2410 case XPATH_BOOLEAN:
2411 res = xmlXPathCastBooleanToString(val->boolval);
2412 break;
2413 case XPATH_NUMBER:
2414 res = xmlXPathCastNumberToString(val->floatval);
2415 break;
2416 case XPATH_USERS:
2417 case XPATH_POINT:
2418 case XPATH_RANGE:
2419 case XPATH_LOCATIONSET:
2420 TODO;
2421 break;
2422 }
2423 xmlXPathFreeObject(val);
2424 if (res == NULL)
2425 return(xmlXPathNewCString(""));
2426 return(xmlXPathWrapString(res));
2427}
2428
2429/**
2430 * xmlXPathCastBooleanToNumber:
2431 * @val: a boolean
2432 *
2433 * Converts a boolean to its number value
2434 *
2435 * Returns the number value
2436 */
2437double
2438xmlXPathCastBooleanToNumber(int val) {
2439 if (val)
2440 return(1.0);
2441 return(0.0);
2442}
2443
2444/**
2445 * xmlXPathCastStringToNumber:
2446 * @val: a string
2447 *
2448 * Converts a string to its number value
2449 *
2450 * Returns the number value
2451 */
2452double
2453xmlXPathCastStringToNumber(const xmlChar * val) {
2454 return(xmlXPathStringEvalNumber(val));
2455}
2456
2457/**
2458 * xmlXPathCastNodeToNumber:
2459 * @node: a node
2460 *
2461 * Converts a node to its number value
2462 *
2463 * Returns the number value
2464 */
2465double
2466xmlXPathCastNodeToNumber (xmlNodePtr node) {
2467 xmlChar *strval;
2468 double ret;
2469
2470 if (node == NULL)
2471 return(xmlXPathNAN);
2472 strval = xmlXPathCastNodeToString(node);
2473 if (strval == NULL)
2474 return(xmlXPathNAN);
2475 ret = xmlXPathCastStringToNumber(strval);
2476 xmlFree(strval);
2477
2478 return(ret);
2479}
2480
2481/**
2482 * xmlXPathCastNodeSetToNumber:
2483 * @ns: a node-set
2484 *
2485 * Converts a node-set to its number value
2486 *
2487 * Returns the number value
2488 */
2489double
2490xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
2491 xmlChar *str;
2492 double ret;
2493
2494 if (ns == NULL)
2495 return(xmlXPathNAN);
2496 str = xmlXPathCastNodeSetToString(ns);
2497 ret = xmlXPathCastStringToNumber(str);
2498 xmlFree(str);
2499 return(ret);
2500}
2501
2502/**
2503 * xmlXPathCastToNumber:
2504 * @val: an XPath object
2505 *
2506 * Converts an XPath object to its number value
2507 *
2508 * Returns the number value
2509 */
2510double
2511xmlXPathCastToNumber(xmlXPathObjectPtr val) {
2512 double ret = 0.0;
2513
2514 if (val == NULL)
2515 return(xmlXPathNAN);
2516 switch (val->type) {
2517 case XPATH_UNDEFINED:
2518#ifdef DEGUB_EXPR
2519 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
2520#endif
2521 ret = xmlXPathNAN;
2522 break;
2523 case XPATH_XSLT_TREE:
2524 case XPATH_NODESET:
2525 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
2526 break;
2527 case XPATH_STRING:
2528 ret = xmlXPathCastStringToNumber(val->stringval);
2529 break;
2530 case XPATH_NUMBER:
2531 ret = val->floatval;
2532 break;
2533 case XPATH_BOOLEAN:
2534 ret = xmlXPathCastBooleanToNumber(val->boolval);
2535 break;
2536 case XPATH_USERS:
2537 case XPATH_POINT:
2538 case XPATH_RANGE:
2539 case XPATH_LOCATIONSET:
2540 TODO;
2541 ret = xmlXPathNAN;
2542 break;
2543 }
2544 return(ret);
2545}
2546
2547/**
2548 * xmlXPathConvertNumber:
2549 * @val: an XPath object
2550 *
2551 * Converts an existing object to its number() equivalent
2552 *
2553 * Returns the new object, the old one is freed (or the operation
2554 * is done directly on @val)
2555 */
2556xmlXPathObjectPtr
2557xmlXPathConvertNumber(xmlXPathObjectPtr val) {
2558 xmlXPathObjectPtr ret;
2559
2560 if (val == NULL)
2561 return(xmlXPathNewFloat(0.0));
2562 if (val->type == XPATH_NUMBER)
2563 return(val);
2564 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
2565 xmlXPathFreeObject(val);
2566 return(ret);
2567}
2568
2569/**
2570 * xmlXPathCastNumberToBoolean:
2571 * @val: a number
2572 *
2573 * Converts a number to its boolean value
2574 *
2575 * Returns the boolean value
2576 */
2577int
2578xmlXPathCastNumberToBoolean (double val) {
2579 if (isnan(val) || (val == 0.0))
2580 return(0);
2581 return(1);
2582}
2583
2584/**
2585 * xmlXPathCastStringToBoolean:
2586 * @val: a string
2587 *
2588 * Converts a string to its boolean value
2589 *
2590 * Returns the boolean value
2591 */
2592int
2593xmlXPathCastStringToBoolean (const xmlChar *val) {
2594 if ((val == NULL) || (xmlStrlen(val) == 0))
2595 return(0);
2596 return(1);
2597}
2598
2599/**
2600 * xmlXPathCastNodeSetToBoolean:
2601 * @ns: a node-set
2602 *
2603 * Converts a node-set to its boolean value
2604 *
2605 * Returns the boolean value
2606 */
2607int
2608xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
2609 if ((ns == NULL) || (ns->nodeNr == 0))
2610 return(0);
2611 return(1);
2612}
2613
2614/**
2615 * xmlXpathCastToBoolean:
2616 * @val: an XPath object
2617 *
2618 * Converts an XPath object to its boolean value
2619 *
2620 * Returns the boolean value
2621 */
2622int
2623xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
2624 int ret = 0;
2625
2626 if (val == NULL)
2627 return(0);
2628 switch (val->type) {
2629 case XPATH_UNDEFINED:
2630#ifdef DEBUG_EXPR
2631 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
2632#endif
2633 ret = 0;
2634 break;
2635 case XPATH_XSLT_TREE:
2636 case XPATH_NODESET:
2637 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
2638 break;
2639 case XPATH_STRING:
2640 ret = xmlXPathCastStringToBoolean(val->stringval);
2641 break;
2642 case XPATH_NUMBER:
2643 ret = xmlXPathCastNumberToBoolean(val->floatval);
2644 break;
2645 case XPATH_BOOLEAN:
2646 ret = val->boolval;
2647 break;
2648 case XPATH_USERS:
2649 case XPATH_POINT:
2650 case XPATH_RANGE:
2651 case XPATH_LOCATIONSET:
2652 TODO;
2653 ret = 0;
2654 break;
2655 }
2656 return(ret);
2657}
2658
2659
2660/**
2661 * xmlXPathConvertBoolean:
2662 * @val: an XPath object
2663 *
2664 * Converts an existing object to its boolean() equivalent
2665 *
2666 * Returns the new object, the old one is freed (or the operation
2667 * is done directly on @val)
2668 */
2669xmlXPathObjectPtr
2670xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
2671 xmlXPathObjectPtr ret;
2672
2673 if (val == NULL)
2674 return(xmlXPathNewBoolean(0));
2675 if (val->type == XPATH_BOOLEAN)
2676 return(val);
2677 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
2678 xmlXPathFreeObject(val);
2679 return(ret);
2680}
2681
Owen Taylor3473f882001-02-23 17:55:21 +00002682/************************************************************************
2683 * *
2684 * Routines to handle XPath contexts *
2685 * *
2686 ************************************************************************/
2687
2688/**
2689 * xmlXPathNewContext:
2690 * @doc: the XML document
2691 *
2692 * Create a new xmlXPathContext
2693 *
2694 * Returns the xmlXPathContext just allocated.
2695 */
2696xmlXPathContextPtr
2697xmlXPathNewContext(xmlDocPtr doc) {
2698 xmlXPathContextPtr ret;
2699
2700 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
2701 if (ret == NULL) {
2702 xmlGenericError(xmlGenericErrorContext,
2703 "xmlXPathNewContext: out of memory\n");
2704 return(NULL);
2705 }
2706 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
2707 ret->doc = doc;
2708 ret->node = NULL;
2709
2710 ret->varHash = NULL;
2711
2712 ret->nb_types = 0;
2713 ret->max_types = 0;
2714 ret->types = NULL;
2715
2716 ret->funcHash = xmlHashCreate(0);
2717
2718 ret->nb_axis = 0;
2719 ret->max_axis = 0;
2720 ret->axis = NULL;
2721
2722 ret->nsHash = NULL;
2723 ret->user = NULL;
2724
2725 ret->contextSize = -1;
2726 ret->proximityPosition = -1;
2727
2728 xmlXPathRegisterAllFunctions(ret);
2729
2730 return(ret);
2731}
2732
2733/**
2734 * xmlXPathFreeContext:
2735 * @ctxt: the context to free
2736 *
2737 * Free up an xmlXPathContext
2738 */
2739void
2740xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
2741 xmlXPathRegisteredNsCleanup(ctxt);
2742 xmlXPathRegisteredFuncsCleanup(ctxt);
2743 xmlXPathRegisteredVariablesCleanup(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00002744 xmlFree(ctxt);
2745}
2746
2747/************************************************************************
2748 * *
2749 * Routines to handle XPath parser contexts *
2750 * *
2751 ************************************************************************/
2752
2753#define CHECK_CTXT(ctxt) \
2754 if (ctxt == NULL) { \
2755 xmlGenericError(xmlGenericErrorContext, \
2756 "%s:%d Internal error: ctxt == NULL\n", \
2757 __FILE__, __LINE__); \
2758 } \
2759
2760
2761#define CHECK_CONTEXT(ctxt) \
2762 if (ctxt == NULL) { \
2763 xmlGenericError(xmlGenericErrorContext, \
2764 "%s:%d Internal error: no context\n", \
2765 __FILE__, __LINE__); \
2766 } \
2767 else if (ctxt->doc == NULL) { \
2768 xmlGenericError(xmlGenericErrorContext, \
2769 "%s:%d Internal error: no document\n", \
2770 __FILE__, __LINE__); \
2771 } \
2772 else if (ctxt->doc->children == NULL) { \
2773 xmlGenericError(xmlGenericErrorContext, \
2774 "%s:%d Internal error: document without root\n", \
2775 __FILE__, __LINE__); \
2776 } \
2777
2778
2779/**
2780 * xmlXPathNewParserContext:
2781 * @str: the XPath expression
2782 * @ctxt: the XPath context
2783 *
2784 * Create a new xmlXPathParserContext
2785 *
2786 * Returns the xmlXPathParserContext just allocated.
2787 */
2788xmlXPathParserContextPtr
2789xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
2790 xmlXPathParserContextPtr ret;
2791
2792 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2793 if (ret == NULL) {
2794 xmlGenericError(xmlGenericErrorContext,
2795 "xmlXPathNewParserContext: out of memory\n");
2796 return(NULL);
2797 }
2798 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2799 ret->cur = ret->base = str;
2800 ret->context = ctxt;
2801
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002802 ret->comp = xmlXPathNewCompExpr();
2803 if (ret->comp == NULL) {
2804 xmlFree(ret->valueTab);
2805 xmlFree(ret);
2806 return(NULL);
2807 }
2808
2809 return(ret);
2810}
2811
2812/**
2813 * xmlXPathCompParserContext:
2814 * @comp: the XPath compiled expression
2815 * @ctxt: the XPath context
2816 *
2817 * Create a new xmlXPathParserContext when processing a compiled expression
2818 *
2819 * Returns the xmlXPathParserContext just allocated.
2820 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002821static xmlXPathParserContextPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002822xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
2823 xmlXPathParserContextPtr ret;
2824
2825 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
2826 if (ret == NULL) {
2827 xmlGenericError(xmlGenericErrorContext,
2828 "xmlXPathNewParserContext: out of memory\n");
2829 return(NULL);
2830 }
2831 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
2832
Owen Taylor3473f882001-02-23 17:55:21 +00002833 /* Allocate the value stack */
2834 ret->valueTab = (xmlXPathObjectPtr *)
2835 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002836 if (ret->valueTab == NULL) {
2837 xmlFree(ret);
2838 xmlGenericError(xmlGenericErrorContext,
2839 "xmlXPathNewParserContext: out of memory\n");
2840 return(NULL);
2841 }
Owen Taylor3473f882001-02-23 17:55:21 +00002842 ret->valueNr = 0;
2843 ret->valueMax = 10;
2844 ret->value = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002845
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00002846 ret->context = ctxt;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002847 ret->comp = comp;
2848
Owen Taylor3473f882001-02-23 17:55:21 +00002849 return(ret);
2850}
2851
2852/**
2853 * xmlXPathFreeParserContext:
2854 * @ctxt: the context to free
2855 *
2856 * Free up an xmlXPathParserContext
2857 */
2858void
2859xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
2860 if (ctxt->valueTab != NULL) {
Owen Taylor3473f882001-02-23 17:55:21 +00002861 xmlFree(ctxt->valueTab);
2862 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00002863 if (ctxt->comp)
2864 xmlXPathFreeCompExpr(ctxt->comp);
Owen Taylor3473f882001-02-23 17:55:21 +00002865 xmlFree(ctxt);
2866}
2867
2868/************************************************************************
2869 * *
2870 * The implicit core function library *
2871 * *
2872 ************************************************************************/
2873
Owen Taylor3473f882001-02-23 17:55:21 +00002874/**
2875 * xmlXPathCompareNodeSetFloat:
2876 * @ctxt: the XPath Parser context
2877 * @inf: less than (1) or greater than (0)
2878 * @strict: is the comparison strict
2879 * @arg: the node set
2880 * @f: the value
2881 *
2882 * Implement the compare operation between a nodeset and a number
2883 * @ns < @val (1, 1, ...
2884 * @ns <= @val (1, 0, ...
2885 * @ns > @val (0, 1, ...
2886 * @ns >= @val (0, 0, ...
2887 *
2888 * If one object to be compared is a node-set and the other is a number,
2889 * then the comparison will be true if and only if there is a node in the
2890 * node-set such that the result of performing the comparison on the number
2891 * to be compared and on the result of converting the string-value of that
2892 * node to a number using the number function is true.
2893 *
2894 * Returns 0 or 1 depending on the results of the test.
2895 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002896static int
Owen Taylor3473f882001-02-23 17:55:21 +00002897xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
2898 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
2899 int i, ret = 0;
2900 xmlNodeSetPtr ns;
2901 xmlChar *str2;
2902
2903 if ((f == NULL) || (arg == NULL) ||
2904 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2905 xmlXPathFreeObject(arg);
2906 xmlXPathFreeObject(f);
2907 return(0);
2908 }
2909 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002910 if (ns != NULL) {
2911 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002912 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002913 if (str2 != NULL) {
2914 valuePush(ctxt,
2915 xmlXPathNewString(str2));
2916 xmlFree(str2);
2917 xmlXPathNumberFunction(ctxt, 1);
2918 valuePush(ctxt, xmlXPathObjectCopy(f));
2919 ret = xmlXPathCompareValues(ctxt, inf, strict);
2920 if (ret)
2921 break;
2922 }
2923 }
Owen Taylor3473f882001-02-23 17:55:21 +00002924 }
2925 xmlXPathFreeObject(arg);
2926 xmlXPathFreeObject(f);
2927 return(ret);
2928}
2929
2930/**
2931 * xmlXPathCompareNodeSetString:
2932 * @ctxt: the XPath Parser context
2933 * @inf: less than (1) or greater than (0)
2934 * @strict: is the comparison strict
2935 * @arg: the node set
2936 * @s: the value
2937 *
2938 * Implement the compare operation between a nodeset and a string
2939 * @ns < @val (1, 1, ...
2940 * @ns <= @val (1, 0, ...
2941 * @ns > @val (0, 1, ...
2942 * @ns >= @val (0, 0, ...
2943 *
2944 * If one object to be compared is a node-set and the other is a string,
2945 * then the comparison will be true if and only if there is a node in
2946 * the node-set such that the result of performing the comparison on the
2947 * string-value of the node and the other string is true.
2948 *
2949 * Returns 0 or 1 depending on the results of the test.
2950 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002951static int
Owen Taylor3473f882001-02-23 17:55:21 +00002952xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
2953 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
2954 int i, ret = 0;
2955 xmlNodeSetPtr ns;
2956 xmlChar *str2;
2957
2958 if ((s == NULL) || (arg == NULL) ||
2959 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
2960 xmlXPathFreeObject(arg);
2961 xmlXPathFreeObject(s);
2962 return(0);
2963 }
2964 ns = arg->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00002965 if (ns != NULL) {
2966 for (i = 0;i < ns->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002967 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
Daniel Veillard911f49a2001-04-07 15:39:35 +00002968 if (str2 != NULL) {
2969 valuePush(ctxt,
2970 xmlXPathNewString(str2));
2971 xmlFree(str2);
2972 valuePush(ctxt, xmlXPathObjectCopy(s));
2973 ret = xmlXPathCompareValues(ctxt, inf, strict);
2974 if (ret)
2975 break;
2976 }
2977 }
Owen Taylor3473f882001-02-23 17:55:21 +00002978 }
2979 xmlXPathFreeObject(arg);
2980 xmlXPathFreeObject(s);
2981 return(ret);
2982}
2983
2984/**
2985 * xmlXPathCompareNodeSets:
Daniel Veillardba0b8c92001-05-15 09:43:47 +00002986 * @inf: less than (1) or greater than (0)
Owen Taylor3473f882001-02-23 17:55:21 +00002987 * @strict: is the comparison strict
2988 * @arg1: the fist node set object
2989 * @arg2: the second node set object
2990 *
2991 * Implement the compare operation on nodesets:
2992 *
2993 * If both objects to be compared are node-sets, then the comparison
2994 * will be true if and only if there is a node in the first node-set
2995 * and a node in the second node-set such that the result of performing
2996 * the comparison on the string-values of the two nodes is true.
2997 * ....
2998 * When neither object to be compared is a node-set and the operator
2999 * is <=, <, >= or >, then the objects are compared by converting both
3000 * objects to numbers and comparing the numbers according to IEEE 754.
3001 * ....
3002 * The number function converts its argument to a number as follows:
3003 * - a string that consists of optional whitespace followed by an
3004 * optional minus sign followed by a Number followed by whitespace
3005 * is converted to the IEEE 754 number that is nearest (according
3006 * to the IEEE 754 round-to-nearest rule) to the mathematical value
3007 * represented by the string; any other string is converted to NaN
3008 *
3009 * Conclusion all nodes need to be converted first to their string value
3010 * and then the comparison must be done when possible
3011 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003012static int
3013xmlXPathCompareNodeSets(int inf, int strict,
Owen Taylor3473f882001-02-23 17:55:21 +00003014 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3015 int i, j, init = 0;
3016 double val1;
3017 double *values2;
3018 int ret = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003019 xmlNodeSetPtr ns1;
3020 xmlNodeSetPtr ns2;
3021
3022 if ((arg1 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003023 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
3024 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003025 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003026 }
Owen Taylor3473f882001-02-23 17:55:21 +00003027 if ((arg2 == NULL) ||
Daniel Veillard4dd93462001-04-02 15:16:19 +00003028 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
3029 xmlXPathFreeObject(arg1);
3030 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003031 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003032 }
Owen Taylor3473f882001-02-23 17:55:21 +00003033
3034 ns1 = arg1->nodesetval;
3035 ns2 = arg2->nodesetval;
3036
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003037 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003038 xmlXPathFreeObject(arg1);
3039 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003040 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003041 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003042 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003043 xmlXPathFreeObject(arg1);
3044 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003045 return(0);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003046 }
Owen Taylor3473f882001-02-23 17:55:21 +00003047
3048 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
3049 if (values2 == NULL) {
Daniel Veillard4dd93462001-04-02 15:16:19 +00003050 xmlXPathFreeObject(arg1);
3051 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003052 return(0);
3053 }
3054 for (i = 0;i < ns1->nodeNr;i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003055 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00003056 if (isnan(val1))
3057 continue;
3058 for (j = 0;j < ns2->nodeNr;j++) {
3059 if (init == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003060 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
Owen Taylor3473f882001-02-23 17:55:21 +00003061 }
3062 if (isnan(values2[j]))
3063 continue;
3064 if (inf && strict)
3065 ret = (val1 < values2[j]);
3066 else if (inf && !strict)
3067 ret = (val1 <= values2[j]);
3068 else if (!inf && strict)
3069 ret = (val1 > values2[j]);
3070 else if (!inf && !strict)
3071 ret = (val1 >= values2[j]);
3072 if (ret)
3073 break;
3074 }
3075 if (ret)
3076 break;
3077 init = 1;
3078 }
3079 xmlFree(values2);
Daniel Veillard4dd93462001-04-02 15:16:19 +00003080 xmlXPathFreeObject(arg1);
3081 xmlXPathFreeObject(arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003082 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003083}
3084
3085/**
3086 * xmlXPathCompareNodeSetValue:
3087 * @ctxt: the XPath Parser context
3088 * @inf: less than (1) or greater than (0)
3089 * @strict: is the comparison strict
3090 * @arg: the node set
3091 * @val: the value
3092 *
3093 * Implement the compare operation between a nodeset and a value
3094 * @ns < @val (1, 1, ...
3095 * @ns <= @val (1, 0, ...
3096 * @ns > @val (0, 1, ...
3097 * @ns >= @val (0, 0, ...
3098 *
3099 * If one object to be compared is a node-set and the other is a boolean,
3100 * then the comparison will be true if and only if the result of performing
3101 * the comparison on the boolean and on the result of converting
3102 * the node-set to a boolean using the boolean function is true.
3103 *
3104 * Returns 0 or 1 depending on the results of the test.
3105 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003106static int
Owen Taylor3473f882001-02-23 17:55:21 +00003107xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
3108 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
3109 if ((val == NULL) || (arg == NULL) ||
3110 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3111 return(0);
3112
3113 switch(val->type) {
3114 case XPATH_NUMBER:
3115 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
3116 case XPATH_NODESET:
3117 case XPATH_XSLT_TREE:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003118 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
Owen Taylor3473f882001-02-23 17:55:21 +00003119 case XPATH_STRING:
3120 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
3121 case XPATH_BOOLEAN:
3122 valuePush(ctxt, arg);
3123 xmlXPathBooleanFunction(ctxt, 1);
3124 valuePush(ctxt, val);
3125 return(xmlXPathCompareValues(ctxt, inf, strict));
3126 default:
3127 TODO
3128 return(0);
3129 }
3130 return(0);
3131}
3132
3133/**
3134 * xmlXPathEqualNodeSetString
3135 * @arg: the nodeset object argument
3136 * @str: the string to compare to.
3137 *
3138 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3139 * If one object to be compared is a node-set and the other is a string,
3140 * then the comparison will be true if and only if there is a node in
3141 * the node-set such that the result of performing the comparison on the
3142 * string-value of the node and the other string is true.
3143 *
3144 * Returns 0 or 1 depending on the results of the test.
3145 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003146static int
Owen Taylor3473f882001-02-23 17:55:21 +00003147xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
3148 int i;
3149 xmlNodeSetPtr ns;
3150 xmlChar *str2;
3151
3152 if ((str == NULL) || (arg == NULL) ||
3153 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3154 return(0);
3155 ns = arg->nodesetval;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00003156 if (ns == NULL)
3157 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003158 if (ns->nodeNr <= 0)
3159 return(0);
3160 for (i = 0;i < ns->nodeNr;i++) {
3161 str2 = xmlNodeGetContent(ns->nodeTab[i]);
3162 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
3163 xmlFree(str2);
3164 return(1);
3165 }
3166 if (str2 != NULL)
3167 xmlFree(str2);
3168 }
3169 return(0);
3170}
3171
3172/**
3173 * xmlXPathEqualNodeSetFloat
3174 * @arg: the nodeset object argument
3175 * @f: the float to compare to
3176 *
3177 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3178 * If one object to be compared is a node-set and the other is a number,
3179 * then the comparison will be true if and only if there is a node in
3180 * the node-set such that the result of performing the comparison on the
3181 * number to be compared and on the result of converting the string-value
3182 * of that node to a number using the number function is true.
3183 *
3184 * Returns 0 or 1 depending on the results of the test.
3185 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003186static int
Owen Taylor3473f882001-02-23 17:55:21 +00003187xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
3188 char buf[100] = "";
3189
3190 if ((arg == NULL) ||
3191 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
3192 return(0);
3193
Bjorn Reesee1dc0112001-03-03 12:09:03 +00003194 xmlXPathFormatNumber(f, buf, sizeof(buf));
Owen Taylor3473f882001-02-23 17:55:21 +00003195 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
3196}
3197
3198
3199/**
3200 * xmlXPathEqualNodeSets
3201 * @arg1: first nodeset object argument
3202 * @arg2: second nodeset object argument
3203 *
3204 * Implement the equal operation on XPath nodesets: @arg1 == @arg2
3205 * If both objects to be compared are node-sets, then the comparison
3206 * will be true if and only if there is a node in the first node-set and
3207 * a node in the second node-set such that the result of performing the
3208 * comparison on the string-values of the two nodes is true.
3209 *
3210 * (needless to say, this is a costly operation)
3211 *
3212 * Returns 0 or 1 depending on the results of the test.
3213 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003214static int
Owen Taylor3473f882001-02-23 17:55:21 +00003215xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
3216 int i, j;
3217 xmlChar **values1;
3218 xmlChar **values2;
3219 int ret = 0;
3220 xmlNodeSetPtr ns1;
3221 xmlNodeSetPtr ns2;
3222
3223 if ((arg1 == NULL) ||
3224 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
3225 return(0);
3226 if ((arg2 == NULL) ||
3227 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
3228 return(0);
3229
3230 ns1 = arg1->nodesetval;
3231 ns2 = arg2->nodesetval;
3232
Daniel Veillard911f49a2001-04-07 15:39:35 +00003233 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003234 return(0);
Daniel Veillard911f49a2001-04-07 15:39:35 +00003235 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
Owen Taylor3473f882001-02-23 17:55:21 +00003236 return(0);
3237
3238 /*
3239 * check if there is a node pertaining to both sets
3240 */
3241 for (i = 0;i < ns1->nodeNr;i++)
3242 for (j = 0;j < ns2->nodeNr;j++)
3243 if (ns1->nodeTab[i] == ns2->nodeTab[j])
3244 return(1);
3245
3246 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
3247 if (values1 == NULL)
3248 return(0);
3249 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
3250 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
3251 if (values2 == NULL) {
3252 xmlFree(values1);
3253 return(0);
3254 }
3255 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
3256 for (i = 0;i < ns1->nodeNr;i++) {
3257 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
3258 for (j = 0;j < ns2->nodeNr;j++) {
3259 if (i == 0)
3260 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
3261 ret = xmlStrEqual(values1[i], values2[j]);
3262 if (ret)
3263 break;
3264 }
3265 if (ret)
3266 break;
3267 }
3268 for (i = 0;i < ns1->nodeNr;i++)
3269 if (values1[i] != NULL)
3270 xmlFree(values1[i]);
3271 for (j = 0;j < ns2->nodeNr;j++)
3272 if (values2[j] != NULL)
3273 xmlFree(values2[j]);
3274 xmlFree(values1);
3275 xmlFree(values2);
3276 return(ret);
3277}
3278
3279/**
3280 * xmlXPathEqualValues:
3281 * @ctxt: the XPath Parser context
3282 *
3283 * Implement the equal operation on XPath objects content: @arg1 == @arg2
3284 *
3285 * Returns 0 or 1 depending on the results of the test.
3286 */
3287int
3288xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
3289 xmlXPathObjectPtr arg1, arg2;
3290 int ret = 0;
3291
3292 arg1 = valuePop(ctxt);
3293 if (arg1 == NULL)
3294 XP_ERROR0(XPATH_INVALID_OPERAND);
3295
3296 arg2 = valuePop(ctxt);
3297 if (arg2 == NULL) {
3298 xmlXPathFreeObject(arg1);
3299 XP_ERROR0(XPATH_INVALID_OPERAND);
3300 }
3301
3302 if (arg1 == arg2) {
3303#ifdef DEBUG_EXPR
3304 xmlGenericError(xmlGenericErrorContext,
3305 "Equal: by pointer\n");
3306#endif
3307 return(1);
3308 }
3309
3310 switch (arg1->type) {
3311 case XPATH_UNDEFINED:
3312#ifdef DEBUG_EXPR
3313 xmlGenericError(xmlGenericErrorContext,
3314 "Equal: undefined\n");
3315#endif
3316 break;
3317 case XPATH_XSLT_TREE:
3318 case XPATH_NODESET:
3319 switch (arg2->type) {
3320 case XPATH_UNDEFINED:
3321#ifdef DEBUG_EXPR
3322 xmlGenericError(xmlGenericErrorContext,
3323 "Equal: undefined\n");
3324#endif
3325 break;
3326 case XPATH_XSLT_TREE:
3327 case XPATH_NODESET:
3328 ret = xmlXPathEqualNodeSets(arg1, arg2);
3329 break;
3330 case XPATH_BOOLEAN:
3331 if ((arg1->nodesetval == NULL) ||
3332 (arg1->nodesetval->nodeNr == 0)) ret = 0;
3333 else
3334 ret = 1;
3335 ret = (ret == arg2->boolval);
3336 break;
3337 case XPATH_NUMBER:
3338 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
3339 break;
3340 case XPATH_STRING:
3341 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
3342 break;
3343 case XPATH_USERS:
3344 case XPATH_POINT:
3345 case XPATH_RANGE:
3346 case XPATH_LOCATIONSET:
3347 TODO
3348 break;
3349 }
3350 break;
3351 case XPATH_BOOLEAN:
3352 switch (arg2->type) {
3353 case XPATH_UNDEFINED:
3354#ifdef DEBUG_EXPR
3355 xmlGenericError(xmlGenericErrorContext,
3356 "Equal: undefined\n");
3357#endif
3358 break;
3359 case XPATH_NODESET:
3360 case XPATH_XSLT_TREE:
3361 if ((arg2->nodesetval == NULL) ||
3362 (arg2->nodesetval->nodeNr == 0)) ret = 0;
3363 else
3364 ret = 1;
3365 break;
3366 case XPATH_BOOLEAN:
3367#ifdef DEBUG_EXPR
3368 xmlGenericError(xmlGenericErrorContext,
3369 "Equal: %d boolean %d \n",
3370 arg1->boolval, arg2->boolval);
3371#endif
3372 ret = (arg1->boolval == arg2->boolval);
3373 break;
3374 case XPATH_NUMBER:
3375 if (arg2->floatval) ret = 1;
3376 else ret = 0;
3377 ret = (arg1->boolval == ret);
3378 break;
3379 case XPATH_STRING:
3380 if ((arg2->stringval == NULL) ||
3381 (arg2->stringval[0] == 0)) ret = 0;
3382 else
3383 ret = 1;
3384 ret = (arg1->boolval == ret);
3385 break;
3386 case XPATH_USERS:
3387 case XPATH_POINT:
3388 case XPATH_RANGE:
3389 case XPATH_LOCATIONSET:
3390 TODO
3391 break;
3392 }
3393 break;
3394 case XPATH_NUMBER:
3395 switch (arg2->type) {
3396 case XPATH_UNDEFINED:
3397#ifdef DEBUG_EXPR
3398 xmlGenericError(xmlGenericErrorContext,
3399 "Equal: undefined\n");
3400#endif
3401 break;
3402 case XPATH_NODESET:
3403 case XPATH_XSLT_TREE:
3404 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
3405 break;
3406 case XPATH_BOOLEAN:
3407 if (arg1->floatval) ret = 1;
3408 else ret = 0;
3409 ret = (arg2->boolval == ret);
3410 break;
3411 case XPATH_STRING:
3412 valuePush(ctxt, arg2);
3413 xmlXPathNumberFunction(ctxt, 1);
3414 arg2 = valuePop(ctxt);
3415 /* no break on purpose */
3416 case XPATH_NUMBER:
3417 ret = (arg1->floatval == arg2->floatval);
3418 break;
3419 case XPATH_USERS:
3420 case XPATH_POINT:
3421 case XPATH_RANGE:
3422 case XPATH_LOCATIONSET:
3423 TODO
3424 break;
3425 }
3426 break;
3427 case XPATH_STRING:
3428 switch (arg2->type) {
3429 case XPATH_UNDEFINED:
3430#ifdef DEBUG_EXPR
3431 xmlGenericError(xmlGenericErrorContext,
3432 "Equal: undefined\n");
3433#endif
3434 break;
3435 case XPATH_NODESET:
3436 case XPATH_XSLT_TREE:
3437 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
3438 break;
3439 case XPATH_BOOLEAN:
3440 if ((arg1->stringval == NULL) ||
3441 (arg1->stringval[0] == 0)) ret = 0;
3442 else
3443 ret = 1;
3444 ret = (arg2->boolval == ret);
3445 break;
3446 case XPATH_STRING:
3447 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
3448 break;
3449 case XPATH_NUMBER:
3450 valuePush(ctxt, arg1);
3451 xmlXPathNumberFunction(ctxt, 1);
3452 arg1 = valuePop(ctxt);
3453 ret = (arg1->floatval == arg2->floatval);
3454 break;
3455 case XPATH_USERS:
3456 case XPATH_POINT:
3457 case XPATH_RANGE:
3458 case XPATH_LOCATIONSET:
3459 TODO
3460 break;
3461 }
3462 break;
3463 case XPATH_USERS:
3464 case XPATH_POINT:
3465 case XPATH_RANGE:
3466 case XPATH_LOCATIONSET:
3467 TODO
3468 break;
3469 }
3470 xmlXPathFreeObject(arg1);
3471 xmlXPathFreeObject(arg2);
3472 return(ret);
3473}
3474
3475
3476/**
3477 * xmlXPathCompareValues:
3478 * @ctxt: the XPath Parser context
3479 * @inf: less than (1) or greater than (0)
3480 * @strict: is the comparison strict
3481 *
3482 * Implement the compare operation on XPath objects:
3483 * @arg1 < @arg2 (1, 1, ...
3484 * @arg1 <= @arg2 (1, 0, ...
3485 * @arg1 > @arg2 (0, 1, ...
3486 * @arg1 >= @arg2 (0, 0, ...
3487 *
3488 * When neither object to be compared is a node-set and the operator is
3489 * <=, <, >=, >, then the objects are compared by converted both objects
3490 * to numbers and comparing the numbers according to IEEE 754. The <
3491 * comparison will be true if and only if the first number is less than the
3492 * second number. The <= comparison will be true if and only if the first
3493 * number is less than or equal to the second number. The > comparison
3494 * will be true if and only if the first number is greater than the second
3495 * number. The >= comparison will be true if and only if the first number
3496 * is greater than or equal to the second number.
3497 *
3498 * Returns 1 if the comparaison succeeded, 0 if it failed
3499 */
3500int
3501xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
3502 int ret = 0;
3503 xmlXPathObjectPtr arg1, arg2;
3504
3505 arg2 = valuePop(ctxt);
3506 if (arg2 == NULL) {
3507 XP_ERROR0(XPATH_INVALID_OPERAND);
3508 }
3509
3510 arg1 = valuePop(ctxt);
3511 if (arg1 == NULL) {
3512 xmlXPathFreeObject(arg2);
3513 XP_ERROR0(XPATH_INVALID_OPERAND);
3514 }
3515
3516 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
3517 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003518 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003519 } else {
3520 if (arg1->type == XPATH_NODESET) {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003521 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
3522 arg1, arg2);
Owen Taylor3473f882001-02-23 17:55:21 +00003523 } else {
Daniel Veillard4af6b6e2001-03-06 08:33:38 +00003524 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
3525 arg2, arg1);
Owen Taylor3473f882001-02-23 17:55:21 +00003526 }
3527 }
3528 return(ret);
3529 }
3530
3531 if (arg1->type != XPATH_NUMBER) {
3532 valuePush(ctxt, arg1);
3533 xmlXPathNumberFunction(ctxt, 1);
3534 arg1 = valuePop(ctxt);
3535 }
3536 if (arg1->type != XPATH_NUMBER) {
3537 xmlXPathFreeObject(arg1);
3538 xmlXPathFreeObject(arg2);
3539 XP_ERROR0(XPATH_INVALID_OPERAND);
3540 }
3541 if (arg2->type != XPATH_NUMBER) {
3542 valuePush(ctxt, arg2);
3543 xmlXPathNumberFunction(ctxt, 1);
3544 arg2 = valuePop(ctxt);
3545 }
3546 if (arg2->type != XPATH_NUMBER) {
3547 xmlXPathFreeObject(arg1);
3548 xmlXPathFreeObject(arg2);
3549 XP_ERROR0(XPATH_INVALID_OPERAND);
3550 }
3551 /*
3552 * Add tests for infinity and nan
3553 * => feedback on 3.4 for Inf and NaN
3554 */
3555 if (inf && strict)
3556 ret = (arg1->floatval < arg2->floatval);
3557 else if (inf && !strict)
3558 ret = (arg1->floatval <= arg2->floatval);
3559 else if (!inf && strict)
3560 ret = (arg1->floatval > arg2->floatval);
3561 else if (!inf && !strict)
3562 ret = (arg1->floatval >= arg2->floatval);
3563 xmlXPathFreeObject(arg1);
3564 xmlXPathFreeObject(arg2);
3565 return(ret);
3566}
3567
3568/**
3569 * xmlXPathValueFlipSign:
3570 * @ctxt: the XPath Parser context
3571 *
3572 * Implement the unary - operation on an XPath object
3573 * The numeric operators convert their operands to numbers as if
3574 * by calling the number function.
3575 */
3576void
3577xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003578 CAST_TO_NUMBER;
3579 CHECK_TYPE(XPATH_NUMBER);
3580 ctxt->value->floatval = - ctxt->value->floatval;
Owen Taylor3473f882001-02-23 17:55:21 +00003581}
3582
3583/**
3584 * xmlXPathAddValues:
3585 * @ctxt: the XPath Parser context
3586 *
3587 * Implement the add operation on XPath objects:
3588 * The numeric operators convert their operands to numbers as if
3589 * by calling the number function.
3590 */
3591void
3592xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
3593 xmlXPathObjectPtr arg;
3594 double val;
3595
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003596 arg = valuePop(ctxt);
3597 if (arg == NULL)
3598 XP_ERROR(XPATH_INVALID_OPERAND);
3599 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003600 xmlXPathFreeObject(arg);
3601
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003602 CAST_TO_NUMBER;
3603 CHECK_TYPE(XPATH_NUMBER);
3604 ctxt->value->floatval += val;
Owen Taylor3473f882001-02-23 17:55:21 +00003605}
3606
3607/**
3608 * xmlXPathSubValues:
3609 * @ctxt: the XPath Parser context
3610 *
3611 * Implement the substraction operation on XPath objects:
3612 * The numeric operators convert their operands to numbers as if
3613 * by calling the number function.
3614 */
3615void
3616xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
3617 xmlXPathObjectPtr arg;
3618 double val;
3619
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003620 arg = valuePop(ctxt);
3621 if (arg == NULL)
3622 XP_ERROR(XPATH_INVALID_OPERAND);
3623 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003624 xmlXPathFreeObject(arg);
3625
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003626 CAST_TO_NUMBER;
3627 CHECK_TYPE(XPATH_NUMBER);
3628 ctxt->value->floatval -= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003629}
3630
3631/**
3632 * xmlXPathMultValues:
3633 * @ctxt: the XPath Parser context
3634 *
3635 * Implement the multiply operation on XPath objects:
3636 * The numeric operators convert their operands to numbers as if
3637 * by calling the number function.
3638 */
3639void
3640xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
3641 xmlXPathObjectPtr arg;
3642 double val;
3643
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003644 arg = valuePop(ctxt);
3645 if (arg == NULL)
3646 XP_ERROR(XPATH_INVALID_OPERAND);
3647 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003648 xmlXPathFreeObject(arg);
3649
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003650 CAST_TO_NUMBER;
3651 CHECK_TYPE(XPATH_NUMBER);
3652 ctxt->value->floatval *= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003653}
3654
3655/**
3656 * xmlXPathDivValues:
3657 * @ctxt: the XPath Parser context
3658 *
3659 * Implement the div operation on XPath objects @arg1 / @arg2:
3660 * The numeric operators convert their operands to numbers as if
3661 * by calling the number function.
3662 */
3663void
3664xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
3665 xmlXPathObjectPtr arg;
3666 double val;
3667
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003668 arg = valuePop(ctxt);
3669 if (arg == NULL)
3670 XP_ERROR(XPATH_INVALID_OPERAND);
3671 val = xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003672 xmlXPathFreeObject(arg);
3673
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003674 CAST_TO_NUMBER;
3675 CHECK_TYPE(XPATH_NUMBER);
3676 ctxt->value->floatval /= val;
Owen Taylor3473f882001-02-23 17:55:21 +00003677}
3678
3679/**
3680 * xmlXPathModValues:
3681 * @ctxt: the XPath Parser context
3682 *
3683 * Implement the mod operation on XPath objects: @arg1 / @arg2
3684 * The numeric operators convert their operands to numbers as if
3685 * by calling the number function.
3686 */
3687void
3688xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
3689 xmlXPathObjectPtr arg;
3690 int arg1, arg2;
3691
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003692 arg = valuePop(ctxt);
3693 if (arg == NULL)
3694 XP_ERROR(XPATH_INVALID_OPERAND);
3695 arg2 = (int) xmlXPathCastToNumber(arg);
Owen Taylor3473f882001-02-23 17:55:21 +00003696 xmlXPathFreeObject(arg);
3697
Daniel Veillardba0b8c92001-05-15 09:43:47 +00003698 CAST_TO_NUMBER;
3699 CHECK_TYPE(XPATH_NUMBER);
3700 arg1 = (int) ctxt->value->floatval;
3701 ctxt->value->floatval = arg1 % arg2;
Owen Taylor3473f882001-02-23 17:55:21 +00003702}
3703
3704/************************************************************************
3705 * *
3706 * The traversal functions *
3707 * *
3708 ************************************************************************/
3709
Owen Taylor3473f882001-02-23 17:55:21 +00003710/*
3711 * A traversal function enumerates nodes along an axis.
3712 * Initially it must be called with NULL, and it indicates
3713 * termination on the axis by returning NULL.
3714 */
3715typedef xmlNodePtr (*xmlXPathTraversalFunction)
3716 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
3717
3718/**
3719 * xmlXPathNextSelf:
3720 * @ctxt: the XPath Parser context
3721 * @cur: the current node in the traversal
3722 *
3723 * Traversal function for the "self" direction
3724 * The self axis contains just the context node itself
3725 *
3726 * Returns the next element following that axis
3727 */
3728xmlNodePtr
3729xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3730 if (cur == NULL)
3731 return(ctxt->context->node);
3732 return(NULL);
3733}
3734
3735/**
3736 * xmlXPathNextChild:
3737 * @ctxt: the XPath Parser context
3738 * @cur: the current node in the traversal
3739 *
3740 * Traversal function for the "child" direction
3741 * The child axis contains the children of the context node in document order.
3742 *
3743 * Returns the next element following that axis
3744 */
3745xmlNodePtr
3746xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3747 if (cur == NULL) {
3748 if (ctxt->context->node == NULL) return(NULL);
3749 switch (ctxt->context->node->type) {
3750 case XML_ELEMENT_NODE:
3751 case XML_TEXT_NODE:
3752 case XML_CDATA_SECTION_NODE:
3753 case XML_ENTITY_REF_NODE:
3754 case XML_ENTITY_NODE:
3755 case XML_PI_NODE:
3756 case XML_COMMENT_NODE:
3757 case XML_NOTATION_NODE:
3758 case XML_DTD_NODE:
3759 return(ctxt->context->node->children);
3760 case XML_DOCUMENT_NODE:
3761 case XML_DOCUMENT_TYPE_NODE:
3762 case XML_DOCUMENT_FRAG_NODE:
3763 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003764#ifdef LIBXML_DOCB_ENABLED
3765 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003766#endif
3767 return(((xmlDocPtr) ctxt->context->node)->children);
3768 case XML_ELEMENT_DECL:
3769 case XML_ATTRIBUTE_DECL:
3770 case XML_ENTITY_DECL:
3771 case XML_ATTRIBUTE_NODE:
3772 case XML_NAMESPACE_DECL:
3773 case XML_XINCLUDE_START:
3774 case XML_XINCLUDE_END:
3775 return(NULL);
3776 }
3777 return(NULL);
3778 }
3779 if ((cur->type == XML_DOCUMENT_NODE) ||
3780 (cur->type == XML_HTML_DOCUMENT_NODE))
3781 return(NULL);
3782 return(cur->next);
3783}
3784
3785/**
3786 * xmlXPathNextDescendant:
3787 * @ctxt: the XPath Parser context
3788 * @cur: the current node in the traversal
3789 *
3790 * Traversal function for the "descendant" direction
3791 * the descendant axis contains the descendants of the context node in document
3792 * order; a descendant is a child or a child of a child and so on.
3793 *
3794 * Returns the next element following that axis
3795 */
3796xmlNodePtr
3797xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3798 if (cur == NULL) {
3799 if (ctxt->context->node == NULL)
3800 return(NULL);
3801 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3802 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3803 return(NULL);
3804
3805 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
3806 return(ctxt->context->doc->children);
3807 return(ctxt->context->node->children);
3808 }
3809
3810 if (cur->children != NULL)
3811 {
3812 if (cur->children->type != XML_ENTITY_DECL)
3813 return(cur->children);
3814 }
3815 if (cur->next != NULL) return(cur->next);
3816
3817 do {
3818 cur = cur->parent;
3819 if (cur == NULL) return(NULL);
3820 if (cur == ctxt->context->node) return(NULL);
3821 if (cur->next != NULL) {
3822 cur = cur->next;
3823 return(cur);
3824 }
3825 } while (cur != NULL);
3826 return(cur);
3827}
3828
3829/**
3830 * xmlXPathNextDescendantOrSelf:
3831 * @ctxt: the XPath Parser context
3832 * @cur: the current node in the traversal
3833 *
3834 * Traversal function for the "descendant-or-self" direction
3835 * the descendant-or-self axis contains the context node and the descendants
3836 * of the context node in document order; thus the context node is the first
3837 * node on the axis, and the first child of the context node is the second node
3838 * on the axis
3839 *
3840 * Returns the next element following that axis
3841 */
3842xmlNodePtr
3843xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3844 if (cur == NULL) {
3845 if (ctxt->context->node == NULL)
3846 return(NULL);
3847 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
3848 (ctxt->context->node->type == XML_NAMESPACE_DECL))
3849 return(NULL);
3850 return(ctxt->context->node);
3851 }
3852
3853 return(xmlXPathNextDescendant(ctxt, cur));
3854}
3855
3856/**
3857 * xmlXPathNextParent:
3858 * @ctxt: the XPath Parser context
3859 * @cur: the current node in the traversal
3860 *
3861 * Traversal function for the "parent" direction
3862 * The parent axis contains the parent of the context node, if there is one.
3863 *
3864 * Returns the next element following that axis
3865 */
3866xmlNodePtr
3867xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3868 /*
3869 * the parent of an attribute or namespace node is the element
3870 * to which the attribute or namespace node is attached
3871 * Namespace handling !!!
3872 */
3873 if (cur == NULL) {
3874 if (ctxt->context->node == NULL) return(NULL);
3875 switch (ctxt->context->node->type) {
3876 case XML_ELEMENT_NODE:
3877 case XML_TEXT_NODE:
3878 case XML_CDATA_SECTION_NODE:
3879 case XML_ENTITY_REF_NODE:
3880 case XML_ENTITY_NODE:
3881 case XML_PI_NODE:
3882 case XML_COMMENT_NODE:
3883 case XML_NOTATION_NODE:
3884 case XML_DTD_NODE:
3885 case XML_ELEMENT_DECL:
3886 case XML_ATTRIBUTE_DECL:
3887 case XML_XINCLUDE_START:
3888 case XML_XINCLUDE_END:
3889 case XML_ENTITY_DECL:
3890 if (ctxt->context->node->parent == NULL)
3891 return((xmlNodePtr) ctxt->context->doc);
3892 return(ctxt->context->node->parent);
3893 case XML_ATTRIBUTE_NODE: {
3894 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
3895
3896 return(att->parent);
3897 }
3898 case XML_DOCUMENT_NODE:
3899 case XML_DOCUMENT_TYPE_NODE:
3900 case XML_DOCUMENT_FRAG_NODE:
3901 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003902#ifdef LIBXML_DOCB_ENABLED
3903 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003904#endif
3905 return(NULL);
3906 case XML_NAMESPACE_DECL:
3907 /*
3908 * TODO !!! may require extending struct _xmlNs with
3909 * parent field
3910 * C.f. Infoset case...
3911 */
3912 return(NULL);
3913 }
3914 }
3915 return(NULL);
3916}
3917
3918/**
3919 * xmlXPathNextAncestor:
3920 * @ctxt: the XPath Parser context
3921 * @cur: the current node in the traversal
3922 *
3923 * Traversal function for the "ancestor" direction
3924 * the ancestor axis contains the ancestors of the context node; the ancestors
3925 * of the context node consist of the parent of context node and the parent's
3926 * parent and so on; the nodes are ordered in reverse document order; thus the
3927 * parent is the first node on the axis, and the parent's parent is the second
3928 * node on the axis
3929 *
3930 * Returns the next element following that axis
3931 */
3932xmlNodePtr
3933xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
3934 /*
3935 * the parent of an attribute or namespace node is the element
3936 * to which the attribute or namespace node is attached
3937 * !!!!!!!!!!!!!
3938 */
3939 if (cur == NULL) {
3940 if (ctxt->context->node == NULL) return(NULL);
3941 switch (ctxt->context->node->type) {
3942 case XML_ELEMENT_NODE:
3943 case XML_TEXT_NODE:
3944 case XML_CDATA_SECTION_NODE:
3945 case XML_ENTITY_REF_NODE:
3946 case XML_ENTITY_NODE:
3947 case XML_PI_NODE:
3948 case XML_COMMENT_NODE:
3949 case XML_DTD_NODE:
3950 case XML_ELEMENT_DECL:
3951 case XML_ATTRIBUTE_DECL:
3952 case XML_ENTITY_DECL:
3953 case XML_NOTATION_NODE:
3954 case XML_XINCLUDE_START:
3955 case XML_XINCLUDE_END:
3956 if (ctxt->context->node->parent == NULL)
3957 return((xmlNodePtr) ctxt->context->doc);
3958 return(ctxt->context->node->parent);
3959 case XML_ATTRIBUTE_NODE: {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003960 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
Owen Taylor3473f882001-02-23 17:55:21 +00003961
Daniel Veillard56a4cb82001-03-24 17:00:36 +00003962 return(tmp->parent);
Owen Taylor3473f882001-02-23 17:55:21 +00003963 }
3964 case XML_DOCUMENT_NODE:
3965 case XML_DOCUMENT_TYPE_NODE:
3966 case XML_DOCUMENT_FRAG_NODE:
3967 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00003968#ifdef LIBXML_DOCB_ENABLED
3969 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00003970#endif
3971 return(NULL);
3972 case XML_NAMESPACE_DECL:
3973 /*
3974 * TODO !!! may require extending struct _xmlNs with
3975 * parent field
3976 * C.f. Infoset case...
3977 */
3978 return(NULL);
3979 }
3980 return(NULL);
3981 }
3982 if (cur == ctxt->context->doc->children)
3983 return((xmlNodePtr) ctxt->context->doc);
3984 if (cur == (xmlNodePtr) ctxt->context->doc)
3985 return(NULL);
3986 switch (cur->type) {
3987 case XML_ELEMENT_NODE:
3988 case XML_TEXT_NODE:
3989 case XML_CDATA_SECTION_NODE:
3990 case XML_ENTITY_REF_NODE:
3991 case XML_ENTITY_NODE:
3992 case XML_PI_NODE:
3993 case XML_COMMENT_NODE:
3994 case XML_NOTATION_NODE:
3995 case XML_DTD_NODE:
3996 case XML_ELEMENT_DECL:
3997 case XML_ATTRIBUTE_DECL:
3998 case XML_ENTITY_DECL:
3999 case XML_XINCLUDE_START:
4000 case XML_XINCLUDE_END:
4001 return(cur->parent);
4002 case XML_ATTRIBUTE_NODE: {
4003 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
4004
4005 return(att->parent);
4006 }
4007 case XML_DOCUMENT_NODE:
4008 case XML_DOCUMENT_TYPE_NODE:
4009 case XML_DOCUMENT_FRAG_NODE:
4010 case XML_HTML_DOCUMENT_NODE:
Daniel Veillardeae522a2001-04-23 13:41:34 +00004011#ifdef LIBXML_DOCB_ENABLED
4012 case XML_DOCB_DOCUMENT_NODE:
Owen Taylor3473f882001-02-23 17:55:21 +00004013#endif
4014 return(NULL);
4015 case XML_NAMESPACE_DECL:
4016 /*
4017 * TODO !!! may require extending struct _xmlNs with
4018 * parent field
4019 * C.f. Infoset case...
4020 */
4021 return(NULL);
4022 }
4023 return(NULL);
4024}
4025
4026/**
4027 * xmlXPathNextAncestorOrSelf:
4028 * @ctxt: the XPath Parser context
4029 * @cur: the current node in the traversal
4030 *
4031 * Traversal function for the "ancestor-or-self" direction
4032 * he ancestor-or-self axis contains the context node and ancestors of
4033 * the context node in reverse document order; thus the context node is
4034 * the first node on the axis, and the context node's parent the second;
4035 * parent here is defined the same as with the parent axis.
4036 *
4037 * Returns the next element following that axis
4038 */
4039xmlNodePtr
4040xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4041 if (cur == NULL)
4042 return(ctxt->context->node);
4043 return(xmlXPathNextAncestor(ctxt, cur));
4044}
4045
4046/**
4047 * xmlXPathNextFollowingSibling:
4048 * @ctxt: the XPath Parser context
4049 * @cur: the current node in the traversal
4050 *
4051 * Traversal function for the "following-sibling" direction
4052 * The following-sibling axis contains the following siblings of the context
4053 * node in document order.
4054 *
4055 * Returns the next element following that axis
4056 */
4057xmlNodePtr
4058xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4059 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4060 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4061 return(NULL);
4062 if (cur == (xmlNodePtr) ctxt->context->doc)
4063 return(NULL);
4064 if (cur == NULL)
4065 return(ctxt->context->node->next);
4066 return(cur->next);
4067}
4068
4069/**
4070 * xmlXPathNextPrecedingSibling:
4071 * @ctxt: the XPath Parser context
4072 * @cur: the current node in the traversal
4073 *
4074 * Traversal function for the "preceding-sibling" direction
4075 * The preceding-sibling axis contains the preceding siblings of the context
4076 * node in reverse document order; the first preceding sibling is first on the
4077 * axis; the sibling preceding that node is the second on the axis and so on.
4078 *
4079 * Returns the next element following that axis
4080 */
4081xmlNodePtr
4082xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4083 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
4084 (ctxt->context->node->type == XML_NAMESPACE_DECL))
4085 return(NULL);
4086 if (cur == (xmlNodePtr) ctxt->context->doc)
4087 return(NULL);
4088 if (cur == NULL)
4089 return(ctxt->context->node->prev);
4090 return(cur->prev);
4091}
4092
4093/**
4094 * xmlXPathNextFollowing:
4095 * @ctxt: the XPath Parser context
4096 * @cur: the current node in the traversal
4097 *
4098 * Traversal function for the "following" direction
4099 * The following axis contains all nodes in the same document as the context
4100 * node that are after the context node in document order, excluding any
4101 * descendants and excluding attribute nodes and namespace nodes; the nodes
4102 * are ordered in document order
4103 *
4104 * Returns the next element following that axis
4105 */
4106xmlNodePtr
4107xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4108 if (cur != NULL && cur->children != NULL)
4109 return cur->children ;
4110 if (cur == NULL) cur = ctxt->context->node;
4111 if (cur == NULL) return(NULL) ; /* ERROR */
4112 if (cur->next != NULL) return(cur->next) ;
4113 do {
4114 cur = cur->parent;
4115 if (cur == NULL) return(NULL);
4116 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
4117 if (cur->next != NULL) return(cur->next);
4118 } while (cur != NULL);
4119 return(cur);
4120}
4121
4122/*
4123 * xmlXPathIsAncestor:
4124 * @ancestor: the ancestor node
4125 * @node: the current node
4126 *
4127 * Check that @ancestor is a @node's ancestor
4128 *
4129 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
4130 */
4131static int
4132xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
4133 if ((ancestor == NULL) || (node == NULL)) return(0);
4134 /* nodes need to be in the same document */
4135 if (ancestor->doc != node->doc) return(0);
4136 /* avoid searching if ancestor or node is the root node */
4137 if (ancestor == (xmlNodePtr) node->doc) return(1);
4138 if (node == (xmlNodePtr) ancestor->doc) return(0);
4139 while (node->parent != NULL) {
4140 if (node->parent == ancestor)
4141 return(1);
4142 node = node->parent;
4143 }
4144 return(0);
4145}
4146
4147/**
4148 * xmlXPathNextPreceding:
4149 * @ctxt: the XPath Parser context
4150 * @cur: the current node in the traversal
4151 *
4152 * Traversal function for the "preceding" direction
4153 * the preceding axis contains all nodes in the same document as the context
4154 * node that are before the context node in document order, excluding any
4155 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
4156 * ordered in reverse document order
4157 *
4158 * Returns the next element following that axis
4159 */
4160xmlNodePtr
4161xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4162 if (cur == NULL)
4163 cur = ctxt->context->node ;
4164 do {
4165 if (cur->prev != NULL) {
4166 for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
4167 ;
4168 return(cur) ;
4169 }
4170
4171 cur = cur->parent;
4172 if (cur == NULL) return(NULL);
4173 if (cur == ctxt->context->doc->children) return(NULL);
4174 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
4175 return(cur);
4176}
4177
4178/**
4179 * xmlXPathNextNamespace:
4180 * @ctxt: the XPath Parser context
4181 * @cur: the current attribute in the traversal
4182 *
4183 * Traversal function for the "namespace" direction
4184 * the namespace axis contains the namespace nodes of the context node;
4185 * the order of nodes on this axis is implementation-defined; the axis will
4186 * be empty unless the context node is an element
4187 *
4188 * Returns the next element following that axis
4189 */
4190xmlNodePtr
4191xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
4192 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
4193 if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
4194 if (ctxt->context->namespaces != NULL)
4195 xmlFree(ctxt->context->namespaces);
4196 ctxt->context->namespaces =
4197 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
4198 if (ctxt->context->namespaces == NULL) return(NULL);
4199 ctxt->context->nsNr = 0;
4200 }
4201 return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
4202}
4203
4204/**
4205 * xmlXPathNextAttribute:
4206 * @ctxt: the XPath Parser context
4207 * @cur: the current attribute in the traversal
4208 *
4209 * Traversal function for the "attribute" direction
4210 * TODO: support DTD inherited default attributes
4211 *
4212 * Returns the next element following that axis
4213 */
4214xmlNodePtr
4215xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
Daniel Veillarde470df72001-04-18 21:41:07 +00004216 if (ctxt->context->node == NULL)
4217 return(NULL);
4218 if (ctxt->context->node->type != XML_ELEMENT_NODE)
4219 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004220 if (cur == NULL) {
4221 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
4222 return(NULL);
4223 return((xmlNodePtr)ctxt->context->node->properties);
4224 }
4225 return((xmlNodePtr)cur->next);
4226}
4227
4228/************************************************************************
4229 * *
4230 * NodeTest Functions *
4231 * *
4232 ************************************************************************/
4233
Owen Taylor3473f882001-02-23 17:55:21 +00004234#define IS_FUNCTION 200
4235
Owen Taylor3473f882001-02-23 17:55:21 +00004236
4237/************************************************************************
4238 * *
4239 * Implicit tree core function library *
4240 * *
4241 ************************************************************************/
4242
4243/**
4244 * xmlXPathRoot:
4245 * @ctxt: the XPath Parser context
4246 *
4247 * Initialize the context to the root of the document
4248 */
4249void
4250xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
4251 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
4252 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4253}
4254
4255/************************************************************************
4256 * *
4257 * The explicit core function library *
4258 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
4259 * *
4260 ************************************************************************/
4261
4262
4263/**
4264 * xmlXPathLastFunction:
4265 * @ctxt: the XPath Parser context
4266 * @nargs: the number of arguments
4267 *
4268 * Implement the last() XPath function
4269 * number last()
4270 * The last function returns the number of nodes in the context node list.
4271 */
4272void
4273xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4274 CHECK_ARITY(0);
4275 if (ctxt->context->contextSize >= 0) {
4276 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
4277#ifdef DEBUG_EXPR
4278 xmlGenericError(xmlGenericErrorContext,
4279 "last() : %d\n", ctxt->context->contextSize);
4280#endif
4281 } else {
4282 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
4283 }
4284}
4285
4286/**
4287 * xmlXPathPositionFunction:
4288 * @ctxt: the XPath Parser context
4289 * @nargs: the number of arguments
4290 *
4291 * Implement the position() XPath function
4292 * number position()
4293 * The position function returns the position of the context node in the
4294 * context node list. The first position is 1, and so the last positionr
4295 * will be equal to last().
4296 */
4297void
4298xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4299 CHECK_ARITY(0);
4300 if (ctxt->context->proximityPosition >= 0) {
4301 valuePush(ctxt,
4302 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
4303#ifdef DEBUG_EXPR
4304 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
4305 ctxt->context->proximityPosition);
4306#endif
4307 } else {
4308 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
4309 }
4310}
4311
4312/**
4313 * xmlXPathCountFunction:
4314 * @ctxt: the XPath Parser context
4315 * @nargs: the number of arguments
4316 *
4317 * Implement the count() XPath function
4318 * number count(node-set)
4319 */
4320void
4321xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4322 xmlXPathObjectPtr cur;
4323
4324 CHECK_ARITY(1);
4325 if ((ctxt->value == NULL) ||
4326 ((ctxt->value->type != XPATH_NODESET) &&
4327 (ctxt->value->type != XPATH_XSLT_TREE)))
4328 XP_ERROR(XPATH_INVALID_TYPE);
4329 cur = valuePop(ctxt);
4330
Daniel Veillard911f49a2001-04-07 15:39:35 +00004331 if ((cur == NULL) || (cur->nodesetval == NULL))
4332 valuePush(ctxt, xmlXPathNewFloat((double) 0));
4333 else
4334 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
Owen Taylor3473f882001-02-23 17:55:21 +00004335 xmlXPathFreeObject(cur);
4336}
4337
4338/**
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004339 * xmlXPathGetElementsByIds:
4340 * @doc: the document
4341 * @ids: a whitespace separated list of IDs
4342 *
4343 * Selects elements by their unique ID.
4344 *
4345 * Returns a node-set of selected elements.
4346 */
4347static xmlNodeSetPtr
4348xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
4349 xmlNodeSetPtr ret;
4350 const xmlChar *cur = ids;
4351 xmlChar *ID;
4352 xmlAttrPtr attr;
4353 xmlNodePtr elem = NULL;
4354
4355 ret = xmlXPathNodeSetCreate(NULL);
4356
4357 while (IS_BLANK(*cur)) cur++;
4358 while (*cur != 0) {
4359 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
4360 (*cur == '.') || (*cur == '-') ||
4361 (*cur == '_') || (*cur == ':') ||
4362 (IS_COMBINING(*cur)) ||
4363 (IS_EXTENDER(*cur)))
4364 cur++;
4365
4366 if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
4367
4368 ID = xmlStrndup(ids, cur - ids);
4369 attr = xmlGetID(doc, ID);
4370 if (attr != NULL) {
4371 elem = attr->parent;
4372 xmlXPathNodeSetAdd(ret, elem);
4373 }
4374 if (ID != NULL)
4375 xmlFree(ID);
4376
4377 while (IS_BLANK(*cur)) cur++;
4378 ids = cur;
4379 }
4380 return(ret);
4381}
4382
4383/**
Owen Taylor3473f882001-02-23 17:55:21 +00004384 * xmlXPathIdFunction:
4385 * @ctxt: the XPath Parser context
4386 * @nargs: the number of arguments
4387 *
4388 * Implement the id() XPath function
4389 * node-set id(object)
4390 * The id function selects elements by their unique ID
4391 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
4392 * then the result is the union of the result of applying id to the
4393 * string value of each of the nodes in the argument node-set. When the
4394 * argument to id is of any other type, the argument is converted to a
4395 * string as if by a call to the string function; the string is split
4396 * into a whitespace-separated list of tokens (whitespace is any sequence
4397 * of characters matching the production S); the result is a node-set
4398 * containing the elements in the same document as the context node that
4399 * have a unique ID equal to any of the tokens in the list.
4400 */
4401void
4402xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004403 xmlChar *tokens;
4404 xmlNodeSetPtr ret;
4405 xmlXPathObjectPtr obj;
Owen Taylor3473f882001-02-23 17:55:21 +00004406
4407 CHECK_ARITY(1);
4408 obj = valuePop(ctxt);
4409 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
4410 if (obj->type == XPATH_NODESET) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004411 xmlNodeSetPtr ns;
Owen Taylor3473f882001-02-23 17:55:21 +00004412 int i;
4413
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004414 ret = xmlXPathNodeSetCreate(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00004415
Daniel Veillard911f49a2001-04-07 15:39:35 +00004416 if (obj->nodesetval != NULL) {
4417 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004418 tokens =
4419 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
4420 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
4421 ret = xmlXPathNodeSetMerge(ret, ns);
4422 xmlXPathFreeNodeSet(ns);
4423 if (tokens != NULL)
4424 xmlFree(tokens);
Daniel Veillard911f49a2001-04-07 15:39:35 +00004425 }
Owen Taylor3473f882001-02-23 17:55:21 +00004426 }
4427
4428 xmlXPathFreeObject(obj);
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004429 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004430 return;
4431 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004432 obj = xmlXPathConvertString(obj);
Owen Taylor3473f882001-02-23 17:55:21 +00004433
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004434 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
4435 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
Owen Taylor3473f882001-02-23 17:55:21 +00004436
Owen Taylor3473f882001-02-23 17:55:21 +00004437 xmlXPathFreeObject(obj);
4438 return;
4439}
4440
4441/**
4442 * xmlXPathLocalNameFunction:
4443 * @ctxt: the XPath Parser context
4444 * @nargs: the number of arguments
4445 *
4446 * Implement the local-name() XPath function
4447 * string local-name(node-set?)
4448 * The local-name function returns a string containing the local part
4449 * of the name of the node in the argument node-set that is first in
4450 * document order. If the node-set is empty or the first node has no
4451 * name, an empty string is returned. If the argument is omitted it
4452 * defaults to the context node.
4453 */
4454void
4455xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4456 xmlXPathObjectPtr cur;
4457
4458 if (nargs == 0) {
4459 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4460 nargs = 1;
4461 }
4462
4463 CHECK_ARITY(1);
4464 if ((ctxt->value == NULL) ||
4465 ((ctxt->value->type != XPATH_NODESET) &&
4466 (ctxt->value->type != XPATH_XSLT_TREE)))
4467 XP_ERROR(XPATH_INVALID_TYPE);
4468 cur = valuePop(ctxt);
4469
Daniel Veillard911f49a2001-04-07 15:39:35 +00004470 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004471 valuePush(ctxt, xmlXPathNewCString(""));
4472 } else {
4473 int i = 0; /* Should be first in document order !!!!! */
4474 switch (cur->nodesetval->nodeTab[i]->type) {
4475 case XML_ELEMENT_NODE:
4476 case XML_ATTRIBUTE_NODE:
4477 case XML_PI_NODE:
4478 valuePush(ctxt,
4479 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
4480 break;
4481 case XML_NAMESPACE_DECL:
4482 valuePush(ctxt, xmlXPathNewString(
4483 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
4484 break;
4485 default:
4486 valuePush(ctxt, xmlXPathNewCString(""));
4487 }
4488 }
4489 xmlXPathFreeObject(cur);
4490}
4491
4492/**
4493 * xmlXPathNamespaceURIFunction:
4494 * @ctxt: the XPath Parser context
4495 * @nargs: the number of arguments
4496 *
4497 * Implement the namespace-uri() XPath function
4498 * string namespace-uri(node-set?)
4499 * The namespace-uri function returns a string containing the
4500 * namespace URI of the expanded name of the node in the argument
4501 * node-set that is first in document order. If the node-set is empty,
4502 * the first node has no name, or the expanded name has no namespace
4503 * URI, an empty string is returned. If the argument is omitted it
4504 * defaults to the context node.
4505 */
4506void
4507xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4508 xmlXPathObjectPtr cur;
4509
4510 if (nargs == 0) {
4511 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4512 nargs = 1;
4513 }
4514 CHECK_ARITY(1);
4515 if ((ctxt->value == NULL) ||
4516 ((ctxt->value->type != XPATH_NODESET) &&
4517 (ctxt->value->type != XPATH_XSLT_TREE)))
4518 XP_ERROR(XPATH_INVALID_TYPE);
4519 cur = valuePop(ctxt);
4520
Daniel Veillard911f49a2001-04-07 15:39:35 +00004521 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004522 valuePush(ctxt, xmlXPathNewCString(""));
4523 } else {
4524 int i = 0; /* Should be first in document order !!!!! */
4525 switch (cur->nodesetval->nodeTab[i]->type) {
4526 case XML_ELEMENT_NODE:
4527 case XML_ATTRIBUTE_NODE:
4528 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4529 valuePush(ctxt, xmlXPathNewCString(""));
4530 else
4531 valuePush(ctxt, xmlXPathNewString(
4532 cur->nodesetval->nodeTab[i]->ns->href));
4533 break;
4534 default:
4535 valuePush(ctxt, xmlXPathNewCString(""));
4536 }
4537 }
4538 xmlXPathFreeObject(cur);
4539}
4540
4541/**
4542 * xmlXPathNameFunction:
4543 * @ctxt: the XPath Parser context
4544 * @nargs: the number of arguments
4545 *
4546 * Implement the name() XPath function
4547 * string name(node-set?)
4548 * The name function returns a string containing a QName representing
4549 * the name of the node in the argument node-set that is first in documenti
4550 * order. The QName must represent the name with respect to the namespace
4551 * declarations in effect on the node whose name is being represented.
4552 * Typically, this will be the form in which the name occurred in the XML
4553 * source. This need not be the case if there are namespace declarations
4554 * in effect on the node that associate multiple prefixes with the same
4555 * namespace. However, an implementation may include information about
4556 * the original prefix in its representation of nodes; in this case, an
4557 * implementation can ensure that the returned string is always the same
4558 * as the QName used in the XML source. If the argument it omitted it
4559 * defaults to the context node.
4560 * Libxml keep the original prefix so the "real qualified name" used is
4561 * returned.
4562 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00004563static void
Owen Taylor3473f882001-02-23 17:55:21 +00004564xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4565 xmlXPathObjectPtr cur;
4566
4567 if (nargs == 0) {
4568 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
4569 nargs = 1;
4570 }
4571
4572 CHECK_ARITY(1);
4573 if ((ctxt->value == NULL) ||
4574 ((ctxt->value->type != XPATH_NODESET) &&
4575 (ctxt->value->type != XPATH_XSLT_TREE)))
4576 XP_ERROR(XPATH_INVALID_TYPE);
4577 cur = valuePop(ctxt);
4578
Daniel Veillard911f49a2001-04-07 15:39:35 +00004579 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00004580 valuePush(ctxt, xmlXPathNewCString(""));
4581 } else {
4582 int i = 0; /* Should be first in document order !!!!! */
4583
4584 switch (cur->nodesetval->nodeTab[i]->type) {
4585 case XML_ELEMENT_NODE:
4586 case XML_ATTRIBUTE_NODE:
4587 if (cur->nodesetval->nodeTab[i]->ns == NULL)
4588 valuePush(ctxt, xmlXPathNewString(
4589 cur->nodesetval->nodeTab[i]->name));
4590
4591 else {
4592 char name[2000];
Owen Taylor3473f882001-02-23 17:55:21 +00004593 snprintf(name, sizeof(name), "%s:%s",
4594 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
4595 (char *) cur->nodesetval->nodeTab[i]->name);
Owen Taylor3473f882001-02-23 17:55:21 +00004596 name[sizeof(name) - 1] = 0;
4597 valuePush(ctxt, xmlXPathNewCString(name));
4598 }
4599 break;
4600 default:
4601 valuePush(ctxt,
4602 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
4603 xmlXPathLocalNameFunction(ctxt, 1);
4604 }
4605 }
4606 xmlXPathFreeObject(cur);
4607}
4608
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004609
4610/**
Owen Taylor3473f882001-02-23 17:55:21 +00004611 * xmlXPathStringFunction:
4612 * @ctxt: the XPath Parser context
4613 * @nargs: the number of arguments
4614 *
4615 * Implement the string() XPath function
4616 * string string(object?)
4617 * he string function converts an object to a string as follows:
4618 * - A node-set is converted to a string by returning the value of
4619 * the node in the node-set that is first in document order.
4620 * If the node-set is empty, an empty string is returned.
4621 * - A number is converted to a string as follows
4622 * + NaN is converted to the string NaN
4623 * + positive zero is converted to the string 0
4624 * + negative zero is converted to the string 0
4625 * + positive infinity is converted to the string Infinity
4626 * + negative infinity is converted to the string -Infinity
4627 * + if the number is an integer, the number is represented in
4628 * decimal form as a Number with no decimal point and no leading
4629 * zeros, preceded by a minus sign (-) if the number is negative
4630 * + otherwise, the number is represented in decimal form as a
4631 * Number including a decimal point with at least one digit
4632 * before the decimal point and at least one digit after the
4633 * decimal point, preceded by a minus sign (-) if the number
4634 * is negative; there must be no leading zeros before the decimal
4635 * point apart possibly from the one required digit immediatelyi
4636 * before the decimal point; beyond the one required digit
4637 * after the decimal point there must be as many, but only as
4638 * many, more digits as are needed to uniquely distinguish the
4639 * number from all other IEEE 754 numeric values.
4640 * - The boolean false value is converted to the string false.
4641 * The boolean true value is converted to the string true.
4642 *
4643 * If the argument is omitted, it defaults to a node-set with the
4644 * context node as its only member.
4645 */
4646void
4647xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4648 xmlXPathObjectPtr cur;
4649
4650 if (nargs == 0) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004651 valuePush(ctxt,
4652 xmlXPathWrapString(
4653 xmlXPathCastNodeToString(ctxt->context->node)));
4654 return;
Owen Taylor3473f882001-02-23 17:55:21 +00004655 }
4656
4657 CHECK_ARITY(1);
4658 cur = valuePop(ctxt);
4659 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00004660 cur = xmlXPathConvertString(cur);
4661 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00004662}
4663
4664/**
4665 * xmlXPathStringLengthFunction:
4666 * @ctxt: the XPath Parser context
4667 * @nargs: the number of arguments
4668 *
4669 * Implement the string-length() XPath function
4670 * number string-length(string?)
4671 * The string-length returns the number of characters in the string
4672 * (see [3.6 Strings]). If the argument is omitted, it defaults to
4673 * the context node converted to a string, in other words the value
4674 * of the context node.
4675 */
4676void
4677xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4678 xmlXPathObjectPtr cur;
4679
4680 if (nargs == 0) {
4681 if (ctxt->context->node == NULL) {
4682 valuePush(ctxt, xmlXPathNewFloat(0));
4683 } else {
4684 xmlChar *content;
4685
Daniel Veillardba0b8c92001-05-15 09:43:47 +00004686 content = xmlXPathCastNodeToString(ctxt->context->node);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004687 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
Owen Taylor3473f882001-02-23 17:55:21 +00004688 xmlFree(content);
4689 }
4690 return;
4691 }
4692 CHECK_ARITY(1);
4693 CAST_TO_STRING;
4694 CHECK_TYPE(XPATH_STRING);
4695 cur = valuePop(ctxt);
Daniel Veillarde043ee12001-04-16 14:08:07 +00004696 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
Owen Taylor3473f882001-02-23 17:55:21 +00004697 xmlXPathFreeObject(cur);
4698}
4699
4700/**
4701 * xmlXPathConcatFunction:
4702 * @ctxt: the XPath Parser context
4703 * @nargs: the number of arguments
4704 *
4705 * Implement the concat() XPath function
4706 * string concat(string, string, string*)
4707 * The concat function returns the concatenation of its arguments.
4708 */
4709void
4710xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4711 xmlXPathObjectPtr cur, newobj;
4712 xmlChar *tmp;
4713
4714 if (nargs < 2) {
4715 CHECK_ARITY(2);
4716 }
4717
4718 CAST_TO_STRING;
4719 cur = valuePop(ctxt);
4720 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
4721 xmlXPathFreeObject(cur);
4722 return;
4723 }
4724 nargs--;
4725
4726 while (nargs > 0) {
4727 CAST_TO_STRING;
4728 newobj = valuePop(ctxt);
4729 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
4730 xmlXPathFreeObject(newobj);
4731 xmlXPathFreeObject(cur);
4732 XP_ERROR(XPATH_INVALID_TYPE);
4733 }
4734 tmp = xmlStrcat(newobj->stringval, cur->stringval);
4735 newobj->stringval = cur->stringval;
4736 cur->stringval = tmp;
4737
4738 xmlXPathFreeObject(newobj);
4739 nargs--;
4740 }
4741 valuePush(ctxt, cur);
4742}
4743
4744/**
4745 * xmlXPathContainsFunction:
4746 * @ctxt: the XPath Parser context
4747 * @nargs: the number of arguments
4748 *
4749 * Implement the contains() XPath function
4750 * boolean contains(string, string)
4751 * The contains function returns true if the first argument string
4752 * contains the second argument string, and otherwise returns false.
4753 */
4754void
4755xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4756 xmlXPathObjectPtr hay, needle;
4757
4758 CHECK_ARITY(2);
4759 CAST_TO_STRING;
4760 CHECK_TYPE(XPATH_STRING);
4761 needle = valuePop(ctxt);
4762 CAST_TO_STRING;
4763 hay = valuePop(ctxt);
4764 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4765 xmlXPathFreeObject(hay);
4766 xmlXPathFreeObject(needle);
4767 XP_ERROR(XPATH_INVALID_TYPE);
4768 }
4769 if (xmlStrstr(hay->stringval, needle->stringval))
4770 valuePush(ctxt, xmlXPathNewBoolean(1));
4771 else
4772 valuePush(ctxt, xmlXPathNewBoolean(0));
4773 xmlXPathFreeObject(hay);
4774 xmlXPathFreeObject(needle);
4775}
4776
4777/**
4778 * xmlXPathStartsWithFunction:
4779 * @ctxt: the XPath Parser context
4780 * @nargs: the number of arguments
4781 *
4782 * Implement the starts-with() XPath function
4783 * boolean starts-with(string, string)
4784 * The starts-with function returns true if the first argument string
4785 * starts with the second argument string, and otherwise returns false.
4786 */
4787void
4788xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4789 xmlXPathObjectPtr hay, needle;
4790 int n;
4791
4792 CHECK_ARITY(2);
4793 CAST_TO_STRING;
4794 CHECK_TYPE(XPATH_STRING);
4795 needle = valuePop(ctxt);
4796 CAST_TO_STRING;
4797 hay = valuePop(ctxt);
4798 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
4799 xmlXPathFreeObject(hay);
4800 xmlXPathFreeObject(needle);
4801 XP_ERROR(XPATH_INVALID_TYPE);
4802 }
4803 n = xmlStrlen(needle->stringval);
4804 if (xmlStrncmp(hay->stringval, needle->stringval, n))
4805 valuePush(ctxt, xmlXPathNewBoolean(0));
4806 else
4807 valuePush(ctxt, xmlXPathNewBoolean(1));
4808 xmlXPathFreeObject(hay);
4809 xmlXPathFreeObject(needle);
4810}
4811
4812/**
4813 * xmlXPathSubstringFunction:
4814 * @ctxt: the XPath Parser context
4815 * @nargs: the number of arguments
4816 *
4817 * Implement the substring() XPath function
4818 * string substring(string, number, number?)
4819 * The substring function returns the substring of the first argument
4820 * starting at the position specified in the second argument with
4821 * length specified in the third argument. For example,
4822 * substring("12345",2,3) returns "234". If the third argument is not
4823 * specified, it returns the substring starting at the position specified
4824 * in the second argument and continuing to the end of the string. For
4825 * example, substring("12345",2) returns "2345". More precisely, each
4826 * character in the string (see [3.6 Strings]) is considered to have a
4827 * numeric position: the position of the first character is 1, the position
4828 * of the second character is 2 and so on. The returned substring contains
4829 * those characters for which the position of the character is greater than
4830 * or equal to the second argument and, if the third argument is specified,
4831 * less than the sum of the second and third arguments; the comparisons
4832 * and addition used for the above follow the standard IEEE 754 rules. Thus:
4833 * - substring("12345", 1.5, 2.6) returns "234"
4834 * - substring("12345", 0, 3) returns "12"
4835 * - substring("12345", 0 div 0, 3) returns ""
4836 * - substring("12345", 1, 0 div 0) returns ""
4837 * - substring("12345", -42, 1 div 0) returns "12345"
4838 * - substring("12345", -1 div 0, 1 div 0) returns ""
4839 */
4840void
4841xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4842 xmlXPathObjectPtr str, start, len;
4843 double le, in;
4844 int i, l;
4845 xmlChar *ret;
4846
4847 /*
Daniel Veillarde043ee12001-04-16 14:08:07 +00004848 * TODO: need to be converted to UTF8 strings
Owen Taylor3473f882001-02-23 17:55:21 +00004849 */
4850 if (nargs < 2) {
4851 CHECK_ARITY(2);
4852 }
4853 if (nargs > 3) {
4854 CHECK_ARITY(3);
4855 }
4856 if (nargs == 3) {
4857 CAST_TO_NUMBER;
4858 CHECK_TYPE(XPATH_NUMBER);
4859 len = valuePop(ctxt);
4860 le = len->floatval;
4861 xmlXPathFreeObject(len);
4862 } else {
4863 le = 2000000000;
4864 }
4865 CAST_TO_NUMBER;
4866 CHECK_TYPE(XPATH_NUMBER);
4867 start = valuePop(ctxt);
4868 in = start->floatval;
4869 xmlXPathFreeObject(start);
4870 CAST_TO_STRING;
4871 CHECK_TYPE(XPATH_STRING);
4872 str = valuePop(ctxt);
4873 le += in;
4874
4875 /* integer index of the first char */
4876 i = (int) in;
4877 if (((double)i) != in) i++;
4878
4879 /* integer index of the last char */
4880 l = (int) le;
4881 if (((double)l) != le) l++;
4882
4883 /* back to a zero based len */
4884 i--;
4885 l--;
4886
4887 /* check against the string len */
4888 if (l > 1024) {
4889 l = xmlStrlen(str->stringval);
4890 }
4891 if (i < 0) {
4892 i = 0;
4893 }
4894
4895 /* number of chars to copy */
4896 l -= i;
4897
4898 ret = xmlStrsub(str->stringval, i, l);
4899 if (ret == NULL)
4900 valuePush(ctxt, xmlXPathNewCString(""));
4901 else {
4902 valuePush(ctxt, xmlXPathNewString(ret));
4903 xmlFree(ret);
4904 }
4905 xmlXPathFreeObject(str);
4906}
4907
4908/**
4909 * xmlXPathSubstringBeforeFunction:
4910 * @ctxt: the XPath Parser context
4911 * @nargs: the number of arguments
4912 *
4913 * Implement the substring-before() XPath function
4914 * string substring-before(string, string)
4915 * The substring-before function returns the substring of the first
4916 * argument string that precedes the first occurrence of the second
4917 * argument string in the first argument string, or the empty string
4918 * if the first argument string does not contain the second argument
4919 * string. For example, substring-before("1999/04/01","/") returns 1999.
4920 */
4921void
4922xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4923 xmlXPathObjectPtr str;
4924 xmlXPathObjectPtr find;
4925 xmlBufferPtr target;
4926 const xmlChar *point;
4927 int offset;
4928
4929 CHECK_ARITY(2);
4930 CAST_TO_STRING;
4931 find = valuePop(ctxt);
4932 CAST_TO_STRING;
4933 str = valuePop(ctxt);
4934
4935 target = xmlBufferCreate();
4936 if (target) {
4937 point = xmlStrstr(str->stringval, find->stringval);
4938 if (point) {
4939 offset = (int)(point - str->stringval);
4940 xmlBufferAdd(target, str->stringval, offset);
4941 }
4942 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4943 xmlBufferFree(target);
4944 }
4945
4946 xmlXPathFreeObject(str);
4947 xmlXPathFreeObject(find);
4948}
4949
4950/**
4951 * xmlXPathSubstringAfterFunction:
4952 * @ctxt: the XPath Parser context
4953 * @nargs: the number of arguments
4954 *
4955 * Implement the substring-after() XPath function
4956 * string substring-after(string, string)
4957 * The substring-after function returns the substring of the first
4958 * argument string that follows the first occurrence of the second
4959 * argument string in the first argument string, or the empty stringi
4960 * if the first argument string does not contain the second argument
4961 * string. For example, substring-after("1999/04/01","/") returns 04/01,
4962 * and substring-after("1999/04/01","19") returns 99/04/01.
4963 */
4964void
4965xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
4966 xmlXPathObjectPtr str;
4967 xmlXPathObjectPtr find;
4968 xmlBufferPtr target;
4969 const xmlChar *point;
4970 int offset;
4971
4972 CHECK_ARITY(2);
4973 CAST_TO_STRING;
4974 find = valuePop(ctxt);
4975 CAST_TO_STRING;
4976 str = valuePop(ctxt);
4977
4978 target = xmlBufferCreate();
4979 if (target) {
4980 point = xmlStrstr(str->stringval, find->stringval);
4981 if (point) {
4982 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
4983 xmlBufferAdd(target, &str->stringval[offset],
4984 xmlStrlen(str->stringval) - offset);
4985 }
4986 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
4987 xmlBufferFree(target);
4988 }
4989
4990 xmlXPathFreeObject(str);
4991 xmlXPathFreeObject(find);
4992}
4993
4994/**
4995 * xmlXPathNormalizeFunction:
4996 * @ctxt: the XPath Parser context
4997 * @nargs: the number of arguments
4998 *
4999 * Implement the normalize-space() XPath function
5000 * string normalize-space(string?)
5001 * The normalize-space function returns the argument string with white
5002 * space normalized by stripping leading and trailing whitespace
5003 * and replacing sequences of whitespace characters by a single
5004 * space. Whitespace characters are the same allowed by the S production
5005 * in XML. If the argument is omitted, it defaults to the context
5006 * node converted to a string, in other words the value of the context node.
5007 */
5008void
5009xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5010 xmlXPathObjectPtr obj = NULL;
5011 xmlChar *source = NULL;
5012 xmlBufferPtr target;
5013 xmlChar blank;
5014
5015 if (nargs == 0) {
5016 /* Use current context node */
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005017 valuePush(ctxt,
5018 xmlXPathWrapString(
5019 xmlXPathCastNodeToString(ctxt->context->node)));
Owen Taylor3473f882001-02-23 17:55:21 +00005020 nargs = 1;
5021 }
5022
5023 CHECK_ARITY(1);
5024 CAST_TO_STRING;
5025 CHECK_TYPE(XPATH_STRING);
5026 obj = valuePop(ctxt);
5027 source = obj->stringval;
5028
5029 target = xmlBufferCreate();
5030 if (target && source) {
5031
5032 /* Skip leading whitespaces */
5033 while (IS_BLANK(*source))
5034 source++;
5035
5036 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
5037 blank = 0;
5038 while (*source) {
5039 if (IS_BLANK(*source)) {
5040 blank = *source;
5041 } else {
5042 if (blank) {
5043 xmlBufferAdd(target, &blank, 1);
5044 blank = 0;
5045 }
5046 xmlBufferAdd(target, source, 1);
5047 }
5048 source++;
5049 }
5050
5051 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5052 xmlBufferFree(target);
5053 }
5054 xmlXPathFreeObject(obj);
5055}
5056
5057/**
5058 * xmlXPathTranslateFunction:
5059 * @ctxt: the XPath Parser context
5060 * @nargs: the number of arguments
5061 *
5062 * Implement the translate() XPath function
5063 * string translate(string, string, string)
5064 * The translate function returns the first argument string with
5065 * occurrences of characters in the second argument string replaced
5066 * by the character at the corresponding position in the third argument
5067 * string. For example, translate("bar","abc","ABC") returns the string
5068 * BAr. If there is a character in the second argument string with no
5069 * character at a corresponding position in the third argument string
5070 * (because the second argument string is longer than the third argument
5071 * string), then occurrences of that character in the first argument
5072 * string are removed. For example, translate("--aaa--","abc-","ABC")
5073 * returns "AAA". If a character occurs more than once in second
5074 * argument string, then the first occurrence determines the replacement
5075 * character. If the third argument string is longer than the second
5076 * argument string, then excess characters are ignored.
5077 */
5078void
5079xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
Daniel Veillarde043ee12001-04-16 14:08:07 +00005080 xmlXPathObjectPtr str;
5081 xmlXPathObjectPtr from;
5082 xmlXPathObjectPtr to;
5083 xmlBufferPtr target;
5084 int i, offset, max;
5085 xmlChar ch;
5086 const xmlChar *point;
Owen Taylor3473f882001-02-23 17:55:21 +00005087
Daniel Veillarde043ee12001-04-16 14:08:07 +00005088 /*
5089 * TODO: need to be converted to UTF8 strings
5090 */
5091 CHECK_ARITY(3);
Owen Taylor3473f882001-02-23 17:55:21 +00005092
Daniel Veillarde043ee12001-04-16 14:08:07 +00005093 CAST_TO_STRING;
5094 to = valuePop(ctxt);
5095 CAST_TO_STRING;
5096 from = valuePop(ctxt);
5097 CAST_TO_STRING;
5098 str = valuePop(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005099
Daniel Veillarde043ee12001-04-16 14:08:07 +00005100 target = xmlBufferCreate();
5101 if (target) {
5102 max = xmlStrlen(to->stringval);
5103 for (i = 0; (ch = str->stringval[i]); i++) {
5104 point = xmlStrchr(from->stringval, ch);
5105 if (point) {
5106 offset = (int)(point - from->stringval);
5107 if (offset < max)
5108 xmlBufferAdd(target, &to->stringval[offset], 1);
5109 } else
5110 xmlBufferAdd(target, &ch, 1);
5111 }
Owen Taylor3473f882001-02-23 17:55:21 +00005112 }
Daniel Veillarde043ee12001-04-16 14:08:07 +00005113 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
5114 xmlBufferFree(target);
5115 xmlXPathFreeObject(str);
5116 xmlXPathFreeObject(from);
5117 xmlXPathFreeObject(to);
Owen Taylor3473f882001-02-23 17:55:21 +00005118}
5119
5120/**
5121 * xmlXPathBooleanFunction:
5122 * @ctxt: the XPath Parser context
5123 * @nargs: the number of arguments
5124 *
5125 * Implement the boolean() XPath function
5126 * boolean boolean(object)
5127 * he boolean function converts its argument to a boolean as follows:
5128 * - a number is true if and only if it is neither positive or
5129 * negative zero nor NaN
5130 * - a node-set is true if and only if it is non-empty
5131 * - a string is true if and only if its length is non-zero
5132 */
5133void
5134xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5135 xmlXPathObjectPtr cur;
Owen Taylor3473f882001-02-23 17:55:21 +00005136
5137 CHECK_ARITY(1);
5138 cur = valuePop(ctxt);
5139 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005140 cur = xmlXPathConvertBoolean(cur);
5141 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005142}
5143
5144/**
5145 * xmlXPathNotFunction:
5146 * @ctxt: the XPath Parser context
5147 * @nargs: the number of arguments
5148 *
5149 * Implement the not() XPath function
5150 * boolean not(boolean)
5151 * The not function returns true if its argument is false,
5152 * and false otherwise.
5153 */
5154void
5155xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5156 CHECK_ARITY(1);
5157 CAST_TO_BOOLEAN;
5158 CHECK_TYPE(XPATH_BOOLEAN);
5159 ctxt->value->boolval = ! ctxt->value->boolval;
5160}
5161
5162/**
5163 * xmlXPathTrueFunction:
5164 * @ctxt: the XPath Parser context
5165 * @nargs: the number of arguments
5166 *
5167 * Implement the true() XPath function
5168 * boolean true()
5169 */
5170void
5171xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5172 CHECK_ARITY(0);
5173 valuePush(ctxt, xmlXPathNewBoolean(1));
5174}
5175
5176/**
5177 * xmlXPathFalseFunction:
5178 * @ctxt: the XPath Parser context
5179 * @nargs: the number of arguments
5180 *
5181 * Implement the false() XPath function
5182 * boolean false()
5183 */
5184void
5185xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5186 CHECK_ARITY(0);
5187 valuePush(ctxt, xmlXPathNewBoolean(0));
5188}
5189
5190/**
5191 * xmlXPathLangFunction:
5192 * @ctxt: the XPath Parser context
5193 * @nargs: the number of arguments
5194 *
5195 * Implement the lang() XPath function
5196 * boolean lang(string)
5197 * The lang function returns true or false depending on whether the
5198 * language of the context node as specified by xml:lang attributes
5199 * is the same as or is a sublanguage of the language specified by
5200 * the argument string. The language of the context node is determined
5201 * by the value of the xml:lang attribute on the context node, or, if
5202 * the context node has no xml:lang attribute, by the value of the
5203 * xml:lang attribute on the nearest ancestor of the context node that
5204 * has an xml:lang attribute. If there is no such attribute, then lang
5205 * returns false. If there is such an attribute, then lang returns
5206 * true if the attribute value is equal to the argument ignoring case,
5207 * or if there is some suffix starting with - such that the attribute
5208 * value is equal to the argument ignoring that suffix of the attribute
5209 * value and ignoring case.
5210 */
5211void
5212xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5213 xmlXPathObjectPtr val;
5214 const xmlChar *theLang;
5215 const xmlChar *lang;
5216 int ret = 0;
5217 int i;
5218
5219 CHECK_ARITY(1);
5220 CAST_TO_STRING;
5221 CHECK_TYPE(XPATH_STRING);
5222 val = valuePop(ctxt);
5223 lang = val->stringval;
5224 theLang = xmlNodeGetLang(ctxt->context->node);
5225 if ((theLang != NULL) && (lang != NULL)) {
5226 for (i = 0;lang[i] != 0;i++)
5227 if (toupper(lang[i]) != toupper(theLang[i]))
5228 goto not_equal;
5229 ret = 1;
5230 }
5231not_equal:
5232 xmlXPathFreeObject(val);
5233 valuePush(ctxt, xmlXPathNewBoolean(ret));
5234}
5235
5236/**
5237 * xmlXPathNumberFunction:
5238 * @ctxt: the XPath Parser context
5239 * @nargs: the number of arguments
5240 *
5241 * Implement the number() XPath function
5242 * number number(object?)
5243 */
5244void
5245xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5246 xmlXPathObjectPtr cur;
5247 double res;
5248
5249 if (nargs == 0) {
5250 if (ctxt->context->node == NULL) {
5251 valuePush(ctxt, xmlXPathNewFloat(0.0));
5252 } else {
5253 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
5254
5255 res = xmlXPathStringEvalNumber(content);
5256 valuePush(ctxt, xmlXPathNewFloat(res));
5257 xmlFree(content);
5258 }
5259 return;
5260 }
5261
5262 CHECK_ARITY(1);
5263 cur = valuePop(ctxt);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005264 cur = xmlXPathConvertNumber(cur);
5265 valuePush(ctxt, cur);
Owen Taylor3473f882001-02-23 17:55:21 +00005266}
5267
5268/**
5269 * xmlXPathSumFunction:
5270 * @ctxt: the XPath Parser context
5271 * @nargs: the number of arguments
5272 *
5273 * Implement the sum() XPath function
5274 * number sum(node-set)
5275 * The sum function returns the sum of the values of the nodes in
5276 * the argument node-set.
5277 */
5278void
5279xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5280 xmlXPathObjectPtr cur;
5281 int i;
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005282 double res = 0.0;
Owen Taylor3473f882001-02-23 17:55:21 +00005283
5284 CHECK_ARITY(1);
5285 if ((ctxt->value == NULL) ||
5286 ((ctxt->value->type != XPATH_NODESET) &&
5287 (ctxt->value->type != XPATH_XSLT_TREE)))
5288 XP_ERROR(XPATH_INVALID_TYPE);
5289 cur = valuePop(ctxt);
5290
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005291 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
Owen Taylor3473f882001-02-23 17:55:21 +00005292 valuePush(ctxt, xmlXPathNewFloat(0.0));
5293 } else {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005294 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
5295 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
Owen Taylor3473f882001-02-23 17:55:21 +00005296 }
Daniel Veillardba0b8c92001-05-15 09:43:47 +00005297 valuePush(ctxt, xmlXPathNewFloat(res));
Owen Taylor3473f882001-02-23 17:55:21 +00005298 }
5299 xmlXPathFreeObject(cur);
5300}
5301
5302/**
5303 * xmlXPathFloorFunction:
5304 * @ctxt: the XPath Parser context
5305 * @nargs: the number of arguments
5306 *
5307 * Implement the floor() XPath function
5308 * number floor(number)
5309 * The floor function returns the largest (closest to positive infinity)
5310 * number that is not greater than the argument and that is an integer.
5311 */
5312void
5313xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5314 CHECK_ARITY(1);
5315 CAST_TO_NUMBER;
5316 CHECK_TYPE(XPATH_NUMBER);
5317#if 0
5318 ctxt->value->floatval = floor(ctxt->value->floatval);
5319#else
5320 /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
5321 ctxt->value->floatval = (double)((int) ctxt->value->floatval);
5322#endif
5323}
5324
5325/**
5326 * xmlXPathCeilingFunction:
5327 * @ctxt: the XPath Parser context
5328 * @nargs: the number of arguments
5329 *
5330 * Implement the ceiling() XPath function
5331 * number ceiling(number)
5332 * The ceiling function returns the smallest (closest to negative infinity)
5333 * number that is not less than the argument and that is an integer.
5334 */
5335void
5336xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5337 double f;
5338
5339 CHECK_ARITY(1);
5340 CAST_TO_NUMBER;
5341 CHECK_TYPE(XPATH_NUMBER);
5342
5343#if 0
5344 ctxt->value->floatval = ceil(ctxt->value->floatval);
5345#else
5346 f = (double)((int) ctxt->value->floatval);
5347 if (f != ctxt->value->floatval)
5348 ctxt->value->floatval = f + 1;
5349#endif
5350}
5351
5352/**
5353 * xmlXPathRoundFunction:
5354 * @ctxt: the XPath Parser context
5355 * @nargs: the number of arguments
5356 *
5357 * Implement the round() XPath function
5358 * number round(number)
5359 * The round function returns the number that is closest to the
5360 * argument and that is an integer. If there are two such numbers,
5361 * then the one that is even is returned.
5362 */
5363void
5364xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5365 double f;
5366
5367 CHECK_ARITY(1);
5368 CAST_TO_NUMBER;
5369 CHECK_TYPE(XPATH_NUMBER);
5370
5371 if ((ctxt->value->floatval == xmlXPathNAN) ||
5372 (ctxt->value->floatval == xmlXPathPINF) ||
5373 (ctxt->value->floatval == xmlXPathNINF) ||
5374 (ctxt->value->floatval == 0.0))
5375 return;
5376
5377#if 0
5378 f = floor(ctxt->value->floatval);
5379#else
5380 f = (double)((int) ctxt->value->floatval);
5381#endif
5382 if (ctxt->value->floatval < f + 0.5)
5383 ctxt->value->floatval = f;
5384 else
5385 ctxt->value->floatval = f + 1;
5386}
5387
5388/************************************************************************
5389 * *
5390 * The Parser *
5391 * *
5392 ************************************************************************/
5393
5394/*
5395 * a couple of forward declarations since we use a recursive call based
5396 * implementation.
5397 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005398static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00005399static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005400static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005401#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005402static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt);
5403#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00005404#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005405static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00005406#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00005407static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
5408 int qualified);
Owen Taylor3473f882001-02-23 17:55:21 +00005409
5410/**
Daniel Veillard61d80a22001-04-27 17:13:01 +00005411 * xmlXPathCurrentChar:
5412 * @ctxt: the XPath parser context
5413 * @cur: pointer to the beginning of the char
5414 * @len: pointer to the length of the char read
5415 *
5416 * The current char value, if using UTF-8 this may actaully span multiple
5417 * bytes in the input buffer.
5418 *
5419 * Returns the current char value and its lenght
5420 */
5421
5422static int
5423xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
5424 unsigned char c;
5425 unsigned int val;
5426 const xmlChar *cur;
5427
5428 if (ctxt == NULL)
5429 return(0);
5430 cur = ctxt->cur;
5431
5432 /*
5433 * We are supposed to handle UTF8, check it's valid
5434 * From rfc2044: encoding of the Unicode values on UTF-8:
5435 *
5436 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
5437 * 0000 0000-0000 007F 0xxxxxxx
5438 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
5439 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
5440 *
5441 * Check for the 0x110000 limit too
5442 */
5443 c = *cur;
5444 if (c & 0x80) {
5445 if ((cur[1] & 0xc0) != 0x80)
5446 goto encoding_error;
5447 if ((c & 0xe0) == 0xe0) {
5448
5449 if ((cur[2] & 0xc0) != 0x80)
5450 goto encoding_error;
5451 if ((c & 0xf0) == 0xf0) {
5452 if (((c & 0xf8) != 0xf0) ||
5453 ((cur[3] & 0xc0) != 0x80))
5454 goto encoding_error;
5455 /* 4-byte code */
5456 *len = 4;
5457 val = (cur[0] & 0x7) << 18;
5458 val |= (cur[1] & 0x3f) << 12;
5459 val |= (cur[2] & 0x3f) << 6;
5460 val |= cur[3] & 0x3f;
5461 } else {
5462 /* 3-byte code */
5463 *len = 3;
5464 val = (cur[0] & 0xf) << 12;
5465 val |= (cur[1] & 0x3f) << 6;
5466 val |= cur[2] & 0x3f;
5467 }
5468 } else {
5469 /* 2-byte code */
5470 *len = 2;
5471 val = (cur[0] & 0x1f) << 6;
5472 val |= cur[1] & 0x3f;
5473 }
5474 if (!IS_CHAR(val)) {
5475 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
5476 }
5477 return(val);
5478 } else {
5479 /* 1-byte code */
5480 *len = 1;
5481 return((int) *cur);
5482 }
5483encoding_error:
5484 /*
5485 * If we detect an UTF8 error that probably mean that the
5486 * input encoding didn't get properly advertized in the
5487 * declaration header. Report the error and switch the encoding
5488 * to ISO-Latin-1 (if you don't like this policy, just declare the
5489 * encoding !)
5490 */
Daniel Veillard42596ad2001-05-22 16:57:14 +00005491 *len = 0;
Daniel Veillard61d80a22001-04-27 17:13:01 +00005492 XP_ERROR0(XPATH_ENCODING_ERROR);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005493}
5494
5495/**
Owen Taylor3473f882001-02-23 17:55:21 +00005496 * xmlXPathParseNCName:
5497 * @ctxt: the XPath Parser context
5498 *
5499 * parse an XML namespace non qualified name.
5500 *
5501 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
5502 *
5503 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
5504 * CombiningChar | Extender
5505 *
5506 * Returns the namespace name or NULL
5507 */
5508
5509xmlChar *
5510xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard2156a562001-04-28 12:24:34 +00005511 const xmlChar *in;
5512 xmlChar *ret;
5513 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005514
Daniel Veillard2156a562001-04-28 12:24:34 +00005515 /*
5516 * Accelerator for simple ASCII names
5517 */
5518 in = ctxt->cur;
5519 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5520 ((*in >= 0x41) && (*in <= 0x5A)) ||
5521 (*in == '_')) {
5522 in++;
5523 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5524 ((*in >= 0x41) && (*in <= 0x5A)) ||
5525 ((*in >= 0x30) && (*in <= 0x39)) ||
5526 (*in == '_'))
5527 in++;
5528 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
5529 (*in == '[') || (*in == ']') || (*in == ':') ||
5530 (*in == '@') || (*in == '*')) {
5531 count = in - ctxt->cur;
5532 if (count == 0)
5533 return(NULL);
5534 ret = xmlStrndup(ctxt->cur, count);
5535 ctxt->cur = in;
5536 return(ret);
5537 }
5538 }
5539 return(xmlXPathParseNameComplex(ctxt, 0));
Owen Taylor3473f882001-02-23 17:55:21 +00005540}
5541
Daniel Veillard2156a562001-04-28 12:24:34 +00005542
Owen Taylor3473f882001-02-23 17:55:21 +00005543/**
5544 * xmlXPathParseQName:
5545 * @ctxt: the XPath Parser context
5546 * @prefix: a xmlChar **
5547 *
5548 * parse an XML qualified name
5549 *
5550 * [NS 5] QName ::= (Prefix ':')? LocalPart
5551 *
5552 * [NS 6] Prefix ::= NCName
5553 *
5554 * [NS 7] LocalPart ::= NCName
5555 *
5556 * Returns the function returns the local part, and prefix is updated
5557 * to get the Prefix if any.
5558 */
5559
Daniel Veillard56a4cb82001-03-24 17:00:36 +00005560static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00005561xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
5562 xmlChar *ret = NULL;
5563
5564 *prefix = NULL;
5565 ret = xmlXPathParseNCName(ctxt);
5566 if (CUR == ':') {
5567 *prefix = ret;
5568 NEXT;
5569 ret = xmlXPathParseNCName(ctxt);
5570 }
5571 return(ret);
5572}
5573
5574/**
5575 * xmlXPathParseName:
5576 * @ctxt: the XPath Parser context
5577 *
5578 * parse an XML name
5579 *
5580 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
5581 * CombiningChar | Extender
5582 *
5583 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
5584 *
5585 * Returns the namespace name or NULL
5586 */
5587
5588xmlChar *
5589xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005590 const xmlChar *in;
5591 xmlChar *ret;
5592 int count = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005593
Daniel Veillard61d80a22001-04-27 17:13:01 +00005594 /*
5595 * Accelerator for simple ASCII names
5596 */
5597 in = ctxt->cur;
5598 if (((*in >= 0x61) && (*in <= 0x7A)) ||
5599 ((*in >= 0x41) && (*in <= 0x5A)) ||
5600 (*in == '_') || (*in == ':')) {
5601 in++;
5602 while (((*in >= 0x61) && (*in <= 0x7A)) ||
5603 ((*in >= 0x41) && (*in <= 0x5A)) ||
5604 ((*in >= 0x30) && (*in <= 0x39)) ||
Daniel Veillard76d66f42001-05-16 21:05:17 +00005605 (*in == '_') || (*in == '-') ||
5606 (*in == ':') || (*in == '.'))
Daniel Veillard61d80a22001-04-27 17:13:01 +00005607 in++;
Daniel Veillard76d66f42001-05-16 21:05:17 +00005608 if ((*in > 0) && (*in < 0x80)) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005609 count = in - ctxt->cur;
5610 ret = xmlStrndup(ctxt->cur, count);
5611 ctxt->cur = in;
5612 return(ret);
5613 }
5614 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005615 return(xmlXPathParseNameComplex(ctxt, 1));
Owen Taylor3473f882001-02-23 17:55:21 +00005616}
5617
Daniel Veillard61d80a22001-04-27 17:13:01 +00005618static xmlChar *
Daniel Veillard2156a562001-04-28 12:24:34 +00005619xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005620 xmlChar buf[XML_MAX_NAMELEN + 5];
5621 int len = 0, l;
5622 int c;
5623
5624 /*
5625 * Handler for more complex cases
5626 */
5627 c = CUR_CHAR(l);
5628 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
Daniel Veillard2156a562001-04-28 12:24:34 +00005629 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
5630 (c == '*') || /* accelerators */
Daniel Veillard61d80a22001-04-27 17:13:01 +00005631 (!IS_LETTER(c) && (c != '_') &&
Daniel Veillard2156a562001-04-28 12:24:34 +00005632 ((qualified) && (c != ':')))) {
Daniel Veillard61d80a22001-04-27 17:13:01 +00005633 return(NULL);
5634 }
5635
5636 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
5637 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
5638 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005639 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005640 (IS_COMBINING(c)) ||
5641 (IS_EXTENDER(c)))) {
5642 COPY_BUF(l,buf,len,c);
5643 NEXTL(l);
5644 c = CUR_CHAR(l);
5645 if (len >= XML_MAX_NAMELEN) {
5646 /*
5647 * Okay someone managed to make a huge name, so he's ready to pay
5648 * for the processing speed.
5649 */
5650 xmlChar *buffer;
5651 int max = len * 2;
5652
5653 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
5654 if (buffer == NULL) {
5655 XP_ERROR0(XPATH_MEMORY_ERROR);
5656 }
5657 memcpy(buffer, buf, len);
5658 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
5659 (c == '.') || (c == '-') ||
Daniel Veillard2156a562001-04-28 12:24:34 +00005660 (c == '_') || ((qualified) && (c == ':')) ||
Daniel Veillard61d80a22001-04-27 17:13:01 +00005661 (IS_COMBINING(c)) ||
5662 (IS_EXTENDER(c))) {
5663 if (len + 10 > max) {
5664 max *= 2;
5665 buffer = (xmlChar *) xmlRealloc(buffer,
5666 max * sizeof(xmlChar));
Daniel Veillard61d80a22001-04-27 17:13:01 +00005667 if (buffer == NULL) {
5668 XP_ERROR0(XPATH_MEMORY_ERROR);
5669 }
5670 }
5671 COPY_BUF(l,buffer,len,c);
5672 NEXTL(l);
5673 c = CUR_CHAR(l);
5674 }
5675 buffer[len] = 0;
5676 return(buffer);
5677 }
5678 }
Daniel Veillard2156a562001-04-28 12:24:34 +00005679 if (len == 0)
5680 return(NULL);
Daniel Veillard61d80a22001-04-27 17:13:01 +00005681 return(xmlStrndup(buf, len));
5682}
Owen Taylor3473f882001-02-23 17:55:21 +00005683/**
5684 * xmlXPathStringEvalNumber:
5685 * @str: A string to scan
5686 *
Bjorn Reese70a9da52001-04-21 16:57:29 +00005687 * [30a] Float ::= Number ('e' Digits?)?
5688 *
Owen Taylor3473f882001-02-23 17:55:21 +00005689 * [30] Number ::= Digits ('.' Digits?)?
5690 * | '.' Digits
5691 * [31] Digits ::= [0-9]+
5692 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005693 * Compile a Number in the string
Owen Taylor3473f882001-02-23 17:55:21 +00005694 * In complement of the Number expression, this function also handles
5695 * negative values : '-' Number.
5696 *
5697 * Returns the double value.
5698 */
5699double
5700xmlXPathStringEvalNumber(const xmlChar *str) {
5701 const xmlChar *cur = str;
5702 double ret = 0.0;
5703 double mult = 1;
5704 int ok = 0;
5705 int isneg = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005706 int exponent = 0;
5707 int is_exponent_negative = 0;
5708
Owen Taylor3473f882001-02-23 17:55:21 +00005709 while (IS_BLANK(*cur)) cur++;
5710 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
5711 return(xmlXPathNAN);
5712 }
5713 if (*cur == '-') {
5714 isneg = 1;
5715 cur++;
5716 }
5717 while ((*cur >= '0') && (*cur <= '9')) {
5718 ret = ret * 10 + (*cur - '0');
5719 ok = 1;
5720 cur++;
5721 }
5722 if (*cur == '.') {
5723 cur++;
5724 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
5725 return(xmlXPathNAN);
5726 }
5727 while ((*cur >= '0') && (*cur <= '9')) {
5728 mult /= 10;
5729 ret = ret + (*cur - '0') * mult;
5730 cur++;
5731 }
5732 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005733 if ((*cur == 'e') || (*cur == 'E')) {
5734 cur++;
5735 if (*cur == '-') {
5736 is_exponent_negative = 1;
5737 cur++;
5738 }
5739 while ((*cur >= '0') && (*cur <= '9')) {
5740 exponent = exponent * 10 + (*cur - '0');
5741 cur++;
5742 }
5743 }
Owen Taylor3473f882001-02-23 17:55:21 +00005744 while (IS_BLANK(*cur)) cur++;
5745 if (*cur != 0) return(xmlXPathNAN);
5746 if (isneg) ret = -ret;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005747 if (is_exponent_negative) exponent = -exponent;
5748 ret *= pow(10.0, (double)exponent);
Owen Taylor3473f882001-02-23 17:55:21 +00005749 return(ret);
5750}
5751
5752/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005753 * xmlXPathCompNumber:
Owen Taylor3473f882001-02-23 17:55:21 +00005754 * @ctxt: the XPath Parser context
5755 *
5756 * [30] Number ::= Digits ('.' Digits?)?
5757 * | '.' Digits
5758 * [31] Digits ::= [0-9]+
5759 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005760 * Compile a Number, then push it on the stack
Owen Taylor3473f882001-02-23 17:55:21 +00005761 *
5762 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005763static void
5764xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005765 double ret = 0.0;
5766 double mult = 1;
5767 int ok = 0;
Bjorn Reese70a9da52001-04-21 16:57:29 +00005768 int exponent = 0;
5769 int is_exponent_negative = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00005770
5771 CHECK_ERROR;
5772 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
5773 XP_ERROR(XPATH_NUMBER_ERROR);
5774 }
5775 while ((CUR >= '0') && (CUR <= '9')) {
5776 ret = ret * 10 + (CUR - '0');
5777 ok = 1;
5778 NEXT;
5779 }
5780 if (CUR == '.') {
5781 NEXT;
5782 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
5783 XP_ERROR(XPATH_NUMBER_ERROR);
5784 }
5785 while ((CUR >= '0') && (CUR <= '9')) {
5786 mult /= 10;
5787 ret = ret + (CUR - '0') * mult;
5788 NEXT;
5789 }
5790 }
Bjorn Reese70a9da52001-04-21 16:57:29 +00005791 if ((CUR == 'e') || (CUR == 'E')) {
5792 NEXT;
5793 if (CUR == '-') {
5794 is_exponent_negative = 1;
5795 NEXT;
5796 }
5797 while ((CUR >= '0') && (CUR <= '9')) {
5798 exponent = exponent * 10 + (CUR - '0');
5799 NEXT;
5800 }
5801 }
5802 if (is_exponent_negative)
5803 exponent = -exponent;
5804 ret *= pow(10.0, (double)exponent);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005805 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
5806 xmlXPathNewFloat(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005807}
5808
5809/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005810 * xmlXPathParseLiteral:
5811 * @ctxt: the XPath Parser context
5812 *
5813 * Parse a Literal
5814 *
5815 * [29] Literal ::= '"' [^"]* '"'
5816 * | "'" [^']* "'"
5817 *
5818 * Returns the value found or NULL in case of error
5819 */
5820static xmlChar *
5821xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
5822 const xmlChar *q;
5823 xmlChar *ret = NULL;
5824
5825 if (CUR == '"') {
5826 NEXT;
5827 q = CUR_PTR;
5828 while ((IS_CHAR(CUR)) && (CUR != '"'))
5829 NEXT;
5830 if (!IS_CHAR(CUR)) {
5831 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5832 } else {
5833 ret = xmlStrndup(q, CUR_PTR - q);
5834 NEXT;
5835 }
5836 } else if (CUR == '\'') {
5837 NEXT;
5838 q = CUR_PTR;
5839 while ((IS_CHAR(CUR)) && (CUR != '\''))
5840 NEXT;
5841 if (!IS_CHAR(CUR)) {
5842 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
5843 } else {
5844 ret = xmlStrndup(q, CUR_PTR - q);
5845 NEXT;
5846 }
5847 } else {
5848 XP_ERROR0(XPATH_START_LITERAL_ERROR);
5849 }
5850 return(ret);
5851}
5852
5853/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005854 * xmlXPathCompLiteral:
Owen Taylor3473f882001-02-23 17:55:21 +00005855 * @ctxt: the XPath Parser context
5856 *
5857 * Parse a Literal and push it on the stack.
5858 *
5859 * [29] Literal ::= '"' [^"]* '"'
5860 * | "'" [^']* "'"
5861 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005862 * TODO: xmlXPathCompLiteral memory allocation could be improved.
Owen Taylor3473f882001-02-23 17:55:21 +00005863 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005864static void
5865xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005866 const xmlChar *q;
5867 xmlChar *ret = NULL;
5868
5869 if (CUR == '"') {
5870 NEXT;
5871 q = CUR_PTR;
5872 while ((IS_CHAR(CUR)) && (CUR != '"'))
5873 NEXT;
5874 if (!IS_CHAR(CUR)) {
5875 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5876 } else {
5877 ret = xmlStrndup(q, CUR_PTR - q);
5878 NEXT;
5879 }
5880 } else if (CUR == '\'') {
5881 NEXT;
5882 q = CUR_PTR;
5883 while ((IS_CHAR(CUR)) && (CUR != '\''))
5884 NEXT;
5885 if (!IS_CHAR(CUR)) {
5886 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
5887 } else {
5888 ret = xmlStrndup(q, CUR_PTR - q);
5889 NEXT;
5890 }
5891 } else {
5892 XP_ERROR(XPATH_START_LITERAL_ERROR);
5893 }
5894 if (ret == NULL) return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005895 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
5896 xmlXPathNewString(ret), NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00005897 xmlFree(ret);
5898}
5899
5900/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005901 * xmlXPathCompVariableReference:
Owen Taylor3473f882001-02-23 17:55:21 +00005902 * @ctxt: the XPath Parser context
5903 *
5904 * Parse a VariableReference, evaluate it and push it on the stack.
5905 *
5906 * The variable bindings consist of a mapping from variable names
5907 * to variable values. The value of a variable is an object, which
5908 * of any of the types that are possible for the value of an expression,
5909 * and may also be of additional types not specified here.
5910 *
5911 * Early evaluation is possible since:
5912 * The variable bindings [...] used to evaluate a subexpression are
5913 * always the same as those used to evaluate the containing expression.
5914 *
5915 * [36] VariableReference ::= '$' QName
5916 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005917static void
5918xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005919 xmlChar *name;
5920 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005921
5922 SKIP_BLANKS;
5923 if (CUR != '$') {
5924 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5925 }
5926 NEXT;
5927 name = xmlXPathParseQName(ctxt, &prefix);
5928 if (name == NULL) {
5929 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
5930 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00005931 ctxt->comp->last = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00005932 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
5933 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00005934 SKIP_BLANKS;
5935}
5936
5937/**
5938 * xmlXPathIsNodeType:
5939 * @ctxt: the XPath Parser context
5940 * @name: a name string
5941 *
5942 * Is the name given a NodeType one.
5943 *
5944 * [38] NodeType ::= 'comment'
5945 * | 'text'
5946 * | 'processing-instruction'
5947 * | 'node'
5948 *
5949 * Returns 1 if true 0 otherwise
5950 */
5951int
5952xmlXPathIsNodeType(const xmlChar *name) {
5953 if (name == NULL)
5954 return(0);
5955
5956 if (xmlStrEqual(name, BAD_CAST "comment"))
5957 return(1);
5958 if (xmlStrEqual(name, BAD_CAST "text"))
5959 return(1);
5960 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
5961 return(1);
5962 if (xmlStrEqual(name, BAD_CAST "node"))
5963 return(1);
5964 return(0);
5965}
5966
5967/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005968 * xmlXPathCompFunctionCall:
Owen Taylor3473f882001-02-23 17:55:21 +00005969 * @ctxt: the XPath Parser context
5970 *
5971 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
5972 * [17] Argument ::= Expr
5973 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005974 * Compile a function call, the evaluation of all arguments are
Owen Taylor3473f882001-02-23 17:55:21 +00005975 * pushed on the stack
5976 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00005977static void
5978xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00005979 xmlChar *name;
5980 xmlChar *prefix;
Owen Taylor3473f882001-02-23 17:55:21 +00005981 int nbargs = 0;
5982
5983 name = xmlXPathParseQName(ctxt, &prefix);
5984 if (name == NULL) {
5985 XP_ERROR(XPATH_EXPR_ERROR);
5986 }
5987 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00005988#ifdef DEBUG_EXPR
5989 if (prefix == NULL)
5990 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
5991 name);
5992 else
5993 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
5994 prefix, name);
5995#endif
5996
Owen Taylor3473f882001-02-23 17:55:21 +00005997 if (CUR != '(') {
5998 XP_ERROR(XPATH_EXPR_ERROR);
5999 }
6000 NEXT;
6001 SKIP_BLANKS;
6002
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006003 ctxt->comp->last = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00006004 while (CUR != ')') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006005 int op1 = ctxt->comp->last;
6006 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006007 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006008 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006009 nbargs++;
6010 if (CUR == ')') break;
6011 if (CUR != ',') {
6012 XP_ERROR(XPATH_EXPR_ERROR);
6013 }
6014 NEXT;
6015 SKIP_BLANKS;
6016 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006017 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
6018 name, prefix);
Owen Taylor3473f882001-02-23 17:55:21 +00006019 NEXT;
6020 SKIP_BLANKS;
Owen Taylor3473f882001-02-23 17:55:21 +00006021}
6022
6023/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006024 * xmlXPathCompPrimaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006025 * @ctxt: the XPath Parser context
6026 *
6027 * [15] PrimaryExpr ::= VariableReference
6028 * | '(' Expr ')'
6029 * | Literal
6030 * | Number
6031 * | FunctionCall
6032 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006033 * Compile a primary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006034 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006035static void
6036xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006037 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006038 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006039 else if (CUR == '(') {
6040 NEXT;
6041 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006042 xmlXPathCompileExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006043 if (CUR != ')') {
6044 XP_ERROR(XPATH_EXPR_ERROR);
6045 }
6046 NEXT;
6047 SKIP_BLANKS;
6048 } else if (IS_DIGIT(CUR)) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006049 xmlXPathCompNumber(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006050 } else if ((CUR == '\'') || (CUR == '"')) {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006051 xmlXPathCompLiteral(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006052 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006053 xmlXPathCompFunctionCall(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006054 }
6055 SKIP_BLANKS;
6056}
6057
6058/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006059 * xmlXPathCompFilterExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006060 * @ctxt: the XPath Parser context
6061 *
6062 * [20] FilterExpr ::= PrimaryExpr
6063 * | FilterExpr Predicate
6064 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006065 * Compile a filter expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006066 * Square brackets are used to filter expressions in the same way that
6067 * they are used in location paths. It is an error if the expression to
6068 * be filtered does not evaluate to a node-set. The context node list
6069 * used for evaluating the expression in square brackets is the node-set
6070 * to be filtered listed in document order.
6071 */
6072
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006073static void
6074xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
6075 xmlXPathCompPrimaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006076 CHECK_ERROR;
6077 SKIP_BLANKS;
6078
6079 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006080 xmlXPathCompPredicate(ctxt, 1);
Owen Taylor3473f882001-02-23 17:55:21 +00006081 SKIP_BLANKS;
6082 }
6083
6084
6085}
6086
6087/**
6088 * xmlXPathScanName:
6089 * @ctxt: the XPath Parser context
6090 *
6091 * Trickery: parse an XML name but without consuming the input flow
6092 * Needed to avoid insanity in the parser state.
6093 *
6094 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
6095 * CombiningChar | Extender
6096 *
6097 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
6098 *
6099 * [6] Names ::= Name (S Name)*
6100 *
6101 * Returns the Name parsed or NULL
6102 */
6103
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006104static xmlChar *
Owen Taylor3473f882001-02-23 17:55:21 +00006105xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
6106 xmlChar buf[XML_MAX_NAMELEN];
6107 int len = 0;
6108
6109 SKIP_BLANKS;
6110 if (!IS_LETTER(CUR) && (CUR != '_') &&
6111 (CUR != ':')) {
6112 return(NULL);
6113 }
6114
6115 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6116 (NXT(len) == '.') || (NXT(len) == '-') ||
6117 (NXT(len) == '_') || (NXT(len) == ':') ||
6118 (IS_COMBINING(NXT(len))) ||
6119 (IS_EXTENDER(NXT(len)))) {
6120 buf[len] = NXT(len);
6121 len++;
6122 if (len >= XML_MAX_NAMELEN) {
6123 xmlGenericError(xmlGenericErrorContext,
6124 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
6125 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
6126 (NXT(len) == '.') || (NXT(len) == '-') ||
6127 (NXT(len) == '_') || (NXT(len) == ':') ||
6128 (IS_COMBINING(NXT(len))) ||
6129 (IS_EXTENDER(NXT(len))))
6130 len++;
6131 break;
6132 }
6133 }
6134 return(xmlStrndup(buf, len));
6135}
6136
6137/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006138 * xmlXPathCompPathExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006139 * @ctxt: the XPath Parser context
6140 *
6141 * [19] PathExpr ::= LocationPath
6142 * | FilterExpr
6143 * | FilterExpr '/' RelativeLocationPath
6144 * | FilterExpr '//' RelativeLocationPath
6145 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006146 * Compile a path expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006147 * The / operator and // operators combine an arbitrary expression
6148 * and a relative location path. It is an error if the expression
6149 * does not evaluate to a node-set.
6150 * The / operator does composition in the same way as when / is
6151 * used in a location path. As in location paths, // is short for
6152 * /descendant-or-self::node()/.
6153 */
6154
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006155static void
6156xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006157 int lc = 1; /* Should we branch to LocationPath ? */
6158 xmlChar *name = NULL; /* we may have to preparse a name to find out */
6159
6160 SKIP_BLANKS;
6161 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
6162 (CUR == '\'') || (CUR == '"')) {
6163 lc = 0;
6164 } else if (CUR == '*') {
6165 /* relative or absolute location path */
6166 lc = 1;
6167 } else if (CUR == '/') {
6168 /* relative or absolute location path */
6169 lc = 1;
6170 } else if (CUR == '@') {
6171 /* relative abbreviated attribute location path */
6172 lc = 1;
6173 } else if (CUR == '.') {
6174 /* relative abbreviated attribute location path */
6175 lc = 1;
6176 } else {
6177 /*
6178 * Problem is finding if we have a name here whether it's:
6179 * - a nodetype
6180 * - a function call in which case it's followed by '('
6181 * - an axis in which case it's followed by ':'
6182 * - a element name
6183 * We do an a priori analysis here rather than having to
6184 * maintain parsed token content through the recursive function
6185 * calls. This looks uglier but makes the code quite easier to
6186 * read/write/debug.
6187 */
6188 SKIP_BLANKS;
6189 name = xmlXPathScanName(ctxt);
6190 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
6191#ifdef DEBUG_STEP
6192 xmlGenericError(xmlGenericErrorContext,
6193 "PathExpr: Axis\n");
6194#endif
6195 lc = 1;
6196 xmlFree(name);
6197 } else if (name != NULL) {
6198 int len =xmlStrlen(name);
6199 int blank = 0;
6200
6201
6202 while (NXT(len) != 0) {
6203 if (NXT(len) == '/') {
6204 /* element name */
6205#ifdef DEBUG_STEP
6206 xmlGenericError(xmlGenericErrorContext,
6207 "PathExpr: AbbrRelLocation\n");
6208#endif
6209 lc = 1;
6210 break;
6211 } else if (IS_BLANK(NXT(len))) {
6212 /* skip to next */
6213 blank = 1;
6214 } else if (NXT(len) == ':') {
6215#ifdef DEBUG_STEP
6216 xmlGenericError(xmlGenericErrorContext,
6217 "PathExpr: AbbrRelLocation\n");
6218#endif
6219 lc = 1;
6220 break;
6221 } else if ((NXT(len) == '(')) {
6222 /* Note Type or Function */
6223 if (xmlXPathIsNodeType(name)) {
6224#ifdef DEBUG_STEP
6225 xmlGenericError(xmlGenericErrorContext,
6226 "PathExpr: Type search\n");
6227#endif
6228 lc = 1;
6229 } else {
6230#ifdef DEBUG_STEP
6231 xmlGenericError(xmlGenericErrorContext,
6232 "PathExpr: function call\n");
6233#endif
6234 lc = 0;
6235 }
6236 break;
6237 } else if ((NXT(len) == '[')) {
6238 /* element name */
6239#ifdef DEBUG_STEP
6240 xmlGenericError(xmlGenericErrorContext,
6241 "PathExpr: AbbrRelLocation\n");
6242#endif
6243 lc = 1;
6244 break;
6245 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
6246 (NXT(len) == '=')) {
6247 lc = 1;
6248 break;
6249 } else {
6250 lc = 1;
6251 break;
6252 }
6253 len++;
6254 }
6255 if (NXT(len) == 0) {
6256#ifdef DEBUG_STEP
6257 xmlGenericError(xmlGenericErrorContext,
6258 "PathExpr: AbbrRelLocation\n");
6259#endif
6260 /* element name */
6261 lc = 1;
6262 }
6263 xmlFree(name);
6264 } else {
6265 /* make sure all cases are covered explicitely */
6266 XP_ERROR(XPATH_EXPR_ERROR);
6267 }
6268 }
6269
6270 if (lc) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006271 if (CUR == '/') {
6272 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
6273 } else {
6274 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006275 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006276 xmlXPathCompLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006277 } else {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006278 xmlXPathCompFilterExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006279 CHECK_ERROR;
6280 if ((CUR == '/') && (NXT(1) == '/')) {
6281 SKIP(2);
6282 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006283
6284 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6285 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
6286 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
6287
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006288 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006289 } else if (CUR == '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006290 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006291 }
6292 }
6293 SKIP_BLANKS;
6294}
6295
6296/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006297 * xmlXPathCompUnionExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006298 * @ctxt: the XPath Parser context
6299 *
6300 * [18] UnionExpr ::= PathExpr
6301 * | UnionExpr '|' PathExpr
6302 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006303 * Compile an union expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006304 */
6305
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006306static void
6307xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
6308 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006309 CHECK_ERROR;
6310 SKIP_BLANKS;
6311 while (CUR == '|') {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006312 int op1 = ctxt->comp->last;
6313 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006314
6315 NEXT;
6316 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006317 xmlXPathCompPathExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006318
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006319 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
6320
Owen Taylor3473f882001-02-23 17:55:21 +00006321 SKIP_BLANKS;
6322 }
Owen Taylor3473f882001-02-23 17:55:21 +00006323}
6324
6325/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006326 * xmlXPathCompUnaryExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006327 * @ctxt: the XPath Parser context
6328 *
6329 * [27] UnaryExpr ::= UnionExpr
6330 * | '-' UnaryExpr
6331 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006332 * Compile an unary expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006333 */
6334
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006335static void
6336xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00006337 int minus = 0;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006338 int found = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006339
6340 SKIP_BLANKS;
Daniel Veillard68d7b672001-03-12 18:22:04 +00006341 while (CUR == '-') {
6342 minus = 1 - minus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006343 found = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006344 NEXT;
6345 SKIP_BLANKS;
6346 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006347
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006348 xmlXPathCompUnionExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006349 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006350 if (found) {
6351 if (minus)
6352 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
6353 else
6354 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006355 }
6356}
6357
6358/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006359 * xmlXPathCompMultiplicativeExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006360 * @ctxt: the XPath Parser context
6361 *
6362 * [26] MultiplicativeExpr ::= UnaryExpr
6363 * | MultiplicativeExpr MultiplyOperator UnaryExpr
6364 * | MultiplicativeExpr 'div' UnaryExpr
6365 * | MultiplicativeExpr 'mod' UnaryExpr
6366 * [34] MultiplyOperator ::= '*'
6367 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006368 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006369 */
6370
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006371static void
6372xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
6373 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006374 CHECK_ERROR;
6375 SKIP_BLANKS;
6376 while ((CUR == '*') ||
6377 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
6378 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
6379 int op = -1;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006380 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006381
6382 if (CUR == '*') {
6383 op = 0;
6384 NEXT;
6385 } else if (CUR == 'd') {
6386 op = 1;
6387 SKIP(3);
6388 } else if (CUR == 'm') {
6389 op = 2;
6390 SKIP(3);
6391 }
6392 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006393 xmlXPathCompUnaryExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006394 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006395 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006396 SKIP_BLANKS;
6397 }
6398}
6399
6400/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006401 * xmlXPathCompAdditiveExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006402 * @ctxt: the XPath Parser context
6403 *
6404 * [25] AdditiveExpr ::= MultiplicativeExpr
6405 * | AdditiveExpr '+' MultiplicativeExpr
6406 * | AdditiveExpr '-' MultiplicativeExpr
6407 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006408 * Compile an Additive expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006409 */
6410
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006411static void
6412xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006413
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006414 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006415 CHECK_ERROR;
6416 SKIP_BLANKS;
6417 while ((CUR == '+') || (CUR == '-')) {
6418 int plus;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006419 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006420
6421 if (CUR == '+') plus = 1;
6422 else plus = 0;
6423 NEXT;
6424 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006425 xmlXPathCompMultiplicativeExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006426 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006427 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006428 SKIP_BLANKS;
6429 }
6430}
6431
6432/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006433 * xmlXPathCompRelationalExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006434 * @ctxt: the XPath Parser context
6435 *
6436 * [24] RelationalExpr ::= AdditiveExpr
6437 * | RelationalExpr '<' AdditiveExpr
6438 * | RelationalExpr '>' AdditiveExpr
6439 * | RelationalExpr '<=' AdditiveExpr
6440 * | RelationalExpr '>=' AdditiveExpr
6441 *
6442 * A <= B > C is allowed ? Answer from James, yes with
6443 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
6444 * which is basically what got implemented.
6445 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006446 * Compile a Relational expression, then push the result
Owen Taylor3473f882001-02-23 17:55:21 +00006447 * on the stack
6448 */
6449
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006450static void
6451xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
6452 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006453 CHECK_ERROR;
6454 SKIP_BLANKS;
6455 while ((CUR == '<') ||
6456 (CUR == '>') ||
6457 ((CUR == '<') && (NXT(1) == '=')) ||
6458 ((CUR == '>') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006459 int inf, strict;
6460 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006461
6462 if (CUR == '<') inf = 1;
6463 else inf = 0;
6464 if (NXT(1) == '=') strict = 0;
6465 else strict = 1;
6466 NEXT;
6467 if (!strict) NEXT;
6468 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006469 xmlXPathCompAdditiveExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006470 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006471 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
Owen Taylor3473f882001-02-23 17:55:21 +00006472 SKIP_BLANKS;
6473 }
6474}
6475
6476/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006477 * xmlXPathCompEqualityExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006478 * @ctxt: the XPath Parser context
6479 *
6480 * [23] EqualityExpr ::= RelationalExpr
6481 * | EqualityExpr '=' RelationalExpr
6482 * | EqualityExpr '!=' RelationalExpr
6483 *
6484 * A != B != C is allowed ? Answer from James, yes with
6485 * (RelationalExpr = RelationalExpr) = RelationalExpr
6486 * (RelationalExpr != RelationalExpr) != RelationalExpr
6487 * which is basically what got implemented.
6488 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006489 * Compile an Equality expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006490 *
6491 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006492static void
6493xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
6494 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006495 CHECK_ERROR;
6496 SKIP_BLANKS;
6497 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006498 int eq;
6499 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006500
6501 if (CUR == '=') eq = 1;
6502 else eq = 0;
6503 NEXT;
6504 if (!eq) NEXT;
6505 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006506 xmlXPathCompRelationalExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006507 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006508 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006509 SKIP_BLANKS;
6510 }
6511}
6512
6513/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006514 * xmlXPathCompAndExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006515 * @ctxt: the XPath Parser context
6516 *
6517 * [22] AndExpr ::= EqualityExpr
6518 * | AndExpr 'and' EqualityExpr
6519 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006520 * Compile an AND expression.
Owen Taylor3473f882001-02-23 17:55:21 +00006521 *
6522 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006523static void
6524xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
6525 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006526 CHECK_ERROR;
6527 SKIP_BLANKS;
6528 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006529 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006530 SKIP(3);
6531 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006532 xmlXPathCompEqualityExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006533 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006534 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006535 SKIP_BLANKS;
6536 }
6537}
6538
6539/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006540 * xmlXPathCompExpr:
Owen Taylor3473f882001-02-23 17:55:21 +00006541 * @ctxt: the XPath Parser context
6542 *
6543 * [14] Expr ::= OrExpr
6544 * [21] OrExpr ::= AndExpr
6545 * | OrExpr 'or' AndExpr
6546 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006547 * Parse and compile an expression
Owen Taylor3473f882001-02-23 17:55:21 +00006548 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006549static void
6550xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
6551 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006552 CHECK_ERROR;
6553 SKIP_BLANKS;
6554 while ((CUR == 'o') && (NXT(1) == 'r')) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006555 int op1 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006556 SKIP(2);
6557 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006558 xmlXPathCompAndExpr(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00006559 CHECK_ERROR;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006560 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
6561 op1 = ctxt->comp->nbStep;
Owen Taylor3473f882001-02-23 17:55:21 +00006562 SKIP_BLANKS;
6563 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006564 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
6565 /* more ops could be optimized too */
6566 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
6567 }
Owen Taylor3473f882001-02-23 17:55:21 +00006568}
6569
6570/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006571 * xmlXPathCompPredicate:
Owen Taylor3473f882001-02-23 17:55:21 +00006572 * @ctxt: the XPath Parser context
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006573 * @filter: act as a filter
Owen Taylor3473f882001-02-23 17:55:21 +00006574 *
6575 * [8] Predicate ::= '[' PredicateExpr ']'
6576 * [9] PredicateExpr ::= Expr
6577 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006578 * Compile a predicate expression
Owen Taylor3473f882001-02-23 17:55:21 +00006579 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006580static void
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006581xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006582 int op1 = ctxt->comp->last;
6583
6584 SKIP_BLANKS;
6585 if (CUR != '[') {
6586 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6587 }
6588 NEXT;
6589 SKIP_BLANKS;
6590
6591 ctxt->comp->last = -1;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006592 xmlXPathCompileExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006593 CHECK_ERROR;
6594
6595 if (CUR != ']') {
6596 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
6597 }
6598
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006599 if (filter)
6600 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
6601 else
6602 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006603
6604 NEXT;
6605 SKIP_BLANKS;
6606}
6607
6608/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006609 * xmlXPathCompNodeTest:
Owen Taylor3473f882001-02-23 17:55:21 +00006610 * @ctxt: the XPath Parser context
6611 * @test: pointer to a xmlXPathTestVal
6612 * @type: pointer to a xmlXPathTypeVal
6613 * @prefix: placeholder for a possible name prefix
6614 *
6615 * [7] NodeTest ::= NameTest
6616 * | NodeType '(' ')'
6617 * | 'processing-instruction' '(' Literal ')'
6618 *
6619 * [37] NameTest ::= '*'
6620 * | NCName ':' '*'
6621 * | QName
6622 * [38] NodeType ::= 'comment'
6623 * | 'text'
6624 * | 'processing-instruction'
6625 * | 'node'
6626 *
6627 * Returns the name found and update @test, @type and @prefix appropriately
6628 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006629static xmlChar *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006630xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
6631 xmlXPathTypeVal *type, const xmlChar **prefix,
6632 xmlChar *name) {
Owen Taylor3473f882001-02-23 17:55:21 +00006633 int blanks;
6634
6635 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
6636 STRANGE;
6637 return(NULL);
6638 }
6639 *type = 0;
6640 *test = 0;
6641 *prefix = NULL;
6642 SKIP_BLANKS;
6643
6644 if ((name == NULL) && (CUR == '*')) {
6645 /*
6646 * All elements
6647 */
6648 NEXT;
6649 *test = NODE_TEST_ALL;
6650 return(NULL);
6651 }
6652
6653 if (name == NULL)
6654 name = xmlXPathParseNCName(ctxt);
6655 if (name == NULL) {
6656 XP_ERROR0(XPATH_EXPR_ERROR);
6657 }
6658
6659 blanks = IS_BLANK(CUR);
6660 SKIP_BLANKS;
6661 if (CUR == '(') {
6662 NEXT;
6663 /*
6664 * NodeType or PI search
6665 */
6666 if (xmlStrEqual(name, BAD_CAST "comment"))
6667 *type = NODE_TYPE_COMMENT;
6668 else if (xmlStrEqual(name, BAD_CAST "node"))
6669 *type = NODE_TYPE_NODE;
6670 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
6671 *type = NODE_TYPE_PI;
6672 else if (xmlStrEqual(name, BAD_CAST "text"))
6673 *type = NODE_TYPE_TEXT;
6674 else {
6675 if (name != NULL)
6676 xmlFree(name);
6677 XP_ERROR0(XPATH_EXPR_ERROR);
6678 }
6679
6680 *test = NODE_TEST_TYPE;
6681
6682 SKIP_BLANKS;
6683 if (*type == NODE_TYPE_PI) {
6684 /*
6685 * Specific case: search a PI by name.
6686 */
Owen Taylor3473f882001-02-23 17:55:21 +00006687 if (name != NULL)
6688 xmlFree(name);
Daniel Veillard82e49712001-04-26 14:38:03 +00006689 name = NULL;
6690 if (CUR != ')') {
6691 name = xmlXPathParseLiteral(ctxt);
6692 CHECK_ERROR 0;
6693 SKIP_BLANKS;
6694 }
Owen Taylor3473f882001-02-23 17:55:21 +00006695 }
6696 if (CUR != ')') {
6697 if (name != NULL)
6698 xmlFree(name);
6699 XP_ERROR0(XPATH_UNCLOSED_ERROR);
6700 }
6701 NEXT;
6702 return(name);
6703 }
6704 *test = NODE_TEST_NAME;
6705 if ((!blanks) && (CUR == ':')) {
6706 NEXT;
6707
6708 /*
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006709 * Since currently the parser context don't have a
6710 * namespace list associated:
6711 * The namespace name for this prefix can be computed
6712 * only at evaluation time. The compilation is done
6713 * outside of any context.
Owen Taylor3473f882001-02-23 17:55:21 +00006714 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006715#if 0
Owen Taylor3473f882001-02-23 17:55:21 +00006716 *prefix = xmlXPathNsLookup(ctxt->context, name);
6717 if (name != NULL)
6718 xmlFree(name);
6719 if (*prefix == NULL) {
6720 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
6721 }
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006722#else
6723 *prefix = name;
6724#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006725
6726 if (CUR == '*') {
6727 /*
6728 * All elements
6729 */
6730 NEXT;
6731 *test = NODE_TEST_ALL;
6732 return(NULL);
6733 }
6734
6735 name = xmlXPathParseNCName(ctxt);
6736 if (name == NULL) {
6737 XP_ERROR0(XPATH_EXPR_ERROR);
6738 }
6739 }
6740 return(name);
6741}
6742
6743/**
6744 * xmlXPathIsAxisName:
6745 * @name: a preparsed name token
6746 *
6747 * [6] AxisName ::= 'ancestor'
6748 * | 'ancestor-or-self'
6749 * | 'attribute'
6750 * | 'child'
6751 * | 'descendant'
6752 * | 'descendant-or-self'
6753 * | 'following'
6754 * | 'following-sibling'
6755 * | 'namespace'
6756 * | 'parent'
6757 * | 'preceding'
6758 * | 'preceding-sibling'
6759 * | 'self'
6760 *
6761 * Returns the axis or 0
6762 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00006763static xmlXPathAxisVal
Owen Taylor3473f882001-02-23 17:55:21 +00006764xmlXPathIsAxisName(const xmlChar *name) {
6765 xmlXPathAxisVal ret = 0;
6766 switch (name[0]) {
6767 case 'a':
6768 if (xmlStrEqual(name, BAD_CAST "ancestor"))
6769 ret = AXIS_ANCESTOR;
6770 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
6771 ret = AXIS_ANCESTOR_OR_SELF;
6772 if (xmlStrEqual(name, BAD_CAST "attribute"))
6773 ret = AXIS_ATTRIBUTE;
6774 break;
6775 case 'c':
6776 if (xmlStrEqual(name, BAD_CAST "child"))
6777 ret = AXIS_CHILD;
6778 break;
6779 case 'd':
6780 if (xmlStrEqual(name, BAD_CAST "descendant"))
6781 ret = AXIS_DESCENDANT;
6782 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
6783 ret = AXIS_DESCENDANT_OR_SELF;
6784 break;
6785 case 'f':
6786 if (xmlStrEqual(name, BAD_CAST "following"))
6787 ret = AXIS_FOLLOWING;
6788 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
6789 ret = AXIS_FOLLOWING_SIBLING;
6790 break;
6791 case 'n':
6792 if (xmlStrEqual(name, BAD_CAST "namespace"))
6793 ret = AXIS_NAMESPACE;
6794 break;
6795 case 'p':
6796 if (xmlStrEqual(name, BAD_CAST "parent"))
6797 ret = AXIS_PARENT;
6798 if (xmlStrEqual(name, BAD_CAST "preceding"))
6799 ret = AXIS_PRECEDING;
6800 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
6801 ret = AXIS_PRECEDING_SIBLING;
6802 break;
6803 case 's':
6804 if (xmlStrEqual(name, BAD_CAST "self"))
6805 ret = AXIS_SELF;
6806 break;
6807 }
6808 return(ret);
6809}
6810
6811/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006812 * xmlXPathCompStep:
Owen Taylor3473f882001-02-23 17:55:21 +00006813 * @ctxt: the XPath Parser context
6814 *
6815 * [4] Step ::= AxisSpecifier NodeTest Predicate*
6816 * | AbbreviatedStep
6817 *
6818 * [12] AbbreviatedStep ::= '.' | '..'
6819 *
6820 * [5] AxisSpecifier ::= AxisName '::'
6821 * | AbbreviatedAxisSpecifier
6822 *
6823 * [13] AbbreviatedAxisSpecifier ::= '@'?
6824 *
6825 * Modified for XPtr range support as:
6826 *
6827 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
6828 * | AbbreviatedStep
6829 * | 'range-to' '(' Expr ')' Predicate*
6830 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006831 * Compile one step in a Location Path
Owen Taylor3473f882001-02-23 17:55:21 +00006832 * A location step of . is short for self::node(). This is
6833 * particularly useful in conjunction with //. For example, the
6834 * location path .//para is short for
6835 * self::node()/descendant-or-self::node()/child::para
6836 * and so will select all para descendant elements of the context
6837 * node.
6838 * Similarly, a location step of .. is short for parent::node().
6839 * For example, ../title is short for parent::node()/child::title
6840 * and so will select the title children of the parent of the context
6841 * node.
6842 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006843static void
6844xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006845#ifdef LIBXML_XPTR_ENABLED
6846 int rangeto = 0;
6847 int op2 = -1;
6848#endif
6849
Owen Taylor3473f882001-02-23 17:55:21 +00006850 SKIP_BLANKS;
6851 if ((CUR == '.') && (NXT(1) == '.')) {
6852 SKIP(2);
6853 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006854 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
6855 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00006856 } else if (CUR == '.') {
6857 NEXT;
6858 SKIP_BLANKS;
6859 } else {
6860 xmlChar *name = NULL;
6861 const xmlChar *prefix = NULL;
6862 xmlXPathTestVal test;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006863 xmlXPathAxisVal axis = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00006864 xmlXPathTypeVal type;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006865 int op1;
Owen Taylor3473f882001-02-23 17:55:21 +00006866
6867 /*
6868 * The modification needed for XPointer change to the production
6869 */
6870#ifdef LIBXML_XPTR_ENABLED
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00006871 if (ctxt->xptr) {
Owen Taylor3473f882001-02-23 17:55:21 +00006872 name = xmlXPathParseNCName(ctxt);
6873 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006874 op2 = ctxt->comp->last;
Owen Taylor3473f882001-02-23 17:55:21 +00006875 xmlFree(name);
6876 SKIP_BLANKS;
6877 if (CUR != '(') {
6878 XP_ERROR(XPATH_EXPR_ERROR);
6879 }
6880 NEXT;
6881 SKIP_BLANKS;
6882
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006883 xmlXPathCompileExpr(ctxt);
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006884 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
Owen Taylor3473f882001-02-23 17:55:21 +00006885 CHECK_ERROR;
6886
6887 SKIP_BLANKS;
6888 if (CUR != ')') {
6889 XP_ERROR(XPATH_EXPR_ERROR);
6890 }
6891 NEXT;
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006892 rangeto = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00006893 goto eval_predicates;
6894 }
6895 }
6896#endif
Daniel Veillard2156a562001-04-28 12:24:34 +00006897 if (CUR == '*') {
6898 axis = AXIS_CHILD;
6899 } else {
6900 if (name == NULL)
6901 name = xmlXPathParseNCName(ctxt);
6902 if (name != NULL) {
6903 axis = xmlXPathIsAxisName(name);
6904 if (axis != 0) {
6905 SKIP_BLANKS;
6906 if ((CUR == ':') && (NXT(1) == ':')) {
6907 SKIP(2);
6908 xmlFree(name);
6909 name = NULL;
6910 } else {
6911 /* an element name can conflict with an axis one :-\ */
6912 axis = AXIS_CHILD;
6913 }
Owen Taylor3473f882001-02-23 17:55:21 +00006914 } else {
Owen Taylor3473f882001-02-23 17:55:21 +00006915 axis = AXIS_CHILD;
6916 }
Daniel Veillard2156a562001-04-28 12:24:34 +00006917 } else if (CUR == '@') {
6918 NEXT;
6919 axis = AXIS_ATTRIBUTE;
Owen Taylor3473f882001-02-23 17:55:21 +00006920 } else {
Daniel Veillard2156a562001-04-28 12:24:34 +00006921 axis = AXIS_CHILD;
Owen Taylor3473f882001-02-23 17:55:21 +00006922 }
Owen Taylor3473f882001-02-23 17:55:21 +00006923 }
6924
6925 CHECK_ERROR;
6926
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006927 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
Owen Taylor3473f882001-02-23 17:55:21 +00006928 if (test == 0)
6929 return;
6930
6931#ifdef DEBUG_STEP
6932 xmlGenericError(xmlGenericErrorContext,
6933 "Basis : computing new set\n");
6934#endif
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006935
Owen Taylor3473f882001-02-23 17:55:21 +00006936#ifdef DEBUG_STEP
6937 xmlGenericError(xmlGenericErrorContext, "Basis : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006938 if (ctxt->value == NULL)
6939 xmlGenericError(xmlGenericErrorContext, "no value\n");
6940 else if (ctxt->value->nodesetval == NULL)
6941 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6942 else
6943 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006944#endif
Owen Taylor3473f882001-02-23 17:55:21 +00006945
6946eval_predicates:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006947 op1 = ctxt->comp->last;
6948 ctxt->comp->last = -1;
6949
Owen Taylor3473f882001-02-23 17:55:21 +00006950 SKIP_BLANKS;
6951 while (CUR == '[') {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006952 xmlXPathCompPredicate(ctxt, 0);
Owen Taylor3473f882001-02-23 17:55:21 +00006953 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006954
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006955#ifdef LIBXML_XPTR_ENABLED
6956 if (rangeto) {
6957 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
6958 } else
6959#endif
6960 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
6961 test, type, (void *)prefix, (void *)name);
Daniel Veillardd8df6c02001-04-05 16:54:14 +00006962
Owen Taylor3473f882001-02-23 17:55:21 +00006963 }
6964#ifdef DEBUG_STEP
6965 xmlGenericError(xmlGenericErrorContext, "Step : ");
Daniel Veillardfd0c3eb2001-04-22 19:13:10 +00006966 if (ctxt->value == NULL)
6967 xmlGenericError(xmlGenericErrorContext, "no value\n");
6968 else if (ctxt->value->nodesetval == NULL)
6969 xmlGenericError(xmlGenericErrorContext, "Empty\n");
6970 else
6971 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
6972 ctxt->value->nodesetval);
Owen Taylor3473f882001-02-23 17:55:21 +00006973#endif
6974}
6975
6976/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006977 * xmlXPathCompRelativeLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00006978 * @ctxt: the XPath Parser context
6979 *
6980 * [3] RelativeLocationPath ::= Step
6981 * | RelativeLocationPath '/' Step
6982 * | AbbreviatedRelativeLocationPath
6983 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
6984 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006985 * Compile a relative location path.
Owen Taylor3473f882001-02-23 17:55:21 +00006986 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006987static void
Owen Taylor3473f882001-02-23 17:55:21 +00006988#ifdef VMS
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006989xmlXPathCompRelLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006990#else
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00006991xmlXPathCompRelativeLocationPath
Owen Taylor3473f882001-02-23 17:55:21 +00006992#endif
6993(xmlXPathParserContextPtr ctxt) {
6994 SKIP_BLANKS;
6995 if ((CUR == '/') && (NXT(1) == '/')) {
6996 SKIP(2);
6997 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00006998 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
6999 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00007000 } else if (CUR == '/') {
7001 NEXT;
7002 SKIP_BLANKS;
7003 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007004 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007005 SKIP_BLANKS;
7006 while (CUR == '/') {
7007 if ((CUR == '/') && (NXT(1) == '/')) {
7008 SKIP(2);
7009 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007010 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
Owen Taylor3473f882001-02-23 17:55:21 +00007011 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007012 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007013 } else if (CUR == '/') {
7014 NEXT;
7015 SKIP_BLANKS;
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007016 xmlXPathCompStep(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007017 }
7018 SKIP_BLANKS;
7019 }
7020}
7021
7022/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007023 * xmlXPathCompLocationPath:
Owen Taylor3473f882001-02-23 17:55:21 +00007024 * @ctxt: the XPath Parser context
7025 *
7026 * [1] LocationPath ::= RelativeLocationPath
7027 * | AbsoluteLocationPath
7028 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
7029 * | AbbreviatedAbsoluteLocationPath
7030 * [10] AbbreviatedAbsoluteLocationPath ::=
7031 * '//' RelativeLocationPath
7032 *
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007033 * Compile a location path
7034 *
Owen Taylor3473f882001-02-23 17:55:21 +00007035 * // is short for /descendant-or-self::node()/. For example,
7036 * //para is short for /descendant-or-self::node()/child::para and
7037 * so will select any para element in the document (even a para element
7038 * that is a document element will be selected by //para since the
7039 * document element node is a child of the root node); div//para is
7040 * short for div/descendant-or-self::node()/child::para and so will
7041 * select all para descendants of div children.
7042 */
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007043static void
7044xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
Owen Taylor3473f882001-02-23 17:55:21 +00007045 SKIP_BLANKS;
7046 if (CUR != '/') {
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007047 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007048 } else {
7049 while (CUR == '/') {
7050 if ((CUR == '/') && (NXT(1) == '/')) {
7051 SKIP(2);
7052 SKIP_BLANKS;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007053 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
7054 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007055 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007056 } else if (CUR == '/') {
7057 NEXT;
7058 SKIP_BLANKS;
7059 if (CUR != 0)
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007060 xmlXPathCompRelativeLocationPath(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00007061 }
7062 }
7063 }
7064}
7065
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007066/************************************************************************
7067 * *
7068 * XPath precompiled expression evaluation *
7069 * *
7070 ************************************************************************/
7071
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007072static void
7073xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
7074
7075/**
7076 * xmlXPathNodeCollectAndTest:
7077 * @ctxt: the XPath Parser context
7078 * @op: the XPath precompiled step operation
7079 *
7080 * This is the function implementing a step: based on the current list
7081 * of nodes, it builds up a new list, looking at all nodes under that
7082 * axis and selecting them it also do the predicate filtering
7083 *
7084 * Pushes the new NodeSet resulting from the search.
7085 */
7086static void
7087xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
7088 xmlXPathStepOpPtr op) {
7089 xmlXPathAxisVal axis = op->value;
7090 xmlXPathTestVal test = op->value2;
7091 xmlXPathTypeVal type = op->value3;
7092 const xmlChar *prefix = op->value4;
7093 const xmlChar *name = op->value5;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007094 const xmlChar *URI = NULL;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007095
7096#ifdef DEBUG_STEP
7097 int n = 0, t = 0;
7098#endif
7099 int i;
7100 xmlNodeSetPtr ret, list;
7101 xmlXPathTraversalFunction next = NULL;
7102 void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
7103 xmlNodePtr cur = NULL;
7104 xmlXPathObjectPtr obj;
7105 xmlNodeSetPtr nodelist;
7106 xmlNodePtr tmp;
7107
7108 CHECK_TYPE(XPATH_NODESET);
7109 obj = valuePop(ctxt);
7110 addNode = xmlXPathNodeSetAdd;
Daniel Veillarde043ee12001-04-16 14:08:07 +00007111 if (prefix != NULL) {
7112 URI = xmlXPathNsLookup(ctxt->context, prefix);
7113 if (URI == NULL)
7114 XP_ERROR(XPATH_UNDEF_PREFIX_ERROR);
7115 }
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007116
7117#ifdef DEBUG_STEP
7118 xmlGenericError(xmlGenericErrorContext,
7119 "new step : ");
7120#endif
7121 switch (axis) {
7122 case AXIS_ANCESTOR:
7123#ifdef DEBUG_STEP
7124 xmlGenericError(xmlGenericErrorContext,
7125 "axis 'ancestors' ");
7126#endif
7127 next = xmlXPathNextAncestor; break;
7128 case AXIS_ANCESTOR_OR_SELF:
7129#ifdef DEBUG_STEP
7130 xmlGenericError(xmlGenericErrorContext,
7131 "axis 'ancestors-or-self' ");
7132#endif
7133 next = xmlXPathNextAncestorOrSelf; break;
7134 case AXIS_ATTRIBUTE:
7135#ifdef DEBUG_STEP
7136 xmlGenericError(xmlGenericErrorContext,
7137 "axis 'attributes' ");
7138#endif
7139 next = xmlXPathNextAttribute; break;
7140 break;
7141 case AXIS_CHILD:
7142#ifdef DEBUG_STEP
7143 xmlGenericError(xmlGenericErrorContext,
7144 "axis 'child' ");
7145#endif
7146 next = xmlXPathNextChild; break;
7147 case AXIS_DESCENDANT:
7148#ifdef DEBUG_STEP
7149 xmlGenericError(xmlGenericErrorContext,
7150 "axis 'descendant' ");
7151#endif
7152 next = xmlXPathNextDescendant; break;
7153 case AXIS_DESCENDANT_OR_SELF:
7154#ifdef DEBUG_STEP
7155 xmlGenericError(xmlGenericErrorContext,
7156 "axis 'descendant-or-self' ");
7157#endif
7158 next = xmlXPathNextDescendantOrSelf; break;
7159 case AXIS_FOLLOWING:
7160#ifdef DEBUG_STEP
7161 xmlGenericError(xmlGenericErrorContext,
7162 "axis 'following' ");
7163#endif
7164 next = xmlXPathNextFollowing; break;
7165 case AXIS_FOLLOWING_SIBLING:
7166#ifdef DEBUG_STEP
7167 xmlGenericError(xmlGenericErrorContext,
7168 "axis 'following-siblings' ");
7169#endif
7170 next = xmlXPathNextFollowingSibling; break;
7171 case AXIS_NAMESPACE:
7172#ifdef DEBUG_STEP
7173 xmlGenericError(xmlGenericErrorContext,
7174 "axis 'namespace' ");
7175#endif
7176 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
7177 break;
7178 case AXIS_PARENT:
7179#ifdef DEBUG_STEP
7180 xmlGenericError(xmlGenericErrorContext,
7181 "axis 'parent' ");
7182#endif
7183 next = xmlXPathNextParent; break;
7184 case AXIS_PRECEDING:
7185#ifdef DEBUG_STEP
7186 xmlGenericError(xmlGenericErrorContext,
7187 "axis 'preceding' ");
7188#endif
7189 next = xmlXPathNextPreceding; break;
7190 case AXIS_PRECEDING_SIBLING:
7191#ifdef DEBUG_STEP
7192 xmlGenericError(xmlGenericErrorContext,
7193 "axis 'preceding-sibling' ");
7194#endif
7195 next = xmlXPathNextPrecedingSibling; break;
7196 case AXIS_SELF:
7197#ifdef DEBUG_STEP
7198 xmlGenericError(xmlGenericErrorContext,
7199 "axis 'self' ");
7200#endif
7201 next = xmlXPathNextSelf; break;
7202 }
7203 if (next == NULL)
7204 return;
7205
7206 nodelist = obj->nodesetval;
7207 if (nodelist == NULL) {
7208 xmlXPathFreeObject(obj);
7209 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
7210 return;
7211 }
7212 addNode = xmlXPathNodeSetAddUnique;
7213 ret = NULL;
7214#ifdef DEBUG_STEP
7215 xmlGenericError(xmlGenericErrorContext,
7216 " context contains %d nodes\n",
7217 nodelist->nodeNr);
7218 switch (test) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007219 case NODE_TEST_NONE:
7220 xmlGenericError(xmlGenericErrorContext,
7221 " searching for none !!!\n");
7222 break;
7223 case NODE_TEST_TYPE:
7224 xmlGenericError(xmlGenericErrorContext,
7225 " searching for type %d\n", type);
7226 break;
7227 case NODE_TEST_PI:
7228 xmlGenericError(xmlGenericErrorContext,
7229 " searching for PI !!!\n");
7230 break;
7231 case NODE_TEST_ALL:
7232 xmlGenericError(xmlGenericErrorContext,
7233 " searching for *\n");
7234 break;
7235 case NODE_TEST_NS:
7236 xmlGenericError(xmlGenericErrorContext,
7237 " searching for namespace %s\n",
7238 prefix);
7239 break;
7240 case NODE_TEST_NAME:
7241 xmlGenericError(xmlGenericErrorContext,
7242 " searching for name %s\n", name);
7243 if (prefix != NULL)
7244 xmlGenericError(xmlGenericErrorContext,
7245 " with namespace %s\n",
7246 prefix);
7247 break;
7248 }
7249 xmlGenericError(xmlGenericErrorContext, "Testing : ");
7250#endif
7251 /*
7252 * 2.3 Node Tests
7253 * - For the attribute axis, the principal node type is attribute.
7254 * - For the namespace axis, the principal node type is namespace.
7255 * - For other axes, the principal node type is element.
7256 *
7257 * A node test * is true for any node of the
7258 * principal node type. For example, child::* willi
7259 * select all element children of the context node
7260 */
7261 tmp = ctxt->context->node;
7262 for (i = 0;i < nodelist->nodeNr; i++) {
7263 ctxt->context->node = nodelist->nodeTab[i];
7264
7265 cur = NULL;
7266 list = xmlXPathNodeSetCreate(NULL);
7267 do {
7268 cur = next(ctxt, cur);
7269 if (cur == NULL) break;
7270#ifdef DEBUG_STEP
7271 t++;
7272 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
7273#endif
7274 switch (test) {
7275 case NODE_TEST_NONE:
7276 ctxt->context->node = tmp;
7277 STRANGE
7278 return;
7279 case NODE_TEST_TYPE:
7280 if ((cur->type == type) ||
7281 ((type == NODE_TYPE_NODE) &&
7282 ((cur->type == XML_DOCUMENT_NODE) ||
7283 (cur->type == XML_HTML_DOCUMENT_NODE) ||
7284 (cur->type == XML_ELEMENT_NODE) ||
7285 (cur->type == XML_PI_NODE) ||
7286 (cur->type == XML_COMMENT_NODE) ||
7287 (cur->type == XML_CDATA_SECTION_NODE) ||
7288 (cur->type == XML_TEXT_NODE)))) {
7289#ifdef DEBUG_STEP
7290 n++;
7291#endif
7292 addNode(list, cur);
7293 }
7294 break;
7295 case NODE_TEST_PI:
7296 if (cur->type == XML_PI_NODE) {
7297 if ((name != NULL) &&
7298 (!xmlStrEqual(name, cur->name)))
7299 break;
7300#ifdef DEBUG_STEP
7301 n++;
7302#endif
7303 addNode(list, cur);
7304 }
7305 break;
7306 case NODE_TEST_ALL:
7307 if (axis == AXIS_ATTRIBUTE) {
7308 if (cur->type == XML_ATTRIBUTE_NODE) {
7309#ifdef DEBUG_STEP
7310 n++;
7311#endif
7312 addNode(list, cur);
7313 }
7314 } else if (axis == AXIS_NAMESPACE) {
7315 if (cur->type == XML_NAMESPACE_DECL) {
7316#ifdef DEBUG_STEP
7317 n++;
7318#endif
7319 addNode(list, cur);
7320 }
7321 } else {
7322 if ((cur->type == XML_ELEMENT_NODE) ||
7323 (cur->type == XML_DOCUMENT_NODE) ||
7324 (cur->type == XML_HTML_DOCUMENT_NODE)) {
7325 if (prefix == NULL) {
7326#ifdef DEBUG_STEP
7327 n++;
7328#endif
7329 addNode(list, cur);
7330 } else if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007331 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007332 cur->ns->href))) {
7333#ifdef DEBUG_STEP
7334 n++;
7335#endif
7336 addNode(list, cur);
7337 }
7338 }
7339 }
7340 break;
7341 case NODE_TEST_NS: {
7342 TODO;
7343 break;
7344 }
7345 case NODE_TEST_NAME:
7346 switch (cur->type) {
7347 case XML_ELEMENT_NODE:
7348 if (xmlStrEqual(name, cur->name)) {
7349 if (prefix == NULL) {
Daniel Veillardaf86c7f2001-05-21 14:11:26 +00007350 if (cur->ns == NULL) {
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007351#ifdef DEBUG_STEP
7352 n++;
7353#endif
7354 addNode(list, cur);
7355 }
7356 } else {
7357 if ((cur->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007358 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007359 cur->ns->href))) {
7360#ifdef DEBUG_STEP
7361 n++;
7362#endif
7363 addNode(list, cur);
7364 }
7365 }
7366 }
7367 break;
7368 case XML_ATTRIBUTE_NODE: {
7369 xmlAttrPtr attr = (xmlAttrPtr) cur;
7370 if (xmlStrEqual(name, attr->name)) {
7371 if (prefix == NULL) {
7372 if ((attr->ns == NULL) ||
7373 (attr->ns->prefix == NULL)) {
7374#ifdef DEBUG_STEP
7375 n++;
7376#endif
7377 addNode(list, (xmlNodePtr) attr);
7378 }
7379 } else {
7380 if ((attr->ns != NULL) &&
Daniel Veillarde043ee12001-04-16 14:08:07 +00007381 (xmlStrEqual(URI,
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007382 attr->ns->href))) {
7383#ifdef DEBUG_STEP
7384 n++;
7385#endif
7386 addNode(list, (xmlNodePtr) attr);
7387 }
7388 }
7389 }
7390 break;
7391 }
7392 case XML_NAMESPACE_DECL: {
7393 TODO;
7394 break;
7395 }
7396 default:
7397 break;
7398 }
7399 break;
7400 }
7401 } while (cur != NULL);
7402
7403 /*
7404 * If there is some predicate filtering do it now
7405 */
7406 if (op->ch2 != -1) {
7407 xmlXPathObjectPtr obj2;
7408
7409 valuePush(ctxt, xmlXPathWrapNodeSet(list));
7410 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
7411 CHECK_TYPE(XPATH_NODESET);
7412 obj2 = valuePop(ctxt);
7413 list = obj2->nodesetval;
7414 obj2->nodesetval = NULL;
7415 xmlXPathFreeObject(obj2);
7416 }
7417 if (ret == NULL) {
7418 ret = list;
7419 } else {
7420 ret = xmlXPathNodeSetMerge(ret, list);
7421 xmlXPathFreeNodeSet(list);
7422 }
7423 }
7424 ctxt->context->node = tmp;
7425#ifdef DEBUG_STEP
7426 xmlGenericError(xmlGenericErrorContext,
7427 "\nExamined %d nodes, found %d nodes at that step\n", t, n);
7428#endif
7429 xmlXPathFreeObject(obj);
7430 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
7431}
7432
Owen Taylor3473f882001-02-23 17:55:21 +00007433/**
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007434 * xmlXPathCompOpEval:
7435 * @ctxt: the XPath parser context with the compiled expression
7436 * @op: an XPath compiled operation
7437 *
7438 * Evaluate the Precompiled XPath operation
7439 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007440static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007441xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) {
7442 int equal, ret;
7443 xmlXPathCompExprPtr comp;
7444 xmlXPathObjectPtr arg1, arg2;
7445
7446 comp = ctxt->comp;
7447 switch (op->op) {
7448 case XPATH_OP_END:
7449 return;
7450 case XPATH_OP_AND:
7451 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7452 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007453 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007454 return;
7455 arg2 = valuePop(ctxt);
7456 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7457 xmlXPathBooleanFunction(ctxt, 1);
7458 arg1 = valuePop(ctxt);
7459 arg1->boolval &= arg2->boolval;
7460 valuePush(ctxt, arg1);
7461 xmlXPathFreeObject(arg2);
7462 return;
7463 case XPATH_OP_OR:
7464 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7465 xmlXPathBooleanFunction(ctxt, 1);
Daniel Veillard76d66f42001-05-16 21:05:17 +00007466 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007467 return;
7468 arg2 = valuePop(ctxt);
7469 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7470 xmlXPathBooleanFunction(ctxt, 1);
7471 arg1 = valuePop(ctxt);
7472 arg1->boolval |= arg2->boolval;
7473 valuePush(ctxt, arg1);
7474 xmlXPathFreeObject(arg2);
7475 return;
7476 case XPATH_OP_EQUAL:
7477 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7478 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7479 equal = xmlXPathEqualValues(ctxt);
7480 if (op->value) valuePush(ctxt, xmlXPathNewBoolean(equal));
7481 else valuePush(ctxt, xmlXPathNewBoolean(!equal));
7482 return;
7483 case XPATH_OP_CMP:
7484 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7485 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7486 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
7487 valuePush(ctxt, xmlXPathNewBoolean(ret));
7488 return;
7489 case XPATH_OP_PLUS:
7490 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7491 if (op->ch2 != -1)
7492 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7493 if (op->value == 0) xmlXPathSubValues(ctxt);
7494 else if (op->value == 1) xmlXPathAddValues(ctxt);
7495 else if (op->value == 2) xmlXPathValueFlipSign(ctxt);
7496 else if (op->value == 3) {
Daniel Veillardba0b8c92001-05-15 09:43:47 +00007497 CAST_TO_NUMBER;
7498 CHECK_TYPE(XPATH_NUMBER);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007499 }
7500 return;
7501 case XPATH_OP_MULT:
7502 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7503 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7504 if (op->value == 0) xmlXPathMultValues(ctxt);
7505 else if (op->value == 1) xmlXPathDivValues(ctxt);
7506 else if (op->value == 2) xmlXPathModValues(ctxt);
7507 return;
7508 case XPATH_OP_UNION:
7509 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7510 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7511 CHECK_TYPE(XPATH_NODESET);
7512 arg2 = valuePop(ctxt);
7513
7514 CHECK_TYPE(XPATH_NODESET);
7515 arg1 = valuePop(ctxt);
7516
7517 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
7518 arg2->nodesetval);
7519 valuePush(ctxt, arg1);
7520 xmlXPathFreeObject(arg2);
7521 return;
7522 case XPATH_OP_ROOT:
7523 xmlXPathRoot(ctxt);
7524 return;
7525 case XPATH_OP_NODE:
7526 if (op->ch1 != -1)
7527 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7528 if (op->ch2 != -1)
7529 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7530 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
7531 return;
7532 case XPATH_OP_RESET:
7533 if (op->ch1 != -1)
7534 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7535 if (op->ch2 != -1)
7536 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7537 ctxt->context->node = NULL;
7538 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007539 case XPATH_OP_COLLECT: {
7540 if (op->ch1 == -1)
7541 return;
7542
7543 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7544 xmlXPathNodeCollectAndTest(ctxt, op);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007545 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007546 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007547 case XPATH_OP_VALUE:
7548 valuePush(ctxt,
7549 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
7550 return;
7551 case XPATH_OP_VARIABLE: {
7552 if (op->ch1 != -1)
7553 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7554 if (op->value5 == NULL)
7555 valuePush(ctxt,
7556 xmlXPathVariableLookup(ctxt->context, op->value4));
7557 else {
7558 const xmlChar *URI;
7559 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7560 if (URI == NULL) {
7561 xmlGenericError(xmlGenericErrorContext,
7562 "xmlXPathRunEval: variable %s bound to undefined prefix %s\n",
7563 op->value4, op->value5);
7564 return;
7565 }
7566 valuePush(ctxt,
7567 xmlXPathVariableLookupNS(ctxt->context,
7568 op->value4, URI));
7569 }
7570 return;
7571 }
7572 case XPATH_OP_FUNCTION: {
7573 xmlXPathFunction func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007574 const xmlChar *oldFunc, *oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007575
7576 if (op->ch1 != -1)
7577 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007578 if (op->cache != NULL)
7579 func = (xmlXPathFunction) op->cache;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007580 else {
Daniel Veillard42596ad2001-05-22 16:57:14 +00007581 const xmlChar *URI = NULL;
7582
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007583 if (op->value5 == NULL)
7584 func = xmlXPathFunctionLookup(ctxt->context, op->value4);
7585 else {
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007586 URI = xmlXPathNsLookup(ctxt->context, op->value5);
7587 if (URI == NULL) {
7588 xmlGenericError(xmlGenericErrorContext,
7589 "xmlXPathRunEval: function %s bound to undefined prefix %s\n",
7590 op->value4, op->value5);
7591 return;
7592 }
7593 func = xmlXPathFunctionLookupNS(ctxt->context,
7594 op->value4, URI);
7595 }
7596 if (func == NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007597 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007598 "xmlXPathRunEval: function %s not found\n",
7599 op->value4);
7600 XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007601 return;
7602 }
Daniel Veillarde39a93d2001-04-28 14:35:02 +00007603 op->cache = (void *) func;
Daniel Veillard42596ad2001-05-22 16:57:14 +00007604 op->cacheURI = (void *) URI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007605 }
Daniel Veillard42596ad2001-05-22 16:57:14 +00007606 oldFunc = ctxt->context->function;
7607 oldFuncURI = ctxt->context->functionURI;
7608 ctxt->context->function = op->value4;
7609 ctxt->context->functionURI = op->cacheURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007610 func(ctxt, op->value);
Daniel Veillard42596ad2001-05-22 16:57:14 +00007611 ctxt->context->function = oldFunc;
7612 ctxt->context->functionURI = oldFuncURI;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007613 return;
7614 }
7615 case XPATH_OP_ARG:
7616 if (op->ch1 != -1)
7617 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7618 if (op->ch2 != -1)
7619 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7620 return;
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007621 case XPATH_OP_PREDICATE:
7622 case XPATH_OP_FILTER: {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007623 xmlXPathObjectPtr res;
7624 xmlXPathObjectPtr obj, tmp;
7625 xmlNodeSetPtr newset = NULL;
7626 xmlNodeSetPtr oldset;
7627 xmlNodePtr oldnode;
7628 int i;
7629
7630 if (op->ch1 != -1)
7631 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7632 if (op->ch2 == -1)
7633 return;
Daniel Veillard76d66f42001-05-16 21:05:17 +00007634 if (ctxt->value == NULL)
7635 return;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007636
7637 oldnode = ctxt->context->node;
7638
7639#ifdef LIBXML_XPTR_ENABLED
7640 /*
7641 * Hum are we filtering the result of an XPointer expression
7642 */
7643 if (ctxt->value->type == XPATH_LOCATIONSET) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007644 xmlLocationSetPtr newlocset = NULL;
7645 xmlLocationSetPtr oldlocset;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007646
7647 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007648 * Extract the old locset, and then evaluate the result of the
7649 * expression for all the element in the locset. use it to grow
7650 * up a new locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007651 */
7652 CHECK_TYPE(XPATH_LOCATIONSET);
7653 obj = valuePop(ctxt);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007654 oldlocset = obj->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007655 ctxt->context->node = NULL;
7656
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007657 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007658 ctxt->context->contextSize = 0;
7659 ctxt->context->proximityPosition = 0;
7660 if (op->ch2 != -1)
7661 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7662 res = valuePop(ctxt);
7663 if (res != NULL)
7664 xmlXPathFreeObject(res);
7665 valuePush(ctxt, obj);
7666 CHECK_ERROR;
7667 return;
7668 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007669 newlocset = xmlXPtrLocationSetCreate(NULL);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007670
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007671 for (i = 0; i < oldlocset->locNr; i++) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007672 /*
7673 * Run the evaluation with a node list made of a
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007674 * single item in the nodelocset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007675 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007676 ctxt->context->node = oldlocset->locTab[i]->user;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007677 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7678 valuePush(ctxt, tmp);
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007679 ctxt->context->contextSize = oldlocset->locNr;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007680 ctxt->context->proximityPosition = i + 1;
7681
7682 if (op->ch2 != -1)
7683 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7684 CHECK_ERROR;
7685
7686 /*
7687 * The result of the evaluation need to be tested to
7688 * decided whether the filter succeeded or not
7689 */
7690 res = valuePop(ctxt);
7691 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007692 xmlXPtrLocationSetAdd(newlocset,
7693 xmlXPathObjectCopy(oldlocset->locTab[i]));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007694 }
7695
7696 /*
7697 * Cleanup
7698 */
7699 if (res != NULL)
7700 xmlXPathFreeObject(res);
7701 if (ctxt->value == tmp) {
7702 res = valuePop(ctxt);
7703 xmlXPathFreeObject(res);
7704 }
7705
7706 ctxt->context->node = NULL;
7707 }
7708
7709 /*
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007710 * The result is used as the new evaluation locset.
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007711 */
7712 xmlXPathFreeObject(obj);
7713 ctxt->context->node = NULL;
7714 ctxt->context->contextSize = -1;
7715 ctxt->context->proximityPosition = -1;
Daniel Veillard56a4cb82001-03-24 17:00:36 +00007716 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007717 ctxt->context->node = oldnode;
7718 return;
7719 }
7720#endif /* LIBXML_XPTR_ENABLED */
7721
7722 /*
7723 * Extract the old set, and then evaluate the result of the
7724 * expression for all the element in the set. use it to grow
7725 * up a new set.
7726 */
7727 CHECK_TYPE(XPATH_NODESET);
7728 obj = valuePop(ctxt);
7729 oldset = obj->nodesetval;
Daniel Veillard911f49a2001-04-07 15:39:35 +00007730
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007731 oldnode = ctxt->context->node;
7732 ctxt->context->node = NULL;
7733
7734 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
7735 ctxt->context->contextSize = 0;
7736 ctxt->context->proximityPosition = 0;
7737 if (op->ch2 != -1)
7738 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7739 res = valuePop(ctxt);
7740 if (res != NULL)
7741 xmlXPathFreeObject(res);
7742 valuePush(ctxt, obj);
Daniel Veillard911f49a2001-04-07 15:39:35 +00007743 ctxt->context->node = oldnode;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007744 CHECK_ERROR;
7745 } else {
7746 /*
7747 * Initialize the new set.
7748 */
7749 newset = xmlXPathNodeSetCreate(NULL);
7750
7751 for (i = 0; i < oldset->nodeNr; i++) {
7752 /*
7753 * Run the evaluation with a node list made of
7754 * a single item in the nodeset.
7755 */
7756 ctxt->context->node = oldset->nodeTab[i];
7757 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7758 valuePush(ctxt, tmp);
7759 ctxt->context->contextSize = oldset->nodeNr;
7760 ctxt->context->proximityPosition = i + 1;
7761
7762 if (op->ch2 != -1)
7763 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7764 CHECK_ERROR;
7765
7766 /*
7767 * The result of the evaluation need to be tested to
7768 * decided whether the filter succeeded or not
7769 */
7770 res = valuePop(ctxt);
7771 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
7772 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
7773 }
7774
7775 /*
7776 * Cleanup
7777 */
7778 if (res != NULL)
7779 xmlXPathFreeObject(res);
7780 if (ctxt->value == tmp) {
7781 res = valuePop(ctxt);
7782 xmlXPathFreeObject(res);
7783 }
7784
7785 ctxt->context->node = NULL;
7786 }
7787
7788 /*
7789 * The result is used as the new evaluation set.
7790 */
7791 xmlXPathFreeObject(obj);
7792 ctxt->context->node = NULL;
7793 ctxt->context->contextSize = -1;
7794 ctxt->context->proximityPosition = -1;
7795 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
7796 }
7797 ctxt->context->node = oldnode;
7798 return;
7799 }
7800 case XPATH_OP_SORT:
7801 if (op->ch1 != -1)
7802 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7803 if ((ctxt->value != NULL) &&
7804 (ctxt->value->type == XPATH_NODESET) &&
7805 (ctxt->value->nodesetval != NULL))
7806 xmlXPathNodeSetSort(ctxt->value->nodesetval);
7807 return;
7808#ifdef LIBXML_XPTR_ENABLED
7809 case XPATH_OP_RANGETO: {
7810 xmlXPathObjectPtr range;
7811 xmlXPathObjectPtr res, obj;
7812 xmlXPathObjectPtr tmp;
7813 xmlLocationSetPtr newset = NULL;
7814 xmlNodeSetPtr oldset;
7815 int i;
7816
7817 if (op->ch1 != -1)
7818 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
7819 if (op->ch2 == -1)
7820 return;
7821
7822 CHECK_TYPE(XPATH_NODESET);
7823 obj = valuePop(ctxt);
7824 oldset = obj->nodesetval;
7825 ctxt->context->node = NULL;
7826
7827 newset = xmlXPtrLocationSetCreate(NULL);
7828
Daniel Veillard911f49a2001-04-07 15:39:35 +00007829 if (oldset != NULL) {
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007830 for (i = 0; i < oldset->nodeNr; i++) {
7831 /*
7832 * Run the evaluation with a node list made of a single item
7833 * in the nodeset.
7834 */
7835 ctxt->context->node = oldset->nodeTab[i];
7836 tmp = xmlXPathNewNodeSet(ctxt->context->node);
7837 valuePush(ctxt, tmp);
7838
7839 if (op->ch2 != -1)
7840 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
7841 CHECK_ERROR;
7842
7843 /*
7844 * The result of the evaluation need to be tested to
7845 * decided whether the filter succeeded or not
7846 */
7847 res = valuePop(ctxt);
7848 range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
7849 if (range != NULL) {
7850 xmlXPtrLocationSetAdd(newset, range);
7851 }
7852
7853 /*
7854 * Cleanup
7855 */
7856 if (res != NULL)
7857 xmlXPathFreeObject(res);
7858 if (ctxt->value == tmp) {
7859 res = valuePop(ctxt);
7860 xmlXPathFreeObject(res);
7861 }
7862
7863 ctxt->context->node = NULL;
7864 }
Daniel Veillard911f49a2001-04-07 15:39:35 +00007865 }
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007866
7867 /*
7868 * The result is used as the new evaluation set.
7869 */
7870 xmlXPathFreeObject(obj);
7871 ctxt->context->node = NULL;
7872 ctxt->context->contextSize = -1;
7873 ctxt->context->proximityPosition = -1;
7874 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
7875 return;
7876 }
7877#endif /* LIBXML_XPTR_ENABLED */
7878 }
7879 xmlGenericError(xmlGenericErrorContext,
7880 "XPath: unknown precompiled operation %d\n",
7881 op->op);
7882 return;
7883}
7884
7885/**
7886 * xmlXPathRunEval:
7887 * @ctxt: the XPath parser context with the compiled expression
7888 *
7889 * Evaluate the Precompiled XPath expression in the given context.
7890 */
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007891static void
Daniel Veillard9e7160d2001-03-18 23:17:47 +00007892xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
7893 xmlXPathCompExprPtr comp;
7894
7895 if ((ctxt == NULL) || (ctxt->comp == NULL))
7896 return;
7897
7898 if (ctxt->valueTab == NULL) {
7899 /* Allocate the value stack */
7900 ctxt->valueTab = (xmlXPathObjectPtr *)
7901 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
7902 if (ctxt->valueTab == NULL) {
7903 xmlFree(ctxt);
7904 xmlGenericError(xmlGenericErrorContext,
7905 "xmlXPathRunEval: out of memory\n");
7906 return;
7907 }
7908 ctxt->valueNr = 0;
7909 ctxt->valueMax = 10;
7910 ctxt->value = NULL;
7911 }
7912 comp = ctxt->comp;
7913 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
7914}
7915
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007916/************************************************************************
7917 * *
7918 * Public interfaces *
7919 * *
7920 ************************************************************************/
7921
7922/**
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007923 * xmlXPathEvalPredicate:
7924 * @ctxt: the XPath context
7925 * @res: the Predicate Expression evaluation result
7926 *
7927 * Evaluate a predicate result for the current node.
7928 * A PredicateExpr is evaluated by evaluating the Expr and converting
7929 * the result to a boolean. If the result is a number, the result will
7930 * be converted to true if the number is equal to the position of the
7931 * context node in the context node list (as returned by the position
7932 * function) and will be converted to false otherwise; if the result
7933 * is not a number, then the result will be converted as if by a call
7934 * to the boolean function.
7935 *
7936 * Return 1 if predicate is true, 0 otherwise
7937 */
7938int
7939xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
7940 if (res == NULL) return(0);
7941 switch (res->type) {
7942 case XPATH_BOOLEAN:
7943 return(res->boolval);
7944 case XPATH_NUMBER:
7945 return(res->floatval == ctxt->proximityPosition);
7946 case XPATH_NODESET:
7947 case XPATH_XSLT_TREE:
Daniel Veillardd8df6c02001-04-05 16:54:14 +00007948 if (res->nodesetval == NULL)
7949 return(0);
Daniel Veillardfbf8a2d2001-03-19 15:58:54 +00007950 return(res->nodesetval->nodeNr != 0);
7951 case XPATH_STRING:
7952 return((res->stringval != NULL) &&
7953 (xmlStrlen(res->stringval) != 0));
7954 default:
7955 STRANGE
7956 }
7957 return(0);
7958}
7959
7960/**
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007961 * xmlXPathEvaluatePredicateResult:
7962 * @ctxt: the XPath Parser context
7963 * @res: the Predicate Expression evaluation result
7964 *
7965 * Evaluate a predicate result for the current node.
7966 * A PredicateExpr is evaluated by evaluating the Expr and converting
7967 * the result to a boolean. If the result is a number, the result will
7968 * be converted to true if the number is equal to the position of the
7969 * context node in the context node list (as returned by the position
7970 * function) and will be converted to false otherwise; if the result
7971 * is not a number, then the result will be converted as if by a call
7972 * to the boolean function.
7973 *
7974 * Return 1 if predicate is true, 0 otherwise
7975 */
7976int
7977xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
7978 xmlXPathObjectPtr res) {
7979 if (res == NULL) return(0);
7980 switch (res->type) {
7981 case XPATH_BOOLEAN:
7982 return(res->boolval);
7983 case XPATH_NUMBER:
7984 return(res->floatval == ctxt->context->proximityPosition);
7985 case XPATH_NODESET:
7986 case XPATH_XSLT_TREE:
Daniel Veillard73639a72001-04-10 14:31:39 +00007987 if (res->nodesetval == NULL)
Daniel Veillard911f49a2001-04-07 15:39:35 +00007988 return(0);
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00007989 return(res->nodesetval->nodeNr != 0);
7990 case XPATH_STRING:
7991 return((res->stringval != NULL) &&
7992 (xmlStrlen(res->stringval) != 0));
7993 default:
7994 STRANGE
7995 }
7996 return(0);
7997}
7998
7999/**
8000 * xmlXPathCompile:
8001 * @str: the XPath expression
8002 *
8003 * Compile an XPath expression
8004 *
8005 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8006 * the caller has to free the object.
8007 */
8008xmlXPathCompExprPtr
8009xmlXPathCompile(const xmlChar *str) {
8010 xmlXPathParserContextPtr ctxt;
8011 xmlXPathCompExprPtr comp;
8012
8013 xmlXPathInit();
8014
8015 ctxt = xmlXPathNewParserContext(str, NULL);
8016 xmlXPathCompileExpr(ctxt);
8017
Daniel Veillard40af6492001-04-22 08:50:55 +00008018 if (*ctxt->cur != 0) {
8019 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8020 comp = NULL;
8021 } else {
8022 comp = ctxt->comp;
8023 ctxt->comp = NULL;
8024 }
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008025 xmlXPathFreeParserContext(ctxt);
8026 return(comp);
8027}
8028
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008029/**
8030 * xmlXPathCompiledEval:
8031 * @comp: the compiled XPath expression
Owen Taylor3473f882001-02-23 17:55:21 +00008032 * @ctx: the XPath context
8033 *
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008034 * Evaluate the Precompiled XPath expression in the given context.
Owen Taylor3473f882001-02-23 17:55:21 +00008035 *
8036 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8037 * the caller has to free the object.
8038 */
8039xmlXPathObjectPtr
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008040xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
Owen Taylor3473f882001-02-23 17:55:21 +00008041 xmlXPathParserContextPtr ctxt;
8042 xmlXPathObjectPtr res, tmp, init = NULL;
8043 int stack = 0;
8044
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008045 if ((comp == NULL) || (ctx == NULL))
8046 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00008047 xmlXPathInit();
8048
8049 CHECK_CONTEXT(ctx)
8050
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008051 ctxt = xmlXPathCompParserContext(comp, ctx);
8052 xmlXPathRunEval(ctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008053
8054 if (ctxt->value == NULL) {
8055 xmlGenericError(xmlGenericErrorContext,
8056 "xmlXPathEval: evaluation failed\n");
8057 res = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00008058 } else {
8059 res = valuePop(ctxt);
8060 }
8061
8062 do {
8063 tmp = valuePop(ctxt);
8064 if (tmp != NULL) {
8065 if (tmp != init)
8066 stack++;
8067 xmlXPathFreeObject(tmp);
8068 }
8069 } while (tmp != NULL);
8070 if ((stack != 0) && (res != NULL)) {
8071 xmlGenericError(xmlGenericErrorContext,
8072 "xmlXPathEval: %d object left on the stack\n",
8073 stack);
8074 }
8075 if (ctxt->error != XPATH_EXPRESSION_OK) {
8076 xmlXPathFreeObject(res);
8077 res = NULL;
8078 }
8079
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008080
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008081 ctxt->comp = NULL;
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008082 xmlXPathFreeParserContext(ctxt);
8083 return(res);
8084}
8085
Daniel Veillardafcbe1c2001-03-19 10:57:13 +00008086/**
8087 * xmlXPathEvalExpr:
8088 * @ctxt: the XPath Parser context
8089 *
8090 * Parse and evaluate an XPath expression in the given context,
8091 * then push the result on the context stack
8092 */
8093void
8094xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
8095 xmlXPathCompileExpr(ctxt);
8096 xmlXPathRunEval(ctxt);
8097}
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008098
8099/**
8100 * xmlXPathEval:
8101 * @str: the XPath expression
8102 * @ctx: the XPath context
8103 *
8104 * Evaluate the XPath Location Path in the given context.
8105 *
8106 * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
8107 * the caller has to free the object.
8108 */
8109xmlXPathObjectPtr
8110xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
8111 xmlXPathParserContextPtr ctxt;
8112 xmlXPathObjectPtr res, tmp, init = NULL;
8113 int stack = 0;
8114
8115 xmlXPathInit();
8116
8117 CHECK_CONTEXT(ctx)
8118
8119 ctxt = xmlXPathNewParserContext(str, ctx);
8120 xmlXPathEvalExpr(ctxt);
Daniel Veillard9e7160d2001-03-18 23:17:47 +00008121
8122 if (ctxt->value == NULL) {
8123 xmlGenericError(xmlGenericErrorContext,
8124 "xmlXPathEval: evaluation failed\n");
8125 res = NULL;
8126 } else if (*ctxt->cur != 0) {
8127 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8128 res = NULL;
8129 } else {
8130 res = valuePop(ctxt);
8131 }
8132
8133 do {
8134 tmp = valuePop(ctxt);
8135 if (tmp != NULL) {
8136 if (tmp != init)
8137 stack++;
8138 xmlXPathFreeObject(tmp);
8139 }
8140 } while (tmp != NULL);
8141 if ((stack != 0) && (res != NULL)) {
8142 xmlGenericError(xmlGenericErrorContext,
8143 "xmlXPathEval: %d object left on the stack\n",
8144 stack);
8145 }
8146 if (ctxt->error != XPATH_EXPRESSION_OK) {
8147 xmlXPathFreeObject(res);
8148 res = NULL;
8149 }
8150
Owen Taylor3473f882001-02-23 17:55:21 +00008151 xmlXPathFreeParserContext(ctxt);
8152 return(res);
8153}
8154
8155/**
8156 * xmlXPathEvalExpression:
8157 * @str: the XPath expression
8158 * @ctxt: the XPath context
8159 *
8160 * Evaluate the XPath expression in the given context.
8161 *
8162 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
8163 * the caller has to free the object.
8164 */
8165xmlXPathObjectPtr
8166xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
8167 xmlXPathParserContextPtr pctxt;
8168 xmlXPathObjectPtr res, tmp;
8169 int stack = 0;
8170
8171 xmlXPathInit();
8172
8173 CHECK_CONTEXT(ctxt)
8174
8175 pctxt = xmlXPathNewParserContext(str, ctxt);
8176 xmlXPathEvalExpr(pctxt);
Owen Taylor3473f882001-02-23 17:55:21 +00008177
8178 if (*pctxt->cur != 0) {
8179 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
8180 res = NULL;
8181 } else {
8182 res = valuePop(pctxt);
8183 }
8184 do {
8185 tmp = valuePop(pctxt);
8186 if (tmp != NULL) {
8187 xmlXPathFreeObject(tmp);
8188 stack++;
8189 }
8190 } while (tmp != NULL);
8191 if ((stack != 0) && (res != NULL)) {
8192 xmlGenericError(xmlGenericErrorContext,
8193 "xmlXPathEvalExpression: %d object left on the stack\n",
8194 stack);
8195 }
8196 xmlXPathFreeParserContext(pctxt);
8197 return(res);
8198}
8199
8200/**
8201 * xmlXPathRegisterAllFunctions:
8202 * @ctxt: the XPath context
8203 *
8204 * Registers all default XPath functions in this context
8205 */
8206void
8207xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
8208{
8209 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
8210 xmlXPathBooleanFunction);
8211 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
8212 xmlXPathCeilingFunction);
8213 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
8214 xmlXPathCountFunction);
8215 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
8216 xmlXPathConcatFunction);
8217 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
8218 xmlXPathContainsFunction);
8219 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
8220 xmlXPathIdFunction);
8221 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
8222 xmlXPathFalseFunction);
8223 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
8224 xmlXPathFloorFunction);
8225 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
8226 xmlXPathLastFunction);
8227 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
8228 xmlXPathLangFunction);
8229 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
8230 xmlXPathLocalNameFunction);
8231 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
8232 xmlXPathNotFunction);
8233 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
8234 xmlXPathNameFunction);
8235 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
8236 xmlXPathNamespaceURIFunction);
8237 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
8238 xmlXPathNormalizeFunction);
8239 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
8240 xmlXPathNumberFunction);
8241 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
8242 xmlXPathPositionFunction);
8243 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
8244 xmlXPathRoundFunction);
8245 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
8246 xmlXPathStringFunction);
8247 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
8248 xmlXPathStringLengthFunction);
8249 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
8250 xmlXPathStartsWithFunction);
8251 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
8252 xmlXPathSubstringFunction);
8253 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
8254 xmlXPathSubstringBeforeFunction);
8255 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
8256 xmlXPathSubstringAfterFunction);
8257 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
8258 xmlXPathSumFunction);
8259 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
8260 xmlXPathTrueFunction);
8261 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
8262 xmlXPathTranslateFunction);
8263}
8264
8265#endif /* LIBXML_XPATH_ENABLED */