Annotation of XML/xpath.c, revision 1.76
1.1 daniel 1: /*
2: * xpath.c: XML Path Language implementation
1.8 daniel 3: * XPath is a language for addressing parts of an XML document,
1.67 veillard 4: * designed to be used by both XSLT and XPointer
1.1 daniel 5: *
1.67 veillard 6: * Reference: W3C Recommendation 16 November 1999
7: * http://www.w3.org/TR/1999/REC-xpath-19991116
1.8 daniel 8: * Public reference:
1.67 veillard 9: * http://www.w3.org/TR/xpath
1.1 daniel 10: *
11: * See COPYRIGHT for the status of this software
12: *
13: * Author: Daniel.Veillard@w3.org
14: */
15:
1.27 daniel 16: #ifdef WIN32
1.34 daniel 17: #include "win32config.h"
1.27 daniel 18: #else
1.28 daniel 19: #include "config.h"
1.27 daniel 20: #endif
21:
1.72 veillard 22: #include <libxml/xmlversion.h>
1.45 daniel 23: #ifdef LIBXML_XPATH_ENABLED
24:
1.27 daniel 25: #include <stdio.h>
26: #include <string.h>
27:
28: #ifdef HAVE_SYS_TYPES_H
29: #include <sys/types.h>
30: #endif
1.12 daniel 31: #ifdef HAVE_MATH_H
1.5 daniel 32: #include <math.h>
1.12 daniel 33: #endif
1.13 daniel 34: #ifdef HAVE_MATH_H
35: #include <float.h>
36: #endif
1.12 daniel 37: #ifdef HAVE_IEEEFP_H
38: #include <ieeefp.h>
39: #endif
40: #ifdef HAVE_NAN_H
41: #include <nan.h>
42: #endif
1.27 daniel 43: #ifdef HAVE_CTYPE_H
1.19 daniel 44: #include <ctype.h>
1.27 daniel 45: #endif
46:
1.45 daniel 47: #include <libxml/xmlmemory.h>
48: #include <libxml/tree.h>
49: #include <libxml/valid.h>
50: #include <libxml/xpath.h>
51: #include <libxml/parserInternals.h>
1.62 veillard 52: #ifdef LIBXML_XPTR_ENABLED
53: #include <libxml/xpointer.h>
54: #endif
1.76 ! veillard 55: #ifdef LIBXML_DEBUG_ENABLED
! 56: #include <libxml/debugXML.h>
! 57: #endif
1.1 daniel 58:
1.53 veillard 59: /* #define DEBUG */
60: /* #define DEBUG_STEP */
61: /* #define DEBUG_EXPR */
1.35 daniel 62:
1.76 ! veillard 63: void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
! 64: double xmlXPathStringEvalNumber(const xmlChar *str);
! 65:
1.5 daniel 66: /*
1.10 daniel 67: * Setup stuff for floating point
1.19 daniel 68: * The lack of portability of this section of the libc is annoying !
1.5 daniel 69: */
1.10 daniel 70: double xmlXPathNAN = 0;
71: double xmlXPathPINF = 1;
72: double xmlXPathMINF = -1;
1.12 daniel 73:
74: #ifndef isinf
75: #ifndef HAVE_ISINF
1.13 daniel 76:
77: #if HAVE_FPCLASS
78:
79: int isinf(double d) {
80: fpclass_t type = fpclass(d);
81: switch (type) {
82: case FP_NINF:
83: return(-1);
84: case FP_PINF:
85: return(1);
86: }
87: return(0);
88: }
89:
90: #elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
91:
92: #if HAVE_FP_CLASS_H
93: #include <fp_class.h>
94: #endif
95:
96: int isinf(double d) {
97: #if HAVE_FP_CLASS
98: int fpclass = fp_class(d);
99: #else
100: int fpclass = fp_class_d(d);
101: #endif
102: if (fpclass == FP_POS_INF)
103: return(1);
104: if (fpclass == FP_NEG_INF)
105: return(-1);
106: return(0);
107: }
108:
109: #elif defined(HAVE_CLASS)
110:
111: int isinf(double d) {
112: int fpclass = class(d);
113: if (fpclass == FP_PLUS_INF)
114: return(1);
115: if (fpclass == FP_MINUS_INF)
116: return(-1);
117: return(0);
118: }
119: #elif defined(finite) || defined(HAVE_FINITE)
1.12 daniel 120: int isinf(double x) { return !finite(x) && x==x; }
1.19 daniel 121: #elif defined(HUGE_VAL)
1.46 daniel 122: int isinf(double x)
1.19 daniel 123: {
124: if (x == HUGE_VAL)
125: return(1);
126: if (x == -HUGE_VAL)
127: return(-1);
128: return(0);
129: }
130: #endif
1.13 daniel 131:
1.12 daniel 132: #endif /* ! HAVE_ISINF */
133: #endif /* ! defined(isinf) */
134:
135: #ifndef isnan
136: #ifndef HAVE_ISNAN
1.13 daniel 137:
1.12 daniel 138: #ifdef HAVE_ISNAND
139: #define isnan(f) isnand(f)
140: #endif /* HAVE_iSNAND */
1.13 daniel 141:
1.12 daniel 142: #endif /* ! HAVE_iSNAN */
143: #endif /* ! defined(isnan) */
1.10 daniel 144:
145: /**
146: * xmlXPathInit:
147: *
148: * Initialize the XPath environment
149: */
150: void
151: xmlXPathInit(void) {
152: static int initialized = 0;
153:
154: if (initialized) return;
155:
156: xmlXPathNAN = 0;
157: xmlXPathNAN /= 0;
158:
159: xmlXPathPINF = 1;
160: xmlXPathPINF /= 0;
161:
162: xmlXPathMINF = -1;
163: xmlXPathMINF /= 0;
164:
165: initialized = 1;
166: }
1.5 daniel 167:
1.1 daniel 168: /************************************************************************
169: * *
1.76 ! veillard 170: * Debugging related functions *
1.1 daniel 171: * *
172: ************************************************************************/
173:
1.76 ! veillard 174: FILE *xmlXPathDebug = NULL;
! 175:
1.71 veillard 176: #define TODO \
177: fprintf(xmlXPathDebug, "Unimplemented block at %s:%d\n", \
178: __FILE__, __LINE__);
179:
180: #define STRANGE \
181: fprintf(xmlXPathDebug, "Internal error at %s:%d\n", \
182: __FILE__, __LINE__);
1.76 ! veillard 183:
! 184: #ifdef LIBXML_DEBUG_ENABLED
! 185: double xmlXPathStringEvalNumber(const xmlChar *str);
! 186: void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
! 187:
! 188: void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
! 189: int i;
! 190: char shift[100];
! 191:
! 192: for (i = 0;((i < depth) && (i < 25));i++)
! 193: shift[2 * i] = shift[2 * i + 1] = ' ';
! 194: shift[2 * i] = shift[2 * i + 1] = 0;
! 195: if (cur == NULL) {
! 196: fprintf(output, shift);
! 197: fprintf(output, "Node is NULL !\n");
! 198: return;
! 199:
! 200: }
! 201:
! 202: if ((cur->type == XML_DOCUMENT_NODE) ||
! 203: (cur->type == XML_HTML_DOCUMENT_NODE)) {
! 204: fprintf(output, shift);
! 205: fprintf(output, " /\n");
! 206: } else if (cur->type == XML_ATTRIBUTE_NODE)
! 207: xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
! 208: else
! 209: xmlDebugDumpOneNode(output, cur, depth);
! 210: }
! 211:
! 212: void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
! 213: int i;
! 214: char shift[100];
! 215:
! 216: for (i = 0;((i < depth) && (i < 25));i++)
! 217: shift[2 * i] = shift[2 * i + 1] = ' ';
! 218: shift[2 * i] = shift[2 * i + 1] = 0;
! 219:
! 220: if (cur == NULL) {
! 221: fprintf(output, shift);
! 222: fprintf(output, "NodeSet is NULL !\n");
! 223: return;
! 224:
! 225: }
! 226:
! 227: fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
! 228: for (i = 0;i < cur->nodeNr;i++) {
! 229: fprintf(output, shift);
! 230: fprintf(output, "%d", i + 1);
! 231: xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
! 232: }
! 233: }
! 234:
! 235: #if defined(LIBXML_XPTR_ENABLED)
! 236: void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
! 237: void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
! 238: int i;
! 239: char shift[100];
! 240:
! 241: for (i = 0;((i < depth) && (i < 25));i++)
! 242: shift[2 * i] = shift[2 * i + 1] = ' ';
! 243: shift[2 * i] = shift[2 * i + 1] = 0;
! 244:
! 245: if (cur == NULL) {
! 246: fprintf(output, shift);
! 247: fprintf(output, "LocationSet is NULL !\n");
! 248: return;
! 249:
! 250: }
! 251:
! 252: for (i = 0;i < cur->locNr;i++) {
! 253: fprintf(output, shift);
! 254: fprintf(output, "%d : ", i + 1);
! 255: xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
! 256: }
! 257: }
! 258: #endif
! 259:
! 260: void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
! 261: int i;
! 262: char shift[100];
! 263:
! 264: for (i = 0;((i < depth) && (i < 25));i++)
! 265: shift[2 * i] = shift[2 * i + 1] = ' ';
! 266: shift[2 * i] = shift[2 * i + 1] = 0;
! 267:
! 268: fprintf(output, shift);
! 269:
! 270: if (cur == NULL) {
! 271: fprintf(output, "Object is empty (NULL)\n");
! 272: return;
! 273: }
! 274: switch(cur->type) {
! 275: case XPATH_UNDEFINED:
! 276: fprintf(output, "Object is uninitialized\n");
! 277: break;
! 278: case XPATH_NODESET:
! 279: fprintf(output, "Object is a Node Set :\n");
! 280: xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
! 281: break;
! 282: case XPATH_BOOLEAN:
! 283: fprintf(output, "Object is a Boolean : ");
! 284: if (cur->boolval) fprintf(output, "true\n");
! 285: else fprintf(output, "false\n");
! 286: break;
! 287: case XPATH_NUMBER:
! 288: fprintf(output, "Object is a number : %0g\n", cur->floatval);
! 289: break;
! 290: case XPATH_STRING:
! 291: fprintf(output, "Object is a string : ");
! 292: xmlDebugDumpString(output, cur->stringval);
! 293: fprintf(output, "\n");
! 294: break;
! 295: case XPATH_POINT:
! 296: fprintf(output, "Object is a point : index %d in node", cur->index);
! 297: xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
! 298: fprintf(output, "\n");
! 299: break;
! 300: case XPATH_RANGE:
! 301: if ((cur->user2 == NULL) ||
! 302: ((cur->user2 == cur->user) && (cur->index = cur->index2))) {
! 303: fprintf(output, "Object is a collapsed range :\n");
! 304: fprintf(output, shift);
! 305: if (cur->index >= 0)
! 306: fprintf(output, "index %d in ", cur->index);
! 307: fprintf(output, "node\n");
! 308: xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
! 309: depth + 1);
! 310: } else {
! 311: fprintf(output, "Object is a range :\n");
! 312: fprintf(output, shift);
! 313: fprintf(output, "From ");
! 314: if (cur->index >= 0)
! 315: fprintf(output, "index %d in ", cur->index);
! 316: fprintf(output, "node\n");
! 317: xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
! 318: depth + 1);
! 319: fprintf(output, shift);
! 320: fprintf(output, "To ");
! 321: if (cur->index2 >= 0)
! 322: fprintf(output, "index %d in ", cur->index2);
! 323: fprintf(output, "node\n");
! 324: xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
! 325: depth + 1);
! 326: fprintf(output, "\n");
! 327: }
! 328: break;
! 329: case XPATH_LOCATIONSET:
! 330: #if defined(LIBXML_XPTR_ENABLED)
! 331: fprintf(output, "Object is a Location Set:\n");
! 332: xmlXPathDebugDumpLocationSet(output,
! 333: (xmlLocationSetPtr) cur->user, depth);
! 334: #endif
! 335: break;
! 336: case XPATH_USERS:
! 337: fprintf(output, "Object is user defined\n");
! 338: break;
! 339: }
! 340: }
! 341: #endif
! 342:
! 343: /************************************************************************
! 344: * *
! 345: * Parser stacks related functions and macros *
! 346: * *
! 347: ************************************************************************/
1.71 veillard 348:
1.1 daniel 349: /*
350: * Generic function for accessing stacks in the Parser Context
351: */
352:
353: #define PUSH_AND_POP(type, name) \
354: extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \
355: if (ctxt->name##Nr >= ctxt->name##Max) { \
356: ctxt->name##Max *= 2; \
1.50 veillard 357: ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \
1.1 daniel 358: ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \
359: if (ctxt->name##Tab == NULL) { \
1.14 daniel 360: fprintf(xmlXPathDebug, "realloc failed !\n"); \
1.36 daniel 361: return(0); \
1.1 daniel 362: } \
363: } \
364: ctxt->name##Tab[ctxt->name##Nr] = value; \
365: ctxt->name = value; \
366: return(ctxt->name##Nr++); \
367: } \
368: extern type name##Pop(xmlXPathParserContextPtr ctxt) { \
369: type ret; \
370: if (ctxt->name##Nr <= 0) return(0); \
371: ctxt->name##Nr--; \
372: if (ctxt->name##Nr > 0) \
373: ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \
374: else \
375: ctxt->name = NULL; \
376: ret = ctxt->name##Tab[ctxt->name##Nr]; \
377: ctxt->name##Tab[ctxt->name##Nr] = 0; \
378: return(ret); \
379: } \
380:
381: PUSH_AND_POP(xmlXPathObjectPtr, value)
382:
383: /*
384: * Macros for accessing the content. Those should be used only by the parser,
385: * and not exported.
386: *
387: * Dirty macros, i.e. one need to make assumption on the context to use them
388: *
1.29 daniel 389: * CUR_PTR return the current pointer to the xmlChar to be parsed.
1.41 daniel 390: * CUR returns the current xmlChar value, i.e. a 8 bit value
391: * in ISO-Latin or UTF-8.
392: * This should be used internally by the parser
1.1 daniel 393: * only to compare to ASCII values otherwise it would break when
394: * running with UTF-8 encoding.
1.29 daniel 395: * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1.1 daniel 396: * to compare on ASCII based substring.
1.29 daniel 397: * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1.1 daniel 398: * strings within the parser.
399: * CURRENT Returns the current char value, with the full decoding of
400: * UTF-8 if we are using this mode. It returns an int.
401: * NEXT Skip to the next character, this does the proper decoding
402: * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1.29 daniel 403: * It returns the pointer to the current xmlChar.
1.1 daniel 404: */
405:
406: #define CUR (*ctxt->cur)
407: #define SKIP(val) ctxt->cur += (val)
408: #define NXT(val) ctxt->cur[(val)]
409: #define CUR_PTR ctxt->cur
410:
411: #define SKIP_BLANKS \
412: while (IS_BLANK(*(ctxt->cur))) NEXT
413:
414: #define CURRENT (*ctxt->cur)
415: #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
416:
417: /************************************************************************
418: * *
419: * Error handling routines *
420: * *
421: ************************************************************************/
422:
1.4 daniel 423:
424: const char *xmlXPathErrorMessages[] = {
425: "Ok",
426: "Number encoding",
427: "Unfinished litteral",
428: "Start of litteral",
429: "Expected $ for variable reference",
430: "Undefined variable",
431: "Invalid predicate",
432: "Invalid expression",
433: "Missing closing curly brace",
434: "Unregistered function",
1.5 daniel 435: "Invalid operand",
1.8 daniel 436: "Invalid type",
437: "Invalid number of arguments",
1.57 veillard 438: "Invalid context size",
439: "Invalid context position",
1.72 veillard 440: "Memory allocation error",
441: "Syntax error",
442: "Resource error",
443: "Sub resource error"
1.4 daniel 444: };
445:
446: /**
447: * xmlXPathError:
448: * @ctxt: the XPath Parser context
449: * @file: the file name
450: * @line: the line number
451: * @no: the error number
452: *
1.10 daniel 453: * Create a new xmlNodeSetPtr of type double and of value @val
1.4 daniel 454: *
455: * Returns the newly created object.
456: */
457: void
458: xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
459: int line, int no) {
460: int n;
1.29 daniel 461: const xmlChar *cur;
462: const xmlChar *base;
1.4 daniel 463:
1.9 daniel 464: fprintf(xmlXPathDebug, "Error %s:%d: %s\n", file, line,
1.4 daniel 465: xmlXPathErrorMessages[no]);
466:
467: cur = ctxt->cur;
468: base = ctxt->base;
469: while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
470: cur--;
471: }
472: n = 0;
473: while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
474: cur--;
475: if ((*cur == '\n') || (*cur == '\r')) cur++;
476: base = cur;
477: n = 0;
478: while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1.9 daniel 479: fprintf(xmlXPathDebug, "%c", (unsigned char) *cur++);
1.4 daniel 480: n++;
481: }
1.9 daniel 482: fprintf(xmlXPathDebug, "\n");
1.4 daniel 483: cur = ctxt->cur;
484: while ((*cur == '\n') || (*cur == '\r'))
485: cur--;
486: n = 0;
487: while ((cur != base) && (n++ < 80)) {
1.9 daniel 488: fprintf(xmlXPathDebug, " ");
1.4 daniel 489: base++;
490: }
1.9 daniel 491: fprintf(xmlXPathDebug,"^\n");
1.4 daniel 492: }
1.1 daniel 493:
494:
495: /************************************************************************
496: * *
497: * Routines to handle NodeSets *
498: * *
499: ************************************************************************/
500:
501: #define XML_NODESET_DEFAULT 10
502: /**
503: * xmlXPathNodeSetCreate:
504: * @val: an initial xmlNodePtr, or NULL
505: *
1.10 daniel 506: * Create a new xmlNodeSetPtr of type double and of value @val
1.1 daniel 507: *
508: * Returns the newly created object.
509: */
510: xmlNodeSetPtr
511: xmlXPathNodeSetCreate(xmlNodePtr val) {
512: xmlNodeSetPtr ret;
513:
1.25 daniel 514: ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1.1 daniel 515: if (ret == NULL) {
1.9 daniel 516: fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
1.1 daniel 517: return(NULL);
518: }
1.11 veillard 519: memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1.1 daniel 520: if (val != NULL) {
1.25 daniel 521: ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1.1 daniel 522: sizeof(xmlNodePtr));
523: if (ret->nodeTab == NULL) {
1.9 daniel 524: fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
1.1 daniel 525: return(NULL);
526: }
527: memset(ret->nodeTab, 0 ,
1.11 veillard 528: XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1.1 daniel 529: ret->nodeMax = XML_NODESET_DEFAULT;
530: ret->nodeTab[ret->nodeNr++] = val;
531: }
532: return(ret);
533: }
534:
535: /**
536: * xmlXPathNodeSetAdd:
537: * @cur: the initial node set
538: * @val: a new xmlNodePtr
539: *
540: * add a new xmlNodePtr ot an existing NodeSet
541: */
542: void
543: xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
544: int i;
545:
546: if (val == NULL) return;
547:
548: /*
549: * check against doublons
550: */
551: for (i = 0;i < cur->nodeNr;i++)
552: if (cur->nodeTab[i] == val) return;
553:
554: /*
555: * grow the nodeTab if needed
556: */
557: if (cur->nodeMax == 0) {
1.25 daniel 558: cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1.1 daniel 559: sizeof(xmlNodePtr));
560: if (cur->nodeTab == NULL) {
1.9 daniel 561: fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
1.1 daniel 562: return;
563: }
564: memset(cur->nodeTab, 0 ,
1.11 veillard 565: XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1.1 daniel 566: cur->nodeMax = XML_NODESET_DEFAULT;
567: } else if (cur->nodeNr == cur->nodeMax) {
568: xmlNodePtr *temp;
569:
570: cur->nodeMax *= 2;
1.25 daniel 571: temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1.1 daniel 572: sizeof(xmlNodePtr));
573: if (temp == NULL) {
1.9 daniel 574: fprintf(xmlXPathDebug, "xmlXPathNodeSetAdd: out of memory\n");
1.1 daniel 575: return;
576: }
1.22 daniel 577: cur->nodeTab = temp;
1.1 daniel 578: }
579: cur->nodeTab[cur->nodeNr++] = val;
580: }
581:
582: /**
1.4 daniel 583: * xmlXPathNodeSetMerge:
1.74 veillard 584: * @val1: the first NodeSet or NULL
1.4 daniel 585: * @val2: the second NodeSet
586: *
587: * Merges two nodesets, all nodes from @val2 are added to @val1
1.74 veillard 588: * if @val1 is NULL, a new set is created and copied from @val2
1.4 daniel 589: *
590: * Returns val1 once extended or NULL in case of error.
591: */
592: xmlNodeSetPtr
593: xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
594: int i;
595:
596: if (val2 == NULL) return(val1);
1.74 veillard 597: if (val1 == NULL) {
598: val1 = xmlXPathNodeSetCreate(NULL);
599: }
1.4 daniel 600:
601: /*
1.6 daniel 602: * !!!!! this can be optimized a lot, knowing that both
1.4 daniel 603: * val1 and val2 already have unicity of their values.
604: */
605:
606: for (i = 0;i < val2->nodeNr;i++)
607: xmlXPathNodeSetAdd(val1, val2->nodeTab[i]);
608:
609: return(val1);
610: }
611:
612: /**
1.1 daniel 613: * xmlXPathNodeSetDel:
614: * @cur: the initial node set
615: * @val: an xmlNodePtr
616: *
617: * Removes an xmlNodePtr from an existing NodeSet
618: */
619: void
620: xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
621: int i;
622:
1.5 daniel 623: if (cur == NULL) return;
1.1 daniel 624: if (val == NULL) return;
625:
626: /*
627: * check against doublons
628: */
629: for (i = 0;i < cur->nodeNr;i++)
630: if (cur->nodeTab[i] == val) break;
631:
632: if (i >= cur->nodeNr) {
633: #ifdef DEBUG
1.9 daniel 634: fprintf(xmlXPathDebug,
1.1 daniel 635: "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
636: val->name);
637: #endif
638: return;
639: }
640: cur->nodeNr--;
641: for (;i < cur->nodeNr;i++)
642: cur->nodeTab[i] = cur->nodeTab[i + 1];
643: cur->nodeTab[cur->nodeNr] = NULL;
644: }
645:
646: /**
1.5 daniel 647: * xmlXPathNodeSetRemove:
648: * @cur: the initial node set
649: * @val: the index to remove
650: *
651: * Removes an entry from an existing NodeSet list.
652: */
653: void
654: xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
655: if (cur == NULL) return;
656: if (val >= cur->nodeNr) return;
657: cur->nodeNr--;
658: for (;val < cur->nodeNr;val++)
659: cur->nodeTab[val] = cur->nodeTab[val + 1];
660: cur->nodeTab[cur->nodeNr] = NULL;
661: }
662:
663: /**
1.1 daniel 664: * xmlXPathFreeNodeSet:
665: * @obj: the xmlNodeSetPtr to free
666: *
667: * Free the NodeSet compound (not the actual nodes !).
668: */
669: void
670: xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
671: if (obj == NULL) return;
672: if (obj->nodeTab != NULL) {
673: #ifdef DEBUG
1.11 veillard 674: memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
1.1 daniel 675: #endif
1.25 daniel 676: xmlFree(obj->nodeTab);
1.1 daniel 677: }
678: #ifdef DEBUG
1.11 veillard 679: memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
1.1 daniel 680: #endif
1.25 daniel 681: xmlFree(obj);
1.1 daniel 682: }
683:
1.22 daniel 684: #if defined(DEBUG) || defined(DEBUG_STEP)
1.4 daniel 685: /**
686: * xmlXPathDebugNodeSet:
687: * @output: a FILE * for the output
688: * @obj: the xmlNodeSetPtr to free
689: *
690: * Quick display of a NodeSet
691: */
692: void
693: xmlXPathDebugNodeSet(FILE *output, xmlNodeSetPtr obj) {
694: int i;
695:
1.9 daniel 696: if (output == NULL) output = xmlXPathDebug;
1.4 daniel 697: if (obj == NULL) {
698: fprintf(output, "NodeSet == NULL !\n");
699: return;
700: }
701: if (obj->nodeNr == 0) {
702: fprintf(output, "NodeSet is empty\n");
703: return;
704: }
705: if (obj->nodeTab == NULL) {
706: fprintf(output, " nodeTab == NULL !\n");
707: return;
708: }
709: for (i = 0; i < obj->nodeNr; i++) {
710: if (obj->nodeTab[i] == NULL) {
711: fprintf(output, " NULL !\n");
712: return;
713: }
1.32 daniel 714: if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
715: (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
1.14 daniel 716: fprintf(output, " /");
717: else if (obj->nodeTab[i]->name == NULL)
1.4 daniel 718: fprintf(output, " noname!");
719: else fprintf(output, " %s", obj->nodeTab[i]->name);
720: }
721: fprintf(output, "\n");
722: }
723: #endif
724:
1.21 daniel 725: /**
1.1 daniel 726: * xmlXPathNewNodeSet:
727: * @val: the NodePtr value
728: *
729: * Create a new xmlXPathObjectPtr of type NodeSet and initialize
730: * it with the single Node @val
731: *
732: * Returns the newly created object.
733: */
734: xmlXPathObjectPtr
735: xmlXPathNewNodeSet(xmlNodePtr val) {
736: xmlXPathObjectPtr ret;
737:
1.25 daniel 738: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1.1 daniel 739: if (ret == NULL) {
1.59 veillard 740: fprintf(xmlXPathDebug, "xmlXPathNewNodeSet: out of memory\n");
1.1 daniel 741: return(NULL);
742: }
1.11 veillard 743: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.1 daniel 744: ret->type = XPATH_NODESET;
745: ret->nodesetval = xmlXPathNodeSetCreate(val);
746: return(ret);
747: }
748:
749: /**
1.3 daniel 750: * xmlXPathNewNodeSetList:
751: * @val: an existing NodeSet
752: *
753: * Create a new xmlXPathObjectPtr of type NodeSet and initialize
754: * it with the Nodeset @val
755: *
756: * Returns the newly created object.
757: */
758: xmlXPathObjectPtr
759: xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
760: xmlXPathObjectPtr ret;
1.47 daniel 761: int i;
1.3 daniel 762:
1.48 daniel 763: if (val == NULL)
764: ret = NULL;
765: else if (val->nodeTab == NULL)
1.47 daniel 766: ret = xmlXPathNewNodeSet(NULL);
767: else
768: {
769: ret = xmlXPathNewNodeSet(val->nodeTab[0]);
770: for (i = 1; i < val->nodeNr; ++i)
771: xmlXPathNodeSetAdd(ret->nodesetval, val->nodeTab[i]);
1.48 daniel 772: }
1.47 daniel 773:
1.3 daniel 774: return(ret);
775: }
776:
777: /**
1.59 veillard 778: * xmlXPathWrapNodeSet:
779: * @val: the NodePtr value
780: *
781: * Wrap the Nodeset @val in a new xmlXPathObjectPtr
782: *
783: * Returns the newly created object.
784: */
785: xmlXPathObjectPtr
786: xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
787: xmlXPathObjectPtr ret;
788:
789: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
790: if (ret == NULL) {
791: fprintf(xmlXPathDebug, "xmlXPathWrapNodeSet: out of memory\n");
792: return(NULL);
793: }
794: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
795: ret->type = XPATH_NODESET;
796: ret->nodesetval = val;
797: return(ret);
798: }
799:
800: /**
1.35 daniel 801: * xmlXPathFreeNodeSetList:
802: * @obj: an existing NodeSetList object
803: *
804: * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
805: * the list contrary to xmlXPathFreeObject().
806: */
807: void
808: xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
809: if (obj == NULL) return;
810: #ifdef DEBUG
811: memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
812: #endif
813: xmlFree(obj);
814: }
815:
1.71 veillard 816: /************************************************************************
817: * *
1.74 veillard 818: * Routines to handle extra functions *
819: * *
820: ************************************************************************/
821:
822: /**
823: * xmlXPathRegisterFunc:
824: * @ctxt: the XPath context
825: * @name: the function name
826: * @f: the function implementation or NULL
827: *
828: * Register a new function. If @f is NULL it unregisters the function
829: *
830: * Returns 0 in case of success, -1 in case of error
831: */
832: int
833: xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
834: xmlXPathFunction f) {
835: int i;
836:
837: if (ctxt == NULL)
838: return(-1);
839: if (name == NULL)
840: return(-1);
841:
842: for (i = 0;i < ctxt->nb_funcs;i++) {
1.75 veillard 843: if (xmlStrEqual(ctxt->funcs[i].name, name)) {
1.74 veillard 844: /*
845: * It's just an update or a removal
846: */
1.75 veillard 847: ctxt->funcs[i].func = f;
1.74 veillard 848: return(0);
849: }
850: }
851: if (ctxt->max_funcs <= 0) {
852: ctxt->max_funcs = 10;
853: ctxt->nb_funcs = 0;
1.75 veillard 854: ctxt->funcs = (xmlXPathFuncPtr) xmlMalloc(ctxt->max_funcs *
855: sizeof(xmlXPathFunct));
1.74 veillard 856: } else if (ctxt->max_funcs <= ctxt->nb_funcs) {
857: ctxt->max_funcs *= 2;
1.75 veillard 858: ctxt->funcs = (xmlXPathFuncPtr) xmlRealloc(ctxt->funcs,
859: ctxt->max_funcs * sizeof(xmlXPathFunct));
1.74 veillard 860: }
861: if (ctxt->funcs == NULL) {
862: fprintf(xmlXPathDebug, "xmlXPathRegisterFunc: out of memory\n");
863: return(-1);
864: }
1.75 veillard 865: ctxt->funcs[ctxt->nb_funcs].name = xmlStrdup(name);
866: ctxt->funcs[ctxt->nb_funcs].func = f;
867: ctxt->nb_funcs++;
1.74 veillard 868: return(0);
869: }
870:
871: /**
872: * xmlXPathFunctionLookup:
873: * @ctxt: the XPath context
874: * @name: the function name
875: *
876: * Search in the Function array of the context for the given
877: * function.
878: *
879: * Returns the xmlXPathFunction or NULL if not found
880: */
881: xmlXPathFunction
882: xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
883: int i;
884:
885: if (ctxt == NULL)
886: return(NULL);
887: if (name == NULL)
888: return(NULL);
889:
890: for (i = 0;i < ctxt->nb_funcs;i++) {
1.75 veillard 891: if (xmlStrEqual(ctxt->funcs[i].name, name)) {
892: return(ctxt->funcs[i].func);
1.74 veillard 893: }
894: }
895: return(NULL);
896: }
897:
898: /**
899: * xmlXPathRegisteredFuncsCleanup:
900: * @ctxt: the XPath context
901: *
902: * Cleanup the XPath context data associated to registered functions
903: */
904: void
905: xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
906: int i;
907:
908: if (ctxt == NULL)
909: return;
910:
911: for (i = 0;i < ctxt->nb_funcs;i++) {
1.75 veillard 912: xmlFree((xmlChar *) ctxt->funcs[i].name);
1.74 veillard 913: }
914: ctxt->nb_funcs = -1;
915: ctxt->max_funcs = -1;
916: if (ctxt->funcs != NULL)
917: xmlFree(ctxt->funcs);
918: ctxt->funcs = NULL;
919: }
920:
921: /************************************************************************
922: * *
1.71 veillard 923: * Routines to handle Variable *
924: * *
925: ************************************************************************/
1.62 veillard 926:
927: /**
1.74 veillard 928: * xmlXPathRegisterVariable:
929: * @ctxt: the XPath context
930: * @name: the variable name
931: * @value: the variable value or NULL
932: *
933: * Register a new variable value. If @value is NULL it unregisters
934: * the variable
935: *
936: * Returns 0 in case of success, -1 in case of error
937: */
938: int
939: xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
940: xmlXPathObjectPtr value) {
941: int i;
942:
943: if (ctxt == NULL)
944: return(-1);
945: if (name == NULL)
946: return(-1);
947:
948: for (i = 0;i < ctxt->nb_variables;i++) {
1.75 veillard 949: if (xmlStrEqual(ctxt->variables[i].name, name)) {
1.74 veillard 950: /*
951: * It's just an update or a removal
952: */
1.75 veillard 953: if (ctxt->variables[i].value != NULL) {
954: xmlXPathFreeObject(ctxt->variables[i].value);
1.74 veillard 955: }
1.75 veillard 956: ctxt->variables[i].value = xmlXPathObjectCopy(value);
1.74 veillard 957: return(0);
958: }
959: }
960: if (ctxt->max_variables <= 0) {
961: ctxt->max_variables = 10;
962: ctxt->nb_variables = 0;
1.75 veillard 963: ctxt->variables = (xmlXPathVariablePtr)
964: xmlMalloc(ctxt->max_variables * sizeof(xmlXPathVariable));
1.74 veillard 965: } else if (ctxt->max_variables <= ctxt->nb_variables) {
966: ctxt->max_variables *= 2;
1.75 veillard 967: ctxt->variables = (xmlXPathVariablePtr)
1.74 veillard 968: xmlRealloc(ctxt->variables,
1.75 veillard 969: ctxt->max_variables * sizeof(xmlXPathVariable));
1.74 veillard 970: }
971: if (ctxt->variables == NULL) {
972: fprintf(xmlXPathDebug, "xmlXPathRegisterVariable: out of memory\n");
973: return(-1);
974: }
1.75 veillard 975: ctxt->variables[ctxt->nb_variables].name = xmlStrdup(name);
976: ctxt->variables[ctxt->nb_variables].value = xmlXPathObjectCopy(value);
977: ctxt->nb_variables++;
1.74 veillard 978: return(0);
979: }
980:
981: /**
982: * xmlXPathVariableLookup:
983: * @ctxt: the XPath context
1.71 veillard 984: * @name: the variable name
1.62 veillard 985: *
1.71 veillard 986: * Search in the Variable array of the context for the given
987: * variable value.
1.62 veillard 988: *
1.71 veillard 989: * Returns the value or NULL if not found
1.62 veillard 990: */
991: xmlXPathObjectPtr
1.74 veillard 992: xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
993: int i;
994:
995: if (ctxt == NULL)
996: return(NULL);
997: if (name == NULL)
998: return(NULL);
999:
1000: for (i = 0;i < ctxt->nb_variables;i++) {
1.75 veillard 1001: if (xmlStrEqual(ctxt->variables[i].name, name)) {
1002: return(xmlXPathObjectCopy(ctxt->variables[i].value));
1.74 veillard 1003: }
1004: }
1.71 veillard 1005: return(NULL);
1.62 veillard 1006: }
1007:
1.74 veillard 1008: /**
1009: * xmlXPathRegisteredVariablesCleanup:
1010: * @ctxt: the XPath context
1011: *
1012: * Cleanup the XPath context data associated to registered variables
1013: */
1014: void
1015: xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
1016: int i;
1017:
1018: if (ctxt == NULL)
1019: return;
1020:
1021: for (i = 0;i < ctxt->nb_variables;i++) {
1.75 veillard 1022: xmlFree((xmlChar *) ctxt->variables[i].name);
1023: xmlXPathFreeObject(ctxt->variables[i].value);
1.74 veillard 1024: }
1025: ctxt->nb_variables = -1;
1026: ctxt->max_variables = -1;
1027: if (ctxt->variables != NULL)
1028: xmlFree(ctxt->variables);
1029: ctxt->variables = NULL;
1030: }
1031:
1.71 veillard 1032: /************************************************************************
1033: * *
1034: * Routines to handle Values *
1035: * *
1036: ************************************************************************/
1.62 veillard 1037:
1.71 veillard 1038: /* Allocations are terrible, one need to optimize all this !!! */
1.62 veillard 1039:
1040: /**
1.71 veillard 1041: * xmlXPathNewFloat:
1042: * @val: the double value
1.62 veillard 1043: *
1.71 veillard 1044: * Create a new xmlXPathObjectPtr of type double and of value @val
1.62 veillard 1045: *
1046: * Returns the newly created object.
1047: */
1048: xmlXPathObjectPtr
1.71 veillard 1049: xmlXPathNewFloat(double val) {
1.62 veillard 1050: xmlXPathObjectPtr ret;
1051:
1052: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1053: if (ret == NULL) {
1.71 veillard 1054: fprintf(xmlXPathDebug, "xmlXPathNewFloat: out of memory\n");
1.62 veillard 1055: return(NULL);
1056: }
1057: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71 veillard 1058: ret->type = XPATH_NUMBER;
1059: ret->floatval = val;
1.62 veillard 1060: return(ret);
1061: }
1062:
1063: /**
1.71 veillard 1064: * xmlXPathNewBoolean:
1065: * @val: the boolean value
1.62 veillard 1066: *
1.71 veillard 1067: * Create a new xmlXPathObjectPtr of type boolean and of value @val
1.62 veillard 1068: *
1069: * Returns the newly created object.
1070: */
1071: xmlXPathObjectPtr
1.71 veillard 1072: xmlXPathNewBoolean(int val) {
1.62 veillard 1073: xmlXPathObjectPtr ret;
1074:
1075: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1076: if (ret == NULL) {
1.71 veillard 1077: fprintf(xmlXPathDebug, "xmlXPathNewBoolean: out of memory\n");
1.62 veillard 1078: return(NULL);
1079: }
1080: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71 veillard 1081: ret->type = XPATH_BOOLEAN;
1082: ret->boolval = (val != 0);
1.62 veillard 1083: return(ret);
1084: }
1085:
1086: /**
1.71 veillard 1087: * xmlXPathNewString:
1088: * @val: the xmlChar * value
1.62 veillard 1089: *
1.71 veillard 1090: * Create a new xmlXPathObjectPtr of type string and of value @val
1.62 veillard 1091: *
1092: * Returns the newly created object.
1093: */
1094: xmlXPathObjectPtr
1.71 veillard 1095: xmlXPathNewString(const xmlChar *val) {
1.62 veillard 1096: xmlXPathObjectPtr ret;
1097:
1098: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1099: if (ret == NULL) {
1.71 veillard 1100: fprintf(xmlXPathDebug, "xmlXPathNewString: out of memory\n");
1.62 veillard 1101: return(NULL);
1102: }
1103: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71 veillard 1104: ret->type = XPATH_STRING;
1105: ret->stringval = xmlStrdup(val);
1.62 veillard 1106: return(ret);
1107: }
1108:
1109: /**
1.71 veillard 1110: * xmlXPathNewCString:
1111: * @val: the char * value
1.62 veillard 1112: *
1.71 veillard 1113: * Create a new xmlXPathObjectPtr of type string and of value @val
1.62 veillard 1114: *
1115: * Returns the newly created object.
1116: */
1117: xmlXPathObjectPtr
1.71 veillard 1118: xmlXPathNewCString(const char *val) {
1.62 veillard 1119: xmlXPathObjectPtr ret;
1120:
1121: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1122: if (ret == NULL) {
1.71 veillard 1123: fprintf(xmlXPathDebug, "xmlXPathNewCString: out of memory\n");
1.62 veillard 1124: return(NULL);
1125: }
1126: memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
1.71 veillard 1127: ret->type = XPATH_STRING;
1128: ret->stringval = xmlStrdup(BAD_CAST val);
1.62 veillard 1129: return(ret);
1130: }
1131:
1.35 daniel 1132: /**
1.74 veillard 1133: * xmlXPathObjectCopy:
1134: * @val: the original object
1135: *
1136: * allocate a new copy of a given object
1137: *
1138: * Returns the newly created object.
1139: */
1140: xmlXPathObjectPtr
1141: xmlXPathObjectCopy(xmlXPathObjectPtr val) {
1142: xmlXPathObjectPtr ret;
1143:
1144: if (val == NULL)
1145: return(NULL);
1146:
1147: ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
1148: if (ret == NULL) {
1149: fprintf(xmlXPathDebug, "xmlXPathObjectCopy: out of memory\n");
1150: return(NULL);
1151: }
1152: memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
1153: switch (val->type) {
1154: case XPATH_BOOLEAN:
1155: case XPATH_NUMBER:
1156: case XPATH_STRING:
1157: case XPATH_POINT:
1158: case XPATH_RANGE:
1159: break;
1160: case XPATH_NODESET:
1161: ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
1162: break;
1163: case XPATH_LOCATIONSET:
1164: #ifdef LIBXML_XPTR_ENABLED
1165: {
1166: xmlLocationSetPtr loc = val->user;
1167: ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
1168: break;
1169: }
1170: #endif
1171: case XPATH_UNDEFINED:
1172: case XPATH_USERS:
1173: fprintf(xmlXPathDebug, "xmlXPathObjectCopy: unsupported type %d\n",
1174: val->type);
1175: }
1176: return(ret);
1177: }
1178:
1179: /**
1.1 daniel 1180: * xmlXPathFreeObject:
1181: * @obj: the object to free
1182: *
1183: * Free up an xmlXPathObjectPtr object.
1184: */
1185: void
1186: xmlXPathFreeObject(xmlXPathObjectPtr obj) {
1187: if (obj == NULL) return;
1.62 veillard 1188: if (obj->type == XPATH_NODESET) {
1189: if (obj->nodesetval != NULL)
1190: xmlXPathFreeNodeSet(obj->nodesetval);
1.72 veillard 1191: #ifdef LIBXML_XPTR_ENABLED
1.70 veillard 1192: } else if (obj->type == XPATH_LOCATIONSET) {
1193: if (obj->user != NULL)
1.73 veillard 1194: xmlXPtrFreeLocationSet(obj->user);
1.72 veillard 1195: #endif
1.62 veillard 1196: } else if (obj->type == XPATH_STRING) {
1197: if (obj->stringval != NULL)
1198: xmlFree(obj->stringval);
1199: }
1200:
1.1 daniel 1201: #ifdef DEBUG
1.11 veillard 1202: memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
1.1 daniel 1203: #endif
1.25 daniel 1204: xmlFree(obj);
1.1 daniel 1205: }
1206:
1207: /************************************************************************
1208: * *
1209: * Routines to handle XPath contexts *
1210: * *
1211: ************************************************************************/
1212:
1213: /**
1214: * xmlXPathNewContext:
1.2 daniel 1215: * @doc: the XML document
1.1 daniel 1216: *
1217: * Create a new xmlXPathContext
1218: *
1219: * Returns the xmlXPathContext just allocated.
1220: */
1221: xmlXPathContextPtr
1.26 daniel 1222: xmlXPathNewContext(xmlDocPtr doc) {
1.1 daniel 1223: xmlXPathContextPtr ret;
1224:
1.25 daniel 1225: ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
1.1 daniel 1226: if (ret == NULL) {
1.9 daniel 1227: fprintf(xmlXPathDebug, "xmlXPathNewContext: out of memory\n");
1.1 daniel 1228: return(NULL);
1229: }
1.11 veillard 1230: memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
1.2 daniel 1231: ret->doc = doc;
1.35 daniel 1232: ret->node = NULL;
1.26 daniel 1233:
1234: ret->nb_variables = 0;
1235: ret->max_variables = 0;
1236: ret->variables = NULL;
1237:
1238: ret->nb_types = 0;
1239: ret->max_types = 0;
1240: ret->types = NULL;
1241:
1242: ret->nb_funcs = 0;
1243: ret->max_funcs = 0;
1244: ret->funcs = NULL;
1245:
1246: ret->nb_axis = 0;
1247: ret->max_axis = 0;
1248: ret->axis = NULL;
1249:
1.19 daniel 1250: ret->namespaces = NULL;
1.26 daniel 1251: ret->user = NULL;
1.19 daniel 1252: ret->nsNr = 0;
1.57 veillard 1253:
1254: ret->contextSize = -1;
1255: ret->proximityPosition = -1;
1.1 daniel 1256: return(ret);
1257: }
1258:
1259: /**
1260: * xmlXPathFreeContext:
1261: * @ctxt: the context to free
1262: *
1263: * Free up an xmlXPathContext
1264: */
1265: void
1266: xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
1.19 daniel 1267: if (ctxt->namespaces != NULL)
1.25 daniel 1268: xmlFree(ctxt->namespaces);
1.19 daniel 1269:
1.74 veillard 1270: xmlXPathRegisteredFuncsCleanup(ctxt);
1271: xmlXPathRegisteredVariablesCleanup(ctxt);
1.1 daniel 1272: #ifdef DEBUG
1.11 veillard 1273: memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
1.1 daniel 1274: #endif
1.25 daniel 1275: xmlFree(ctxt);
1.1 daniel 1276: }
1277:
1278: /************************************************************************
1279: * *
1280: * Routines to handle XPath parser contexts *
1281: * *
1282: ************************************************************************/
1283:
1.59 veillard 1284: #define CHECK_CTXT(ctxt) \
1.2 daniel 1285: if (ctxt == NULL) { \
1.9 daniel 1286: fprintf(xmlXPathDebug, "%s:%d Internal error: ctxt == NULL\n", \
1.2 daniel 1287: __FILE__, __LINE__); \
1288: } \
1289:
1290:
1.59 veillard 1291: #define CHECK_CONTEXT(ctxt) \
1.2 daniel 1292: if (ctxt == NULL) { \
1.9 daniel 1293: fprintf(xmlXPathDebug, "%s:%d Internal error: no context\n", \
1.2 daniel 1294: __FILE__, __LINE__); \
1295: } \
1296: if (ctxt->doc == NULL) { \
1.9 daniel 1297: fprintf(xmlXPathDebug, "%s:%d Internal error: no document\n", \
1.2 daniel 1298: __FILE__, __LINE__); \
1299: } \
1.42 daniel 1300: if (ctxt->doc->children == NULL) { \
1.9 daniel 1301: fprintf(xmlXPathDebug, \
1302: "%s:%d Internal error: document without root\n", \
1.2 daniel 1303: __FILE__, __LINE__); \
1304: } \
1305:
1306:
1.1 daniel 1307: /**
1308: * xmlXPathNewParserContext:
1309: * @str: the XPath expression
1310: * @ctxt: the XPath context
1311: *
1312: * Create a new xmlXPathParserContext
1313: *
1314: * Returns the xmlXPathParserContext just allocated.
1315: */
1316: xmlXPathParserContextPtr
1.29 daniel 1317: xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
1.1 daniel 1318: xmlXPathParserContextPtr ret;
1319:
1.25 daniel 1320: ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
1.1 daniel 1321: if (ret == NULL) {
1.9 daniel 1322: fprintf(xmlXPathDebug, "xmlXPathNewParserContext: out of memory\n");
1.1 daniel 1323: return(NULL);
1324: }
1.11 veillard 1325: memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
1.1 daniel 1326: ret->cur = ret->base = str;
1327: ret->context = ctxt;
1328:
1329: /* Allocate the value stack */
1330: ret->valueTab = (xmlXPathObjectPtr *)
1.25 daniel 1331: xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
1.1 daniel 1332: ret->valueNr = 0;
1333: ret->valueMax = 10;
1334: ret->value = NULL;
1335: return(ret);
1336: }
1337:
1338: /**
1339: * xmlXPathFreeParserContext:
1340: * @ctxt: the context to free
1341: *
1342: * Free up an xmlXPathParserContext
1343: */
1344: void
1345: xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
1346: if (ctxt->valueTab != NULL) {
1347: #ifdef DEBUG
1.11 veillard 1348: memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
1.1 daniel 1349: #endif
1.25 daniel 1350: xmlFree(ctxt->valueTab);
1.1 daniel 1351: }
1352: #ifdef DEBUG
1.11 veillard 1353: memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
1.1 daniel 1354: #endif
1.25 daniel 1355: xmlFree(ctxt);
1.1 daniel 1356: }
1357:
1358: /************************************************************************
1359: * *
1360: * The implicit core function library *
1361: * *
1362: ************************************************************************/
1363:
1.3 daniel 1364: /*
1.6 daniel 1365: * Auto-pop and cast to a number
1366: */
1.8 daniel 1367: void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
1368:
1.6 daniel 1369:
1370: #define POP_FLOAT \
1371: arg = valuePop(ctxt); \
1372: if (arg == NULL) { \
1.49 daniel 1373: XP_ERROR(XPATH_INVALID_OPERAND); \
1.6 daniel 1374: } \
1375: if (arg->type != XPATH_NUMBER) { \
1376: valuePush(ctxt, arg); \
1.10 daniel 1377: xmlXPathNumberFunction(ctxt, 1); \
1.6 daniel 1378: arg = valuePop(ctxt); \
1379: }
1380:
1.1 daniel 1381: /**
1.18 daniel 1382: * xmlXPathEqualNodeSetString
1383: * @arg: the nodeset object argument
1384: * @str: the string to compare to.
1385: *
1386: * Implement the equal operation on XPath objects content: @arg1 == @arg2
1387: * If one object to be compared is a node-set and the other is a string,
1388: * then the comparison will be true if and only if there is a node in
1389: * the node-set such that the result of performing the comparison on the
1390: * string-value of the node and the other string is true.
1391: *
1392: * Returns 0 or 1 depending on the results of the test.
1393: */
1394: int
1.29 daniel 1395: xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
1.18 daniel 1396: int i;
1397: xmlNodeSetPtr ns;
1.29 daniel 1398: xmlChar *str2;
1.18 daniel 1399:
1400: if ((str == NULL) || (arg == NULL) || (arg->type != XPATH_NODESET))
1401: return(0);
1402: ns = arg->nodesetval;
1403: for (i = 0;i < ns->nodeNr;i++) {
1404: str2 = xmlNodeGetContent(ns->nodeTab[i]);
1.58 veillard 1405: if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
1.25 daniel 1406: xmlFree(str2);
1.18 daniel 1407: return(1);
1408: }
1.25 daniel 1409: xmlFree(str2);
1.18 daniel 1410: }
1411: return(0);
1412: }
1413:
1414: /**
1415: * xmlXPathEqualNodeSetFloat
1416: * @arg: the nodeset object argument
1417: * @f: the float to compare to
1418: *
1419: * Implement the equal operation on XPath objects content: @arg1 == @arg2
1420: * If one object to be compared is a node-set and the other is a number,
1421: * then the comparison will be true if and only if there is a node in
1422: * the node-set such that the result of performing the comparison on the
1423: * number to be compared and on the result of converting the string-value
1424: * of that node to a number using the number function is true.
1425: *
1426: * Returns 0 or 1 depending on the results of the test.
1427: */
1428: int
1429: xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, float f) {
1.21 daniel 1430: char buf[100] = "";
1.18 daniel 1431:
1432: if ((arg == NULL) || (arg->type != XPATH_NODESET))
1433: return(0);
1434:
1435: if (isnan(f))
1436: sprintf(buf, "NaN");
1437: else if (isinf(f) > 0)
1438: sprintf(buf, "+Infinity");
1439: else if (isinf(f) < 0)
1440: sprintf(buf, "-Infinity");
1441: else
1442: sprintf(buf, "%0g", f);
1443:
1.21 daniel 1444: return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
1.18 daniel 1445: }
1446:
1447:
1448: /**
1449: * xmlXPathEqualNodeSets
1450: * @arg1: first nodeset object argument
1451: * @arg2: second nodeset object argument
1452: *
1453: * Implement the equal operation on XPath nodesets: @arg1 == @arg2
1454: * If both objects to be compared are node-sets, then the comparison
1455: * will be true if and only if there is a node in the first node-set and
1456: * a node in the second node-set such that the result of performing the
1457: * comparison on the string-values of the two nodes is true.
1458: *
1459: * (needless to say, this is a costly operation)
1460: *
1461: * Returns 0 or 1 depending on the results of the test.
1462: */
1463: int
1464: xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
1465: int i;
1466: xmlNodeSetPtr ns;
1.29 daniel 1467: xmlChar *str;
1.18 daniel 1468:
1469: if ((arg1 == NULL) || (arg1->type != XPATH_NODESET))
1470: return(0);
1471: if ((arg2 == NULL) || (arg2->type != XPATH_NODESET))
1472: return(0);
1473:
1474: ns = arg1->nodesetval;
1475: for (i = 0;i < ns->nodeNr;i++) {
1476: str = xmlNodeGetContent(ns->nodeTab[i]);
1477: if ((str != NULL) && (xmlXPathEqualNodeSetString(arg2, str))) {
1.25 daniel 1478: xmlFree(str);
1.18 daniel 1479: return(1);
1480: }
1.25 daniel 1481: xmlFree(str);
1.18 daniel 1482: }
1483: return(0);
1484: }
1485:
1486: /**
1.1 daniel 1487: * xmlXPathEqualValues:
1.18 daniel 1488: * @ctxt: the XPath Parser context
1.1 daniel 1489: *
1490: * Implement the equal operation on XPath objects content: @arg1 == @arg2
1491: *
1492: * Returns 0 or 1 depending on the results of the test.
1493: */
1494: int
1.18 daniel 1495: xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
1496: xmlXPathObjectPtr arg1, arg2;
1497: int ret = 0;
1498:
1499: arg1 = valuePop(ctxt);
1500: if (arg1 == NULL)
1.49 daniel 1501: XP_ERROR0(XPATH_INVALID_OPERAND);
1.18 daniel 1502:
1503: arg2 = valuePop(ctxt);
1504: if (arg2 == NULL) {
1505: xmlXPathFreeObject(arg1);
1.49 daniel 1506: XP_ERROR0(XPATH_INVALID_OPERAND);
1.18 daniel 1507: }
1508:
1.5 daniel 1509: if (arg1 == arg2) {
1510: #ifdef DEBUG_EXPR
1.9 daniel 1511: fprintf(xmlXPathDebug, "Equal: by pointer\n");
1.5 daniel 1512: #endif
1513: return(1);
1514: }
1.18 daniel 1515:
1.3 daniel 1516: switch (arg1->type) {
1517: case XPATH_UNDEFINED:
1.5 daniel 1518: #ifdef DEBUG_EXPR
1.9 daniel 1519: fprintf(xmlXPathDebug, "Equal: undefined\n");
1.5 daniel 1520: #endif
1.18 daniel 1521: break;
1.3 daniel 1522: case XPATH_NODESET:
1.18 daniel 1523: switch (arg2->type) {
1524: case XPATH_UNDEFINED:
1525: #ifdef DEBUG_EXPR
1526: fprintf(xmlXPathDebug, "Equal: undefined\n");
1527: #endif
1528: break;
1529: case XPATH_NODESET:
1530: ret = xmlXPathEqualNodeSets(arg1, arg2);
1531: break;
1532: case XPATH_BOOLEAN:
1533: if ((arg1->nodesetval == NULL) ||
1534: (arg1->nodesetval->nodeNr == 0)) ret = 0;
1535: else
1536: ret = 1;
1537: ret = (ret == arg2->boolval);
1538: break;
1539: case XPATH_NUMBER:
1540: ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
1541: break;
1542: case XPATH_STRING:
1543: ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
1544: break;
1.59 veillard 1545: case XPATH_USERS:
1.62 veillard 1546: case XPATH_POINT:
1547: case XPATH_RANGE:
1.63 veillard 1548: case XPATH_LOCATIONSET:
1.59 veillard 1549: TODO
1550: break;
1.18 daniel 1551: }
1.3 daniel 1552: break;
1553: case XPATH_BOOLEAN:
1.18 daniel 1554: switch (arg2->type) {
1555: case XPATH_UNDEFINED:
1.5 daniel 1556: #ifdef DEBUG_EXPR
1.18 daniel 1557: fprintf(xmlXPathDebug, "Equal: undefined\n");
1.5 daniel 1558: #endif
1.18 daniel 1559: break;
1560: case XPATH_NODESET:
1561: if ((arg2->nodesetval == NULL) ||
1562: (arg2->nodesetval->nodeNr == 0)) ret = 0;
1563: else
1564: ret = 1;
1565: break;
1566: case XPATH_BOOLEAN:
1567: #ifdef DEBUG_EXPR
1568: fprintf(xmlXPathDebug, "Equal: %d boolean %d \n",
1569: arg1->boolval, arg2->boolval);
1570: #endif
1571: ret = (arg1->boolval == arg2->boolval);
1572: break;
1573: case XPATH_NUMBER:
1574: if (arg2->floatval) ret = 1;
1575: else ret = 0;
1576: ret = (arg1->boolval == ret);
1577: break;
1578: case XPATH_STRING:
1579: if ((arg2->stringval == NULL) ||
1580: (arg2->stringval[0] == 0)) ret = 0;
1581: else
1582: ret = 1;
1583: ret = (arg1->boolval == ret);
1584: break;
1.59 veillard 1585: case XPATH_USERS:
1.62 veillard 1586: case XPATH_POINT:
1587: case XPATH_RANGE:
1.63 veillard 1588: case XPATH_LOCATIONSET:
1.59 veillard 1589: TODO
1590: break;
1.18 daniel 1591: }
1592: break;
1.3 daniel 1593: case XPATH_NUMBER:
1.18 daniel 1594: switch (arg2->type) {
1595: case XPATH_UNDEFINED:
1.5 daniel 1596: #ifdef DEBUG_EXPR
1.18 daniel 1597: fprintf(xmlXPathDebug, "Equal: undefined\n");
1.5 daniel 1598: #endif
1.18 daniel 1599: break;
1600: case XPATH_NODESET:
1601: ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
1602: break;
1603: case XPATH_BOOLEAN:
1604: if (arg1->floatval) ret = 1;
1605: else ret = 0;
1606: ret = (arg2->boolval == ret);
1607: break;
1608: case XPATH_STRING:
1609: valuePush(ctxt, arg2);
1610: xmlXPathNumberFunction(ctxt, 1);
1611: arg2 = valuePop(ctxt);
1612: /* no break on purpose */
1613: case XPATH_NUMBER:
1614: ret = (arg1->floatval == arg2->floatval);
1615: break;
1.59 veillard 1616: case XPATH_USERS:
1.62 veillard 1617: case XPATH_POINT:
1618: case XPATH_RANGE:
1.63 veillard 1619: case XPATH_LOCATIONSET:
1.59 veillard 1620: TODO
1621: break;
1.18 daniel 1622: }
1623: break;
1.3 daniel 1624: case XPATH_STRING:
1.18 daniel 1625: switch (arg2->type) {
1626: case XPATH_UNDEFINED:
1627: #ifdef DEBUG_EXPR
1628: fprintf(xmlXPathDebug, "Equal: undefined\n");
1629: #endif
1630: break;
1631: case XPATH_NODESET:
1632: ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
1633: break;
1634: case XPATH_BOOLEAN:
1635: if ((arg1->stringval == NULL) ||
1636: (arg1->stringval[0] == 0)) ret = 0;
1637: else
1638: ret = 1;
1639: ret = (arg2->boolval == ret);
1640: break;
1641: case XPATH_STRING:
1.58 veillard 1642: ret = xmlStrEqual(arg1->stringval, arg2->stringval);
1.18 daniel 1643: break;
1644: case XPATH_NUMBER:
1645: valuePush(ctxt, arg1);
1646: xmlXPathNumberFunction(ctxt, 1);
1647: arg1 = valuePop(ctxt);
1648: ret = (arg1->floatval == arg2->floatval);
1649: break;
1.59 veillard 1650: case XPATH_USERS:
1.62 veillard 1651: case XPATH_POINT:
1652: case XPATH_RANGE:
1.63 veillard 1653: case XPATH_LOCATIONSET:
1.59 veillard 1654: TODO
1655: break;
1.18 daniel 1656: }
1657: break;
1.59 veillard 1658: case XPATH_USERS:
1.62 veillard 1659: case XPATH_POINT:
1660: case XPATH_RANGE:
1.63 veillard 1661: case XPATH_LOCATIONSET:
1.59 veillard 1662: TODO
1663: break;
1.3 daniel 1664: }
1.18 daniel 1665: xmlXPathFreeObject(arg1);
1666: xmlXPathFreeObject(arg2);
1667: return(ret);
1.1 daniel 1668: }
1669:
1670: /**
1671: * xmlXPathCompareValues:
1.18 daniel 1672: * @ctxt: the XPath Parser context
1.1 daniel 1673: * @inf: less than (1) or greater than (2)
1674: * @strict: is the comparison strict
1675: *
1676: * Implement the compare operation on XPath objects:
1677: * @arg1 < @arg2 (1, 1, ...
1678: * @arg1 <= @arg2 (1, 0, ...
1679: * @arg1 > @arg2 (0, 1, ...
1680: * @arg1 >= @arg2 (0, 0, ...
1681: *
1.18 daniel 1682: * When neither object to be compared is a node-set and the operator is
1683: * <=, <, >=, >, then the objects are compared by converted both objects
1684: * to numbers and comparing the numbers according to IEEE 754. The <
1685: * comparison will be true if and only if the first number is less than the
1686: * second number. The <= comparison will be true if and only if the first
1687: * number is less than or equal to the second number. The > comparison
1688: * will be true if and only if the first number is greater than the second
1689: * number. The >= comparison will be true if and only if the first number
1690: * is greater than or equal to the second number.
1.1 daniel 1691: */
1692: int
1.18 daniel 1693: xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
1694: int ret = 0;
1695: xmlXPathObjectPtr arg1, arg2;
1696:
1697: arg2 = valuePop(ctxt);
1698: if ((arg2 == NULL) || (arg2->type == XPATH_NODESET)) {
1699: if (arg2 != NULL)
1700: xmlXPathFreeObject(arg2);
1.49 daniel 1701: XP_ERROR0(XPATH_INVALID_OPERAND);
1.18 daniel 1702: }
1703:
1704: arg1 = valuePop(ctxt);
1705: if ((arg1 == NULL) || (arg1->type == XPATH_NODESET)) {
1706: if (arg1 != NULL)
1707: xmlXPathFreeObject(arg1);
1708: xmlXPathFreeObject(arg2);
1.49 daniel 1709: XP_ERROR0(XPATH_INVALID_OPERAND);
1.18 daniel 1710: }
1711:
1712: if (arg1->type != XPATH_NUMBER) {
1713: valuePush(ctxt, arg1);
1714: xmlXPathNumberFunction(ctxt, 1);
1715: arg1 = valuePop(ctxt);
1716: }
1717: if (arg1->type != XPATH_NUMBER) {
1718: xmlXPathFreeObject(arg1);
1719: xmlXPathFreeObject(arg2);
1.49 daniel 1720: XP_ERROR0(XPATH_INVALID_OPERAND);
1.18 daniel 1721: }
1722: if (arg2->type != XPATH_NUMBER) {
1723: valuePush(ctxt, arg2);
1724: xmlXPathNumberFunction(ctxt, 1);
1725: arg2 = valuePop(ctxt);
1726: }
1727: if (arg2->type != XPATH_NUMBER) {
1728: xmlXPathFreeObject(arg1);
1729: xmlXPathFreeObject(arg2);
1.49 daniel 1730: XP_ERROR0(XPATH_INVALID_OPERAND);
1.18 daniel 1731: }
1732: /*
1733: * Add tests for infinity and nan
1734: * => feedback on 3.4 for Inf and NaN
1735: */
1736: if (inf && strict)
1737: ret = (arg1->floatval < arg2->floatval);
1738: else if (inf && !strict)
1739: ret = (arg1->floatval <= arg2->floatval);
1740: else if (!inf && strict)
1741: ret = (arg1->floatval > arg2->floatval);
1742: else if (!inf && !strict)
1743: ret = (arg1->floatval >= arg2->floatval);
1744: xmlXPathFreeObject(arg1);
1745: xmlXPathFreeObject(arg2);
1746: return(ret);
1.1 daniel 1747: }
1748:
1749: /**
1750: * xmlXPathValueFlipSign:
1.6 daniel 1751: * @ctxt: the XPath Parser context
1.1 daniel 1752: *
1753: * Implement the unary - operation on an XPath object
1.6 daniel 1754: * The numeric operators convert their operands to numbers as if
1755: * by calling the number function.
1.1 daniel 1756: */
1757: void
1.6 daniel 1758: xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
1759: xmlXPathObjectPtr arg;
1760:
1761: POP_FLOAT
1762: arg->floatval = -arg->floatval;
1763: valuePush(ctxt, arg);
1.1 daniel 1764: }
1765:
1766: /**
1767: * xmlXPathAddValues:
1.6 daniel 1768: * @ctxt: the XPath Parser context
1.1 daniel 1769: *
1.10 daniel 1770: * Implement the add operation on XPath objects:
1.6 daniel 1771: * The numeric operators convert their operands to numbers as if
1772: * by calling the number function.
1.1 daniel 1773: */
1.6 daniel 1774: void
1775: xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
1776: xmlXPathObjectPtr arg;
1.10 daniel 1777: double val;
1.6 daniel 1778:
1779: POP_FLOAT
1780: val = arg->floatval;
1781: xmlXPathFreeObject(arg);
1782:
1783: POP_FLOAT
1784: arg->floatval += val;
1785: valuePush(ctxt, arg);
1.1 daniel 1786: }
1787:
1788: /**
1789: * xmlXPathSubValues:
1.6 daniel 1790: * @ctxt: the XPath Parser context
1.1 daniel 1791: *
1.10 daniel 1792: * Implement the substraction operation on XPath objects:
1.6 daniel 1793: * The numeric operators convert their operands to numbers as if
1794: * by calling the number function.
1795: */
1796: void
1797: xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
1798: xmlXPathObjectPtr arg;
1.10 daniel 1799: double val;
1.6 daniel 1800:
1801: POP_FLOAT
1802: val = arg->floatval;
1803: xmlXPathFreeObject(arg);
1804:
1805: POP_FLOAT
1806: arg->floatval -= val;
1807: valuePush(ctxt, arg);
1.1 daniel 1808: }
1809:
1810: /**
1811: * xmlXPathMultValues:
1.6 daniel 1812: * @ctxt: the XPath Parser context
1.1 daniel 1813: *
1.10 daniel 1814: * Implement the multiply operation on XPath objects:
1.6 daniel 1815: * The numeric operators convert their operands to numbers as if
1816: * by calling the number function.
1.1 daniel 1817: */
1.6 daniel 1818: void
1819: xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
1820: xmlXPathObjectPtr arg;
1.10 daniel 1821: double val;
1.6 daniel 1822:
1823: POP_FLOAT
1824: val = arg->floatval;
1825: xmlXPathFreeObject(arg);
1826:
1827: POP_FLOAT
1828: arg->floatval *= val;
1829: valuePush(ctxt, arg);
1.1 daniel 1830: }
1831:
1832: /**
1833: * xmlXPathDivValues:
1.6 daniel 1834: * @ctxt: the XPath Parser context
1.1 daniel 1835: *
1.10 daniel 1836: * Implement the div operation on XPath objects:
1.6 daniel 1837: * The numeric operators convert their operands to numbers as if
1838: * by calling the number function.
1.1 daniel 1839: */
1.6 daniel 1840: void
1841: xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
1842: xmlXPathObjectPtr arg;
1.10 daniel 1843: double val;
1.6 daniel 1844:
1845: POP_FLOAT
1846: val = arg->floatval;
1847: xmlXPathFreeObject(arg);
1848:
1849: POP_FLOAT
1850: arg->floatval /= val;
1851: valuePush(ctxt, arg);
1.1 daniel 1852: }
1853:
1854: /**
1855: * xmlXPathModValues:
1.6 daniel 1856: * @ctxt: the XPath Parser context
1.1 daniel 1857: *
1858: * Implement the div operation on XPath objects: @arg1 / @arg2
1.6 daniel 1859: * The numeric operators convert their operands to numbers as if
1860: * by calling the number function.
1.1 daniel 1861: */
1.6 daniel 1862: void
1863: xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
1864: xmlXPathObjectPtr arg;
1.10 daniel 1865: double val;
1.6 daniel 1866:
1867: POP_FLOAT
1868: val = arg->floatval;
1869: xmlXPathFreeObject(arg);
1870:
1871: POP_FLOAT
1872: arg->floatval /= val;
1873: valuePush(ctxt, arg);
1.1 daniel 1874: }
1875:
1876: /************************************************************************
1877: * *
1.2 daniel 1878: * The traversal functions *
1879: * *
1880: ************************************************************************/
1881:
1.59 veillard 1882: typedef enum {
1883: AXIS_ANCESTOR = 1,
1884: AXIS_ANCESTOR_OR_SELF,
1885: AXIS_ATTRIBUTE,
1886: AXIS_CHILD,
1887: AXIS_DESCENDANT,
1888: AXIS_DESCENDANT_OR_SELF,
1889: AXIS_FOLLOWING,
1890: AXIS_FOLLOWING_SIBLING,
1891: AXIS_NAMESPACE,
1892: AXIS_PARENT,
1893: AXIS_PRECEDING,
1894: AXIS_PRECEDING_SIBLING,
1895: AXIS_SELF
1896: } xmlXPathAxisVal;
1.3 daniel 1897:
1898: /*
1899: * A traversal function enumerates nodes along an axis.
1900: * Initially it must be called with NULL, and it indicates
1901: * termination on the axis by returning NULL.
1902: */
1903: typedef xmlNodePtr (*xmlXPathTraversalFunction)
1904: (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
1905:
1.2 daniel 1906: /**
1907: * mlXPathNextSelf:
1908: * @ctxt: the XPath Parser context
1909: * @cur: the current node in the traversal
1910: *
1911: * Traversal function for the "self" direction
1912: * he self axis contains just the context node itself
1.19 daniel 1913: *
1914: * Returns the next element following that axis
1.2 daniel 1915: */
1916: xmlNodePtr
1917: xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1918: if (cur == NULL)
1919: return(ctxt->context->node);
1920: return(NULL);
1921: }
1922:
1923: /**
1924: * mlXPathNextChild:
1925: * @ctxt: the XPath Parser context
1926: * @cur: the current node in the traversal
1927: *
1928: * Traversal function for the "child" direction
1929: * The child axis contains the children of the context node in document order.
1.19 daniel 1930: *
1931: * Returns the next element following that axis
1.2 daniel 1932: */
1933: xmlNodePtr
1934: xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14 daniel 1935: if (cur == NULL) {
1.37 daniel 1936: if (ctxt->context->node == NULL) return(NULL);
1937: switch (ctxt->context->node->type) {
1938: case XML_ELEMENT_NODE:
1939: case XML_TEXT_NODE:
1940: case XML_CDATA_SECTION_NODE:
1941: case XML_ENTITY_REF_NODE:
1942: case XML_ENTITY_NODE:
1943: case XML_PI_NODE:
1944: case XML_COMMENT_NODE:
1945: case XML_NOTATION_NODE:
1.42 daniel 1946: case XML_DTD_NODE:
1947: return(ctxt->context->node->children);
1.37 daniel 1948: case XML_DOCUMENT_NODE:
1949: case XML_DOCUMENT_TYPE_NODE:
1950: case XML_DOCUMENT_FRAG_NODE:
1951: case XML_HTML_DOCUMENT_NODE:
1.55 veillard 1952: #ifdef LIBXML_SGML_ENABLED
1953: case XML_SGML_DOCUMENT_NODE:
1954: #endif
1.42 daniel 1955: return(((xmlDocPtr) ctxt->context->node)->children);
1.43 daniel 1956: case XML_ELEMENT_DECL:
1957: case XML_ATTRIBUTE_DECL:
1.44 daniel 1958: case XML_ENTITY_DECL:
1.43 daniel 1959: case XML_ATTRIBUTE_NODE:
1960: return(NULL);
1.37 daniel 1961: }
1962: return(NULL);
1.14 daniel 1963: }
1.35 daniel 1964: if ((cur->type == XML_DOCUMENT_NODE) ||
1965: (cur->type == XML_HTML_DOCUMENT_NODE))
1.14 daniel 1966: return(NULL);
1.2 daniel 1967: return(cur->next);
1968: }
1969:
1970: /**
1971: * mlXPathNextDescendant:
1972: * @ctxt: the XPath Parser context
1973: * @cur: the current node in the traversal
1974: *
1975: * Traversal function for the "descendant" direction
1976: * the descendant axis contains the descendants of the context node in document
1977: * order; a descendant is a child or a child of a child and so on.
1.19 daniel 1978: *
1979: * Returns the next element following that axis
1.2 daniel 1980: */
1981: xmlNodePtr
1982: xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14 daniel 1983: if (cur == NULL) {
1.37 daniel 1984: if (ctxt->context->node == NULL)
1985: return(NULL);
1986: if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
1987: return(NULL);
1988:
1.14 daniel 1989: if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
1.42 daniel 1990: return(ctxt->context->doc->children);
1991: return(ctxt->context->node->children);
1.14 daniel 1992: }
1.2 daniel 1993:
1.48 daniel 1994: if (cur->children != NULL)
1995: {
1996: if (cur->children->type != XML_ENTITY_DECL)
1997: return(cur->children);
1998: }
1.2 daniel 1999: if (cur->next != NULL) return(cur->next);
2000:
2001: do {
2002: cur = cur->parent;
2003: if (cur == NULL) return(NULL);
2004: if (cur == ctxt->context->node) return(NULL);
2005: if (cur->next != NULL) {
2006: cur = cur->next;
2007: return(cur);
2008: }
2009: } while (cur != NULL);
2010: return(cur);
2011: }
2012:
2013: /**
2014: * mlXPathNextDescendantOrSelf:
2015: * @ctxt: the XPath Parser context
2016: * @cur: the current node in the traversal
2017: *
2018: * Traversal function for the "descendant-or-self" direction
2019: * the descendant-or-self axis contains the context node and the descendants
2020: * of the context node in document order; thus the context node is the first
2021: * node on the axis, and the first child of the context node is the second node
2022: * on the axis
1.19 daniel 2023: *
2024: * Returns the next element following that axis
1.2 daniel 2025: */
2026: xmlNodePtr
2027: xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.37 daniel 2028: if (cur == NULL) {
2029: if (ctxt->context->node == NULL)
2030: return(NULL);
2031: if (ctxt->context->node->type == XML_ATTRIBUTE_NODE)
2032: return(NULL);
1.2 daniel 2033: return(ctxt->context->node);
1.37 daniel 2034: }
1.2 daniel 2035:
1.37 daniel 2036: return(xmlXPathNextDescendant(ctxt, cur));
1.2 daniel 2037: }
2038:
2039: /**
2040: * xmlXPathNextParent:
2041: * @ctxt: the XPath Parser context
2042: * @cur: the current node in the traversal
2043: *
2044: * Traversal function for the "parent" direction
2045: * The parent axis contains the parent of the context node, if there is one.
1.19 daniel 2046: *
2047: * Returns the next element following that axis
1.2 daniel 2048: */
2049: xmlNodePtr
2050: xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2051: /*
2052: * the parent of an attribute or namespace node is the element
2053: * to which the attribute or namespace node is attached
1.37 daniel 2054: * Namespace handling !!!
1.2 daniel 2055: */
1.14 daniel 2056: if (cur == NULL) {
1.37 daniel 2057: if (ctxt->context->node == NULL) return(NULL);
2058: switch (ctxt->context->node->type) {
2059: case XML_ELEMENT_NODE:
2060: case XML_TEXT_NODE:
2061: case XML_CDATA_SECTION_NODE:
2062: case XML_ENTITY_REF_NODE:
2063: case XML_ENTITY_NODE:
2064: case XML_PI_NODE:
2065: case XML_COMMENT_NODE:
2066: case XML_NOTATION_NODE:
1.42 daniel 2067: case XML_DTD_NODE:
1.43 daniel 2068: case XML_ELEMENT_DECL:
2069: case XML_ATTRIBUTE_DECL:
1.44 daniel 2070: case XML_ENTITY_DECL:
1.37 daniel 2071: if (ctxt->context->node->parent == NULL)
2072: return((xmlNodePtr) ctxt->context->doc);
2073: return(ctxt->context->node->parent);
2074: case XML_ATTRIBUTE_NODE: {
2075: xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2076:
1.42 daniel 2077: return(att->parent);
1.37 daniel 2078: }
2079: case XML_DOCUMENT_NODE:
2080: case XML_DOCUMENT_TYPE_NODE:
2081: case XML_DOCUMENT_FRAG_NODE:
2082: case XML_HTML_DOCUMENT_NODE:
1.55 veillard 2083: #ifdef LIBXML_SGML_ENABLED
2084: case XML_SGML_DOCUMENT_NODE:
2085: #endif
1.37 daniel 2086: return(NULL);
2087: }
1.14 daniel 2088: }
1.2 daniel 2089: return(NULL);
2090: }
2091:
2092: /**
2093: * xmlXPathNextAncestor:
2094: * @ctxt: the XPath Parser context
2095: * @cur: the current node in the traversal
2096: *
2097: * Traversal function for the "ancestor" direction
2098: * the ancestor axis contains the ancestors of the context node; the ancestors
2099: * of the context node consist of the parent of context node and the parent's
2100: * parent and so on; the nodes are ordered in reverse document order; thus the
2101: * parent is the first node on the axis, and the parent's parent is the second
2102: * node on the axis
1.19 daniel 2103: *
2104: * Returns the next element following that axis
1.2 daniel 2105: */
2106: xmlNodePtr
2107: xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2108: /*
2109: * the parent of an attribute or namespace node is the element
2110: * to which the attribute or namespace node is attached
1.37 daniel 2111: * !!!!!!!!!!!!!
1.2 daniel 2112: */
1.14 daniel 2113: if (cur == NULL) {
1.37 daniel 2114: if (ctxt->context->node == NULL) return(NULL);
2115: switch (ctxt->context->node->type) {
2116: case XML_ELEMENT_NODE:
2117: case XML_TEXT_NODE:
2118: case XML_CDATA_SECTION_NODE:
2119: case XML_ENTITY_REF_NODE:
2120: case XML_ENTITY_NODE:
2121: case XML_PI_NODE:
2122: case XML_COMMENT_NODE:
1.42 daniel 2123: case XML_DTD_NODE:
1.43 daniel 2124: case XML_ELEMENT_DECL:
2125: case XML_ATTRIBUTE_DECL:
1.44 daniel 2126: case XML_ENTITY_DECL:
1.37 daniel 2127: case XML_NOTATION_NODE:
2128: if (ctxt->context->node->parent == NULL)
2129: return((xmlNodePtr) ctxt->context->doc);
2130: return(ctxt->context->node->parent);
2131: case XML_ATTRIBUTE_NODE: {
2132: xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
2133:
1.42 daniel 2134: return(cur->parent);
1.37 daniel 2135: }
2136: case XML_DOCUMENT_NODE:
2137: case XML_DOCUMENT_TYPE_NODE:
2138: case XML_DOCUMENT_FRAG_NODE:
2139: case XML_HTML_DOCUMENT_NODE:
1.55 veillard 2140: #ifdef LIBXML_SGML_ENABLED
2141: case XML_SGML_DOCUMENT_NODE:
2142: #endif
1.37 daniel 2143: return(NULL);
2144: }
2145: return(NULL);
1.14 daniel 2146: }
1.42 daniel 2147: if (cur == ctxt->context->doc->children)
1.14 daniel 2148: return((xmlNodePtr) ctxt->context->doc);
2149: if (cur == (xmlNodePtr) ctxt->context->doc)
2150: return(NULL);
1.37 daniel 2151: switch (cur->type) {
2152: case XML_ELEMENT_NODE:
2153: case XML_TEXT_NODE:
2154: case XML_CDATA_SECTION_NODE:
2155: case XML_ENTITY_REF_NODE:
2156: case XML_ENTITY_NODE:
2157: case XML_PI_NODE:
2158: case XML_COMMENT_NODE:
2159: case XML_NOTATION_NODE:
1.42 daniel 2160: case XML_DTD_NODE:
1.43 daniel 2161: case XML_ELEMENT_DECL:
2162: case XML_ATTRIBUTE_DECL:
1.44 daniel 2163: case XML_ENTITY_DECL:
1.37 daniel 2164: return(cur->parent);
2165: case XML_ATTRIBUTE_NODE: {
2166: xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
2167:
1.42 daniel 2168: return(att->parent);
1.37 daniel 2169: }
2170: case XML_DOCUMENT_NODE:
2171: case XML_DOCUMENT_TYPE_NODE:
2172: case XML_DOCUMENT_FRAG_NODE:
2173: case XML_HTML_DOCUMENT_NODE:
1.55 veillard 2174: #ifdef LIBXML_SGML_ENABLED
2175: case XML_SGML_DOCUMENT_NODE:
2176: #endif
1.37 daniel 2177: return(NULL);
2178: }
2179: return(NULL);
1.2 daniel 2180: }
2181:
2182: /**
2183: * xmlXPathNextAncestorOrSelf:
2184: * @ctxt: the XPath Parser context
2185: * @cur: the current node in the traversal
2186: *
2187: * Traversal function for the "ancestor-or-self" direction
1.19 daniel 2188: * he ancestor-or-self axis contains the context node and ancestors of
2189: * the context node in reverse document order; thus the context node is
2190: * the first node on the axis, and the context node's parent the second;
2191: * parent here is defined the same as with the parent axis.
2192: *
2193: * Returns the next element following that axis
1.2 daniel 2194: */
2195: xmlNodePtr
2196: xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2197: if (cur == NULL)
2198: return(ctxt->context->node);
1.37 daniel 2199: return(xmlXPathNextAncestor(ctxt, cur));
1.2 daniel 2200: }
2201:
2202: /**
2203: * xmlXPathNextFollowingSibling:
2204: * @ctxt: the XPath Parser context
2205: * @cur: the current node in the traversal
2206: *
2207: * Traversal function for the "following-sibling" direction
2208: * The following-sibling axis contains the following siblings of the context
2209: * node in document order.
1.19 daniel 2210: *
2211: * Returns the next element following that axis
1.2 daniel 2212: */
2213: xmlNodePtr
2214: xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14 daniel 2215: if (cur == (xmlNodePtr) ctxt->context->doc)
2216: return(NULL);
1.2 daniel 2217: if (cur == NULL)
2218: return(ctxt->context->node->next);
2219: return(cur->next);
2220: }
2221:
2222: /**
2223: * xmlXPathNextPrecedingSibling:
2224: * @ctxt: the XPath Parser context
2225: * @cur: the current node in the traversal
2226: *
2227: * Traversal function for the "preceding-sibling" direction
2228: * The preceding-sibling axis contains the preceding siblings of the context
2229: * node in reverse document order; the first preceding sibling is first on the
2230: * axis; the sibling preceding that node is the second on the axis and so on.
1.19 daniel 2231: *
2232: * Returns the next element following that axis
1.2 daniel 2233: */
2234: xmlNodePtr
2235: xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.14 daniel 2236: if (cur == (xmlNodePtr) ctxt->context->doc)
2237: return(NULL);
1.2 daniel 2238: if (cur == NULL)
2239: return(ctxt->context->node->prev);
2240: return(cur->prev);
2241: }
2242:
2243: /**
2244: * xmlXPathNextFollowing:
2245: * @ctxt: the XPath Parser context
2246: * @cur: the current node in the traversal
2247: *
2248: * Traversal function for the "following" direction
2249: * The following axis contains all nodes in the same document as the context
2250: * node that are after the context node in document order, excluding any
2251: * descendants and excluding attribute nodes and namespace nodes; the nodes
2252: * are ordered in document order
1.19 daniel 2253: *
2254: * Returns the next element following that axis
1.2 daniel 2255: */
2256: xmlNodePtr
2257: xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
1.60 veillard 2258: if (cur != NULL && cur->children != NULL)
2259: return cur->children ;
1.63 veillard 2260: if (cur == NULL) cur = ctxt->context->node;
2261: if (cur == NULL) return(NULL) ; /* ERROR */
2262: if (cur->next != NULL) return(cur->next) ;
1.60 veillard 2263: do {
2264: cur = cur->parent;
2265: if (cur == NULL) return(NULL);
1.63 veillard 2266: if (cur == ctxt->context->doc->children) return(NULL); /* !!!!!?!? */
2267: if (cur->next != NULL) return(cur->next);
1.60 veillard 2268: } while (cur != NULL);
2269: return(cur);
2270: }
2271:
2272: /*
1.63 veillard 2273: * xmlXPathIsAncestor:
2274: * @ancestor: the ancestor node
2275: * @node: the current node
2276: *
2277: * Check that @ancestor is a @node's ancestor
2278: *
1.60 veillard 2279: * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
2280: */
2281: static int
1.63 veillard 2282: xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
1.60 veillard 2283: xmlNodePtr tmp ;
2284: if (ancestor == NULL || node == NULL) return 0 ;
2285: for (tmp = node ; tmp->parent != NULL ; tmp = tmp->parent) {
2286: if (tmp->parent == ancestor)
2287: return 1 ;
2288: }
2289: return 0 ;
2290: }
2291:
2292: /**
2293: * xmlXPathNextPreceding:
2294: * @ctxt: the XPath Parser context
2295: * @cur: the current node in the traversal
2296: *
2297: * Traversal function for the "preceding" direction
2298: * the preceding axis contains all nodes in the same document as the context
2299: * node that are before the context node in document order, excluding any
2300: * ancestors and excluding attribute nodes and namespace nodes; the nodes are
2301: * ordered in reverse document order
2302: *
2303: * Returns the next element following that axis
2304: */
2305: xmlNodePtr
2306: xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
2307: if (cur == NULL)
2308: cur = ctxt->context->node ;
2309: do {
2310: if (cur->prev != NULL) {
2311: for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
2312: ;
2313: return(cur) ;
2314: }
2315:
2316: cur = cur->parent;
2317: if (cur == NULL) return(NULL);
2318: if (cur == ctxt->context->doc->children) return(NULL);
1.63 veillard 2319: } while (xmlXPathIsAncestor(cur, ctxt->context->node));
1.2 daniel 2320: return(cur);
2321: }
2322:
2323: /**
2324: * xmlXPathNextNamespace:
2325: * @ctxt: the XPath Parser context
2326: * @cur: the current attribute in the traversal
2327: *
2328: * Traversal function for the "namespace" direction
2329: * the namespace axis contains the namespace nodes of the context node;
2330: * the order of nodes on this axis is implementation-defined; the axis will
2331: * be empty unless the context node is an element
1.19 daniel 2332: *
2333: * Returns the next element following that axis
1.2 daniel 2334: */
1.19 daniel 2335: xmlNsPtr
1.2 daniel 2336: xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1.19 daniel 2337: if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
2338: if (ctxt->context->namespaces != NULL)
1.25 daniel 2339: xmlFree(ctxt->context->namespaces);
1.19 daniel 2340: ctxt->context->namespaces =
2341: xmlGetNsList(ctxt->context->doc, ctxt->context->node);
2342: if (ctxt->context->namespaces == NULL) return(NULL);
2343: ctxt->context->nsNr = 0;
2344: }
2345: return(ctxt->context->namespaces[ctxt->context->nsNr++]);
1.2 daniel 2346: }
2347:
2348: /**
2349: * xmlXPathNextAttribute:
2350: * @ctxt: the XPath Parser context
2351: * @cur: the current attribute in the traversal
2352: *
2353: * Traversal function for the "attribute" direction
1.33 daniel 2354: * TODO: support DTD inherited default attributes
1.19 daniel 2355: *
2356: * Returns the next element following that axis
1.2 daniel 2357: */
2358: xmlAttrPtr
2359: xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlAttrPtr cur) {
1.18 daniel 2360: if (cur == NULL) {
2361: if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
2362: return(NULL);
1.2 daniel 2363: return(ctxt->context->node->properties);
1.18 daniel 2364: }
1.2 daniel 2365: return(cur->next);
2366: }
2367:
2368: /************************************************************************
2369: * *
1.3 daniel 2370: * NodeTest Functions *
2371: * *
2372: ************************************************************************/
2373:
1.59 veillard 2374: typedef enum {
2375: NODE_TEST_NONE = 0,
2376: NODE_TEST_TYPE = 1,
2377: NODE_TEST_PI = 2,
2378: NODE_TEST_ALL = 3,
2379: NODE_TEST_NS = 4,
2380: NODE_TEST_NAME = 5
2381: } xmlXPathTestVal;
2382:
2383: typedef enum {
1.66 veillard 2384: NODE_TYPE_COMMENT = XML_COMMENT_NODE,
2385: NODE_TYPE_TEXT = XML_TEXT_NODE,
2386: NODE_TYPE_PI = XML_PI_NODE,
2387: NODE_TYPE_NODE = XML_ELEMENT_NODE
1.59 veillard 2388: } xmlXPathTypeVal;
1.3 daniel 2389:
2390: #define IS_FUNCTION 200
2391:
2392: /**
2393: * xmlXPathNodeCollectAndTest:
2394: * @ctxt: the XPath Parser context
1.59 veillard 2395: * @axis: the XPath axis
2396: * @test: the XPath test
2397: * @type: the XPath type
2398: * @prefix: the namesapce prefix if any
2399: * @name: the name used in the search if any
1.3 daniel 2400: *
2401: * This is the function implementing a step: based on the current list
2402: * of nodes, it builds up a new list, looking at all nodes under that
2403: * axis and selecting them.
2404: *
2405: * Returns the new NodeSet resulting from the search.
2406: */
1.59 veillard 2407: void
2408: xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
2409: xmlXPathTestVal test, xmlXPathTypeVal type,
2410: const xmlChar *prefix, const xmlChar *name) {
1.4 daniel 2411: #ifdef DEBUG_STEP
2412: int n = 0, t = 0;
1.3 daniel 2413: #endif
2414: int i;
2415: xmlNodeSetPtr ret;
2416: xmlXPathTraversalFunction next = NULL;
2417: xmlNodePtr cur = NULL;
1.59 veillard 2418: xmlXPathObjectPtr obj;
2419: xmlNodeSetPtr nodelist;
2420:
2421: CHECK_TYPE(XPATH_NODESET);
2422: obj = valuePop(ctxt);
1.3 daniel 2423:
1.4 daniel 2424: #ifdef DEBUG_STEP
1.9 daniel 2425: fprintf(xmlXPathDebug, "new step : ");
1.4 daniel 2426: #endif
1.3 daniel 2427: switch (axis) {
2428: case AXIS_ANCESTOR:
1.4 daniel 2429: #ifdef DEBUG_STEP
1.9 daniel 2430: fprintf(xmlXPathDebug, "axis 'ancestors' ");
1.4 daniel 2431: #endif
1.3 daniel 2432: next = xmlXPathNextAncestor; break;
2433: case AXIS_ANCESTOR_OR_SELF:
1.4 daniel 2434: #ifdef DEBUG_STEP
1.9 daniel 2435: fprintf(xmlXPathDebug, "axis 'ancestors-or-self' ");
1.4 daniel 2436: #endif
1.3 daniel 2437: next = xmlXPathNextAncestorOrSelf; break;
2438: case AXIS_ATTRIBUTE:
1.4 daniel 2439: #ifdef DEBUG_STEP
1.9 daniel 2440: fprintf(xmlXPathDebug, "axis 'attributes' ");
1.4 daniel 2441: #endif
1.19 daniel 2442: next = (xmlXPathTraversalFunction) xmlXPathNextAttribute; break;
1.3 daniel 2443: break;
2444: case AXIS_CHILD:
1.4 daniel 2445: #ifdef DEBUG_STEP
1.9 daniel 2446: fprintf(xmlXPathDebug, "axis 'child' ");
1.4 daniel 2447: #endif
1.3 daniel 2448: next = xmlXPathNextChild; break;
2449: case AXIS_DESCENDANT:
1.4 daniel 2450: #ifdef DEBUG_STEP
1.9 daniel 2451: fprintf(xmlXPathDebug, "axis 'descendant' ");
1.4 daniel 2452: #endif
1.3 daniel 2453: next = xmlXPathNextDescendant; break;
2454: case AXIS_DESCENDANT_OR_SELF:
1.4 daniel 2455: #ifdef DEBUG_STEP
1.9 daniel 2456: fprintf(xmlXPathDebug, "axis 'descendant-or-self' ");
1.4 daniel 2457: #endif
1.3 daniel 2458: next = xmlXPathNextDescendantOrSelf; break;
2459: case AXIS_FOLLOWING:
1.4 daniel 2460: #ifdef DEBUG_STEP
1.9 daniel 2461: fprintf(xmlXPathDebug, "axis 'following' ");
1.4 daniel 2462: #endif
1.3 daniel 2463: next = xmlXPathNextFollowing; break;
2464: case AXIS_FOLLOWING_SIBLING:
1.4 daniel 2465: #ifdef DEBUG_STEP
1.9 daniel 2466: fprintf(xmlXPathDebug, "axis 'following-siblings' ");
1.4 daniel 2467: #endif
1.3 daniel 2468: next = xmlXPathNextFollowingSibling; break;
2469: case AXIS_NAMESPACE:
1.4 daniel 2470: #ifdef DEBUG_STEP
1.9 daniel 2471: fprintf(xmlXPathDebug, "axis 'namespace' ");
1.4 daniel 2472: #endif
1.19 daniel 2473: next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
1.3 daniel 2474: break;
2475: case AXIS_PARENT:
1.4 daniel 2476: #ifdef DEBUG_STEP
1.9 daniel 2477: fprintf(xmlXPathDebug, "axis 'parent' ");
1.4 daniel 2478: #endif
1.3 daniel 2479: next = xmlXPathNextParent; break;
2480: case AXIS_PRECEDING:
1.4 daniel 2481: #ifdef DEBUG_STEP
1.9 daniel 2482: fprintf(xmlXPathDebug, "axis 'preceding' ");
1.4 daniel 2483: #endif
1.3 daniel 2484: next = xmlXPathNextPreceding; break;
2485: case AXIS_PRECEDING_SIBLING:
1.4 daniel 2486: #ifdef DEBUG_STEP
1.9 daniel 2487: fprintf(xmlXPathDebug, "axis 'preceding-sibling' ");
1.4 daniel 2488: #endif
1.3 daniel 2489: next = xmlXPathNextPrecedingSibling; break;
2490: case AXIS_SELF:
1.4 daniel 2491: #ifdef DEBUG_STEP
1.9 daniel 2492: fprintf(xmlXPathDebug, "axis 'self' ");
1.4 daniel 2493: #endif
1.3 daniel 2494: next = xmlXPathNextSelf; break;
2495: }
1.59 veillard 2496: if (next == NULL)
2497: return;
2498:
2499: nodelist = obj->nodesetval;
1.3 daniel 2500: ret = xmlXPathNodeSetCreate(NULL);
1.4 daniel 2501: #ifdef DEBUG_STEP
1.9 daniel 2502: fprintf(xmlXPathDebug, " context contains %d nodes\n",
1.59 veillard 2503: nodelist->nodeNr);
1.4 daniel 2504: switch (test) {
2505: case NODE_TEST_NONE:
1.35 daniel 2506: fprintf(xmlXPathDebug, " searching for none !!!\n");
1.4 daniel 2507: break;
2508: case NODE_TEST_TYPE:
1.35 daniel 2509: fprintf(xmlXPathDebug, " searching for type %d\n", type);
1.4 daniel 2510: break;
2511: case NODE_TEST_PI:
1.35 daniel 2512: fprintf(xmlXPathDebug, " searching for PI !!!\n");
1.4 daniel 2513: break;
2514: case NODE_TEST_ALL:
1.35 daniel 2515: fprintf(xmlXPathDebug, " searching for *\n");
1.4 daniel 2516: break;
2517: case NODE_TEST_NS:
1.35 daniel 2518: fprintf(xmlXPathDebug, " searching for namespace %s\n",
1.9 daniel 2519: prefix);
1.4 daniel 2520: break;
2521: case NODE_TEST_NAME:
1.35 daniel 2522: fprintf(xmlXPathDebug, " searching for name %s\n", name);
1.4 daniel 2523: if (prefix != NULL)
1.9 daniel 2524: fprintf(xmlXPathDebug, " with namespace %s\n",
2525: prefix);
1.4 daniel 2526: break;
2527: }
1.9 daniel 2528: fprintf(xmlXPathDebug, "Testing : ");
1.4 daniel 2529: #endif
1.73 veillard 2530: /*
2531: * 2.3 Node Tests
2532: * - For the attribute axis, the principal node type is attribute.
2533: * - For the namespace axis, the principal node type is namespace.
2534: * - For other axes, the principal node type is element.
2535: *
2536: * A node test * is true for any node of the
2537: * principal node type. For example, child::* willi
2538: * select all element children of the context node
2539: */
1.59 veillard 2540: for (i = 0;i < nodelist->nodeNr; i++) {
2541: ctxt->context->node = nodelist->nodeTab[i];
1.3 daniel 2542:
2543: cur = NULL;
2544: do {
2545: cur = next(ctxt, cur);
2546: if (cur == NULL) break;
1.9 daniel 2547: #ifdef DEBUG_STEP
1.4 daniel 2548: t++;
1.9 daniel 2549: fprintf(xmlXPathDebug, " %s", cur->name);
1.4 daniel 2550: #endif
1.3 daniel 2551: switch (test) {
2552: case NODE_TEST_NONE:
1.6 daniel 2553: STRANGE
1.59 veillard 2554: return;
1.3 daniel 2555: case NODE_TEST_TYPE:
1.35 daniel 2556: if ((cur->type == type) ||
2557: ((type == XML_ELEMENT_NODE) &&
2558: ((cur->type == XML_DOCUMENT_NODE) ||
2559: (cur->type == XML_HTML_DOCUMENT_NODE)))) {
1.9 daniel 2560: #ifdef DEBUG_STEP
1.3 daniel 2561: n++;
2562: #endif
2563: xmlXPathNodeSetAdd(ret, cur);
2564: }
2565: break;
2566: case NODE_TEST_PI:
1.19 daniel 2567: if (cur->type == XML_PI_NODE) {
1.22 daniel 2568: if ((name != NULL) &&
1.58 veillard 2569: (!xmlStrEqual(name, cur->name)))
1.22 daniel 2570: break;
1.19 daniel 2571: #ifdef DEBUG_STEP
1.22 daniel 2572: n++;
1.19 daniel 2573: #endif
1.22 daniel 2574: xmlXPathNodeSetAdd(ret, cur);
1.19 daniel 2575: }
1.3 daniel 2576: break;
2577: case NODE_TEST_ALL:
1.19 daniel 2578: if ((cur->type == XML_ELEMENT_NODE) ||
1.73 veillard 2579: (cur->type == XML_DOCUMENT_NODE) ||
2580: (cur->type == XML_HTML_DOCUMENT_NODE)) {
1.9 daniel 2581: #ifdef DEBUG_STEP
1.3 daniel 2582: n++;
2583: #endif
2584: xmlXPathNodeSetAdd(ret, cur);
2585: }
2586: break;
1.19 daniel 2587: case NODE_TEST_NS: {
1.22 daniel 2588: TODO /* namespace search */
1.3 daniel 2589: break;
1.19 daniel 2590: }
1.3 daniel 2591: case NODE_TEST_NAME:
1.15 daniel 2592: switch (cur->type) {
2593: case XML_ELEMENT_NODE:
1.58 veillard 2594: if (xmlStrEqual(name, cur->name) &&
1.15 daniel 2595: (((prefix == NULL) ||
2596: ((cur->ns != NULL) &&
1.58 veillard 2597: (xmlStrEqual(prefix, cur->ns->href)))))) {
1.9 daniel 2598: #ifdef DEBUG_STEP
1.59 veillard 2599: n++;
1.3 daniel 2600: #endif
1.15 daniel 2601: xmlXPathNodeSetAdd(ret, cur);
2602: }
1.19 daniel 2603: break;
2604: case XML_ATTRIBUTE_NODE: {
2605: xmlAttrPtr attr = (xmlAttrPtr) cur;
1.58 veillard 2606: if (xmlStrEqual(name, attr->name)) {
1.19 daniel 2607: #ifdef DEBUG_STEP
1.59 veillard 2608: n++;
1.19 daniel 2609: #endif
2610: xmlXPathNodeSetAdd(ret, cur);
2611: }
2612: break;
2613: }
1.15 daniel 2614: default:
2615: break;
1.3 daniel 2616: }
2617: break;
2618: }
2619: } while (cur != NULL);
2620: }
1.9 daniel 2621: #ifdef DEBUG_STEP
2622: fprintf(xmlXPathDebug,
2623: "\nExamined %d nodes, found %d nodes at that step\n", t, n);
1.3 daniel 2624: #endif
1.59 veillard 2625: xmlXPathFreeObject(obj);
2626: valuePush(ctxt, xmlXPathWrapNodeSet(ret));
1.3 daniel 2627: }
2628:
2629:
2630: /************************************************************************
2631: * *
1.2 daniel 2632: * Implicit tree core function library *
2633: * *
2634: ************************************************************************/
2635:
2636: /**
2637: * xmlXPathRoot:
2638: * @ctxt: the XPath Parser context
2639: *
2640: * Initialize the context to the root of the document
2641: */
2642: void
2643: xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
1.69 veillard 2644: if (ctxt->value != NULL) {
2645: xmlXPathObjectPtr obj;
1.59 veillard 2646:
1.69 veillard 2647: CHECK_TYPE(XPATH_NODESET);
2648: obj = valuePop(ctxt);
2649: xmlXPathFreeObject(obj);
2650: }
1.14 daniel 2651: ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
1.59 veillard 2652: valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
1.2 daniel 2653: }
2654:
2655: /************************************************************************
2656: * *
1.1 daniel 2657: * The explicit core function library *
2658: *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
2659: * *
2660: ************************************************************************/
2661:
1.5 daniel 2662:
1.1 daniel 2663: /**
2664: * xmlXPathLastFunction:
2665: * @ctxt: the XPath Parser context
2666: *
2667: * Implement the last() XPath function
1.5 daniel 2668: * The last function returns the number of nodes in the context node list.
1.1 daniel 2669: */
2670: void
1.8 daniel 2671: xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2672: CHECK_ARITY(0);
1.57 veillard 2673: if (ctxt->context->contextSize > 0) {
2674: valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
2675: #ifdef DEBUG_EXPR
2676: fprintf(xmlXPathDebug, "last() : %d\n", ctxt->context->contextSize);
2677: #endif
1.5 daniel 2678: } else {
1.57 veillard 2679: XP_ERROR(XPATH_INVALID_CTXT_SIZE);
1.5 daniel 2680: }
1.1 daniel 2681: }
2682:
2683: /**
2684: * xmlXPathPositionFunction:
2685: * @ctxt: the XPath Parser context
2686: *
2687: * Implement the position() XPath function
1.4 daniel 2688: * The position function returns the position of the context node in the
2689: * context node list. The first position is 1, and so the last positionr
2690: * will be equal to last().
1.1 daniel 2691: */
2692: void
1.8 daniel 2693: xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
2694: CHECK_ARITY(0);
1.57 veillard 2695: if (ctxt->context->proximityPosition > 0) {
2696: valuePush(ctxt,
2697: xmlXPathNewFloat((double) ctxt->context->proximityPosition));
2698: #ifdef DEBUG_EXPR
2699: fprintf(xmlXPathDebug, "position() : %d\n",
2700: ctxt->context->proximityPosition);
2701: #endif
2702: } else {
2703: XP_ERROR(XPATH_INVALID_CTXT_POSITION);
1.4 daniel 2704: }
1.1 daniel 2705: }
2706:
2707: /**
2708: * xmlXPathCountFunction:
2709: * @ctxt: the XPath Parser context
2710: *
2711: * Implement the count() XPath function
2712: */
2713: void
1.8 daniel 2714: xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5 daniel 2715: xmlXPathObjectPtr cur;
2716:
1.8 daniel 2717: CHECK_ARITY(1);
2718: CHECK_TYPE(XPATH_NODESET);
1.5 daniel 2719: cur = valuePop(ctxt);
2720:
1.10 daniel 2721: valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
1.5 daniel 2722: xmlXPathFreeObject(cur);
1.1 daniel 2723: }
2724:
2725: /**
2726: * xmlXPathIdFunction:
2727: * @ctxt: the XPath Parser context
2728: *
2729: * Implement the id() XPath function
1.8 daniel 2730: * The id function selects elements by their unique ID
2731: * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
2732: * then the result is the union of the result of applying id to the
2733: * string value of each of the nodes in the argument node-set. When the
2734: * argument to id is of any other type, the argument is converted to a
2735: * string as if by a call to the string function; the string is split
2736: * into a whitespace-separated list of tokens (whitespace is any sequence
2737: * of characters matching the production S); the result is a node-set
2738: * containing the elements in the same document as the context node that
2739: * have a unique ID equal to any of the tokens in the list.
1.1 daniel 2740: */
2741: void
1.8 daniel 2742: xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.29 daniel 2743: const xmlChar *tokens;
2744: const xmlChar *cur;
2745: xmlChar *ID;
1.19 daniel 2746: xmlAttrPtr attr;
2747: xmlNodePtr elem = NULL;
2748: xmlXPathObjectPtr ret, obj;
2749:
1.8 daniel 2750: CHECK_ARITY(1);
1.19 daniel 2751: obj = valuePop(ctxt);
1.49 daniel 2752: if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
1.19 daniel 2753: if (obj->type == XPATH_NODESET) {
1.22 daniel 2754: TODO /* ID function in case of NodeSet */
1.19 daniel 2755: }
2756: if (obj->type != XPATH_STRING) {
2757: valuePush(ctxt, obj);
2758: xmlXPathStringFunction(ctxt, 1);
2759: obj = valuePop(ctxt);
2760: if (obj->type != XPATH_STRING) {
2761: xmlXPathFreeObject(obj);
2762: return;
2763: }
2764: }
2765: tokens = obj->stringval;
2766:
2767: ret = xmlXPathNewNodeSet(NULL);
2768: valuePush(ctxt, ret);
2769: if (tokens == NULL) {
2770: xmlXPathFreeObject(obj);
2771: return;
2772: }
2773:
2774: cur = tokens;
2775:
2776: while (IS_BLANK(*cur)) cur++;
2777: while (*cur != 0) {
2778: while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
2779: (*cur == '.') || (*cur == '-') ||
2780: (*cur == '_') || (*cur == ':') ||
2781: (IS_COMBINING(*cur)) ||
2782: (IS_EXTENDER(*cur)))
2783: cur++;
2784:
2785: if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
2786:
2787: ID = xmlStrndup(tokens, cur - tokens);
2788: attr = xmlGetID(ctxt->context->doc, ID);
2789: if (attr != NULL) {
1.42 daniel 2790: elem = attr->parent;
1.19 daniel 2791: xmlXPathNodeSetAdd(ret->nodesetval, elem);
2792: }
2793: if (ID != NULL)
1.25 daniel 2794: xmlFree(ID);
1.19 daniel 2795:
2796: while (IS_BLANK(*cur)) cur++;
2797: tokens = cur;
2798: }
2799: xmlXPathFreeObject(obj);
2800: return;
1.1 daniel 2801: }
2802:
2803: /**
2804: * xmlXPathLocalPartFunction:
2805: * @ctxt: the XPath Parser context
2806: *
2807: * Implement the local-part() XPath function
1.8 daniel 2808: * The local-part function returns a string containing the local part
2809: * of the name of the node in the argument node-set that is first in
2810: * document order. If the node-set is empty or the first node has no
2811: * name, an empty string is returned. If the argument is omitted it
2812: * defaults to the context node.
1.1 daniel 2813: */
2814: void
1.8 daniel 2815: xmlXPathLocalPartFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5 daniel 2816: xmlXPathObjectPtr cur;
2817:
1.8 daniel 2818: CHECK_ARITY(1);
2819: CHECK_TYPE(XPATH_NODESET);
1.5 daniel 2820: cur = valuePop(ctxt);
2821:
2822: if (cur->nodesetval->nodeNr == 0) {
1.21 daniel 2823: valuePush(ctxt, xmlXPathNewCString(""));
1.5 daniel 2824: } else {
2825: int i = 0; /* Should be first in document order !!!!! */
2826: valuePush(ctxt, xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
2827: }
2828: xmlXPathFreeObject(cur);
1.1 daniel 2829: }
2830:
2831: /**
2832: * xmlXPathNamespaceFunction:
2833: * @ctxt: the XPath Parser context
2834: *
2835: * Implement the namespace() XPath function
1.8 daniel 2836: * The namespace function returns a string containing the namespace URI
2837: * of the expanded name of the node in the argument node-set that is
2838: * first in document order. If the node-set is empty, the first node has
2839: * no name, or the expanded name has no namespace URI, an empty string
2840: * is returned. If the argument is omitted it defaults to the context node.
1.1 daniel 2841: */
2842: void
1.8 daniel 2843: xmlXPathNamespaceFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5 daniel 2844: xmlXPathObjectPtr cur;
2845:
1.19 daniel 2846: if (nargs == 0) {
2847: valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
2848: nargs = 1;
2849: }
1.8 daniel 2850: CHECK_ARITY(1);
2851: CHECK_TYPE(XPATH_NODESET);
1.5 daniel 2852: cur = valuePop(ctxt);
2853:
2854: if (cur->nodesetval->nodeNr == 0) {
1.21 daniel 2855: valuePush(ctxt, xmlXPathNewCString(""));
1.5 daniel 2856: } else {
2857: int i = 0; /* Should be first in document order !!!!! */
2858:
2859: if (cur->nodesetval->nodeTab[i]->ns == NULL)
1.21 daniel 2860: valuePush(ctxt, xmlXPathNewCString(""));
1.5 daniel 2861: else
2862: valuePush(ctxt, xmlXPathNewString(
2863: cur->nodesetval->nodeTab[i]->ns->href));
2864: }
2865: xmlXPathFreeObject(cur);
1.1 daniel 2866: }
2867:
2868: /**
2869: * xmlXPathNameFunction:
2870: * @ctxt: the XPath Parser context
2871: *
1.8 daniel 2872: * Implement the name() XPath function
2873: * The name function returns a string containing a QName representing
2874: * the name of the node in the argument node-set that is first in documenti
2875: * order. The QName must represent the name with respect to the namespace
2876: * declarations in effect on the node whose name is being represented.
2877: * Typically, this will be the form in which the name occurred in the XML
2878: * source. This need not be the case if there are namespace declarations
2879: * in effect on the node that associate multiple prefixes with the same
2880: * namespace. However, an implementation may include information about
2881: * the original prefix in its representation of nodes; in this case, an
2882: * implementation can ensure that the returned string is always the same
2883: * as the QName used in the XML source. If the argument it omitted it
2884: * defaults to the context node.
2885: * Libxml keep the original prefix so the "real qualified name" used is
2886: * returned.
1.1 daniel 2887: */
2888: void
1.8 daniel 2889: xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5 daniel 2890: xmlXPathObjectPtr cur;
2891:
1.8 daniel 2892: CHECK_ARITY(1);
2893: CHECK_TYPE(XPATH_NODESET);
1.5 daniel 2894: cur = valuePop(ctxt);
2895:
2896: if (cur->nodesetval->nodeNr == 0) {
1.21 daniel 2897: valuePush(ctxt, xmlXPathNewCString(""));
1.5 daniel 2898: } else {
2899: int i = 0; /* Should be first in document order !!!!! */
2900:
2901: if (cur->nodesetval->nodeTab[i]->ns == NULL)
2902: valuePush(ctxt, xmlXPathNewString(
1.8 daniel 2903: cur->nodesetval->nodeTab[i]->name));
2904:
2905: else {
1.21 daniel 2906: char name[2000];
1.54 veillard 2907: #ifdef HAVE_SNPRINTF
2908: snprintf(name, sizeof(name), "%s:%s",
2909: (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2910: (char *) cur->nodesetval->nodeTab[i]->name);
2911: #else
1.21 daniel 2912: sprintf(name, "%s:%s",
2913: (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
2914: (char *) cur->nodesetval->nodeTab[i]->name);
1.54 veillard 2915: #endif
2916: name[sizeof(name) - 1] = 0;
1.21 daniel 2917: valuePush(ctxt, xmlXPathNewCString(name));
1.8 daniel 2918: }
1.5 daniel 2919: }
2920: xmlXPathFreeObject(cur);
1.1 daniel 2921: }
2922:
2923: /**
2924: * xmlXPathStringFunction:
2925: * @ctxt: the XPath Parser context
2926: *
2927: * Implement the string() XPath function
1.8 daniel 2928: * he string function converts an object to a string as follows:
2929: * - A node-set is converted to a string by returning the value of
2930: * the node in the node-set that is first in document order.
2931: * If the node-set is empty, an empty string is returned.
2932: * - A number is converted to a string as follows
2933: * + NaN is converted to the string NaN
2934: * + positive zero is converted to the string 0
2935: * + negative zero is converted to the string 0
2936: * + positive infinity is converted to the string Infinity
2937: * + negative infinity is converted to the string -Infinity
2938: * + if the number is an integer, the number is represented in
2939: * decimal form as a Number with no decimal point and no leading
2940: * zeros, preceded by a minus sign (-) if the number is negative
2941: * + otherwise, the number is represented in decimal form as a
2942: * Number including a decimal point with at least one digit
2943: * before the decimal point and at least one digit after the
2944: * decimal point, preceded by a minus sign (-) if the number
2945: * is negative; there must be no leading zeros before the decimal
2946: * point apart possibly from the one required digit immediatelyi
2947: * before the decimal point; beyond the one required digit
2948: * after the decimal point there must be as many, but only as
2949: * many, more digits as are needed to uniquely distinguish the
2950: * number from all other IEEE 754 numeric values.
2951: * - The boolean false value is converted to the string false.
2952: * The boolean true value is converted to the string true.
1.1 daniel 2953: */
2954: void
1.8 daniel 2955: xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5 daniel 2956: xmlXPathObjectPtr cur;
2957:
1.8 daniel 2958: CHECK_ARITY(1);
1.5 daniel 2959: cur = valuePop(ctxt);
1.49 daniel 2960: if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
1.5 daniel 2961: switch (cur->type) {
1.59 veillard 2962: case XPATH_UNDEFINED:
2963: #ifdef DEBUG_EXPR
2964: fprintf(xmlXPathDebug, "String: undefined\n");
2965: #endif
2966: valuePush(ctxt, xmlXPathNewCString(""));
2967: break;
1.5 daniel 2968: case XPATH_NODESET:
2969: if (cur->nodesetval->nodeNr == 0) {
1.21 daniel 2970: valuePush(ctxt, xmlXPathNewCString(""));
1.5 daniel 2971: } else {
1.29 daniel 2972: xmlChar *res;
1.8 daniel 2973: int i = 0; /* Should be first in document order !!!!! */
1.5 daniel 2974: res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
2975: valuePush(ctxt, xmlXPathNewString(res));
1.25 daniel 2976: xmlFree(res);
1.5 daniel 2977: }
2978: xmlXPathFreeObject(cur);
2979: return;
2980: case XPATH_STRING:
2981: valuePush(ctxt, cur);
2982: return;
2983: case XPATH_BOOLEAN:
1.21 daniel 2984: if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
2985: else valuePush(ctxt, xmlXPathNewCString("false"));
1.5 daniel 2986: xmlXPathFreeObject(cur);
2987: return;
2988: case XPATH_NUMBER: {
1.21 daniel 2989: char buf[100];
1.5 daniel 2990:
1.10 daniel 2991: if (isnan(cur->floatval))
2992: sprintf(buf, "NaN");
2993: else if (isinf(cur->floatval) > 0)
2994: sprintf(buf, "+Infinity");
2995: else if (isinf(cur->floatval) < 0)
2996: sprintf(buf, "-Infinity");
2997: else
2998: sprintf(buf, "%0g", cur->floatval);
1.21 daniel 2999: valuePush(ctxt, xmlXPathNewCString(buf));
1.11 veillard 3000: xmlXPathFreeObject(cur);
1.5 daniel 3001: return;
3002: }
1.59 veillard 3003: case XPATH_USERS:
1.62 veillard 3004: case XPATH_POINT:
3005: case XPATH_RANGE:
1.63 veillard 3006: case XPATH_LOCATIONSET:
1.59 veillard 3007: TODO
3008: valuePush(ctxt, xmlXPathNewCString(""));
3009: break;
1.5 daniel 3010: }
3011: STRANGE
1.1 daniel 3012: }
3013:
3014: /**
3015: * xmlXPathStringLengthFunction:
3016: * @ctxt: the XPath Parser context
3017: *
3018: * Implement the string-length() XPath function
1.8 daniel 3019: * The string-length returns the number of characters in the string
3020: * (see [3.6 Strings]). If the argument is omitted, it defaults to
3021: * the context node converted to a string, in other words the value
3022: * of the context node.
1.1 daniel 3023: */
3024: void
1.8 daniel 3025: xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3026: xmlXPathObjectPtr cur;
3027:
3028: if (nargs == 0) {
3029: if (ctxt->context->node == NULL) {
3030: valuePush(ctxt, xmlXPathNewFloat(0));
3031: } else {
1.29 daniel 3032: xmlChar *content;
1.8 daniel 3033:
3034: content = xmlNodeGetContent(ctxt->context->node);
3035: valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
1.25 daniel 3036: xmlFree(content);
1.8 daniel 3037: }
3038: return;
3039: }
3040: CHECK_ARITY(1);
3041: CHECK_TYPE(XPATH_STRING);
3042: cur = valuePop(ctxt);
3043: valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
3044: xmlXPathFreeObject(cur);
1.1 daniel 3045: }
3046:
3047: /**
3048: * xmlXPathConcatFunction:
3049: * @ctxt: the XPath Parser context
3050: *
3051: * Implement the concat() XPath function
1.8 daniel 3052: * The concat function returns the concatenation of its arguments.
1.1 daniel 3053: */
3054: void
1.8 daniel 3055: xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.50 veillard 3056: xmlXPathObjectPtr cur, newobj;
1.29 daniel 3057: xmlChar *tmp;
1.8 daniel 3058:
3059: if (nargs < 2) {
3060: CHECK_ARITY(2);
3061: }
3062:
3063: cur = valuePop(ctxt);
3064: if ((cur == NULL) || (cur->type != XPATH_STRING)) {
3065: xmlXPathFreeObject(cur);
3066: return;
3067: }
3068: nargs--;
3069:
3070: while (nargs > 0) {
1.50 veillard 3071: newobj = valuePop(ctxt);
3072: if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
3073: xmlXPathFreeObject(newobj);
1.8 daniel 3074: xmlXPathFreeObject(cur);
1.49 daniel 3075: XP_ERROR(XPATH_INVALID_TYPE);
1.8 daniel 3076: }
1.50 veillard 3077: tmp = xmlStrcat(newobj->stringval, cur->stringval);
3078: newobj->stringval = cur->stringval;
1.8 daniel 3079: cur->stringval = tmp;
1.9 daniel 3080:
1.50 veillard 3081: xmlXPathFreeObject(newobj);
1.9 daniel 3082: nargs--;
1.8 daniel 3083: }
3084: valuePush(ctxt, cur);
1.1 daniel 3085: }
3086:
3087: /**
3088: * xmlXPathContainsFunction:
3089: * @ctxt: the XPath Parser context
3090: *
3091: * Implement the contains() XPath function
1.8 daniel 3092: * The contains function returns true if the first argument string
3093: * contains the second argument string, and otherwise returns false.
1.1 daniel 3094: */
3095: void
1.8 daniel 3096: xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3097: xmlXPathObjectPtr hay, needle;
3098:
3099: CHECK_ARITY(2);
3100: CHECK_TYPE(XPATH_STRING);
3101: needle = valuePop(ctxt);
3102: hay = valuePop(ctxt);
3103: if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3104: xmlXPathFreeObject(hay);
3105: xmlXPathFreeObject(needle);
1.49 daniel 3106: XP_ERROR(XPATH_INVALID_TYPE);
1.8 daniel 3107: }
3108: if (xmlStrstr(hay->stringval, needle->stringval))
3109: valuePush(ctxt, xmlXPathNewBoolean(1));
3110: else
3111: valuePush(ctxt, xmlXPathNewBoolean(0));
3112: xmlXPathFreeObject(hay);
3113: xmlXPathFreeObject(needle);
1.1 daniel 3114: }
3115:
3116: /**
1.9 daniel 3117: * xmlXPathStartsWithFunction:
1.1 daniel 3118: * @ctxt: the XPath Parser context
3119: *
1.9 daniel 3120: * Implement the starts-with() XPath function
1.8 daniel 3121: * The starts-with function returns true if the first argument string
3122: * starts with the second argument string, and otherwise returns false.
1.1 daniel 3123: */
3124: void
1.9 daniel 3125: xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.8 daniel 3126: xmlXPathObjectPtr hay, needle;
3127: int n;
3128:
3129: CHECK_ARITY(2);
3130: CHECK_TYPE(XPATH_STRING);
3131: needle = valuePop(ctxt);
3132: hay = valuePop(ctxt);
3133: if ((hay == NULL) || (hay->type != XPATH_STRING)) {
3134: xmlXPathFreeObject(hay);
3135: xmlXPathFreeObject(needle);
1.49 daniel 3136: XP_ERROR(XPATH_INVALID_TYPE);
1.8 daniel 3137: }
3138: n = xmlStrlen(needle->stringval);
3139: if (xmlStrncmp(hay->stringval, needle->stringval, n))
3140: valuePush(ctxt, xmlXPathNewBoolean(0));
3141: else
3142: valuePush(ctxt, xmlXPathNewBoolean(1));
3143: xmlXPathFreeObject(hay);
3144: xmlXPathFreeObject(needle);
1.1 daniel 3145: }
3146:
3147: /**
3148: * xmlXPathSubstringFunction:
3149: * @ctxt: the XPath Parser context
3150: *
3151: * Implement the substring() XPath function
1.8 daniel 3152: * The substring function returns the substring of the first argument
3153: * starting at the position specified in the second argument with
3154: * length specified in the third argument. For example,
3155: * substring("12345",2,3) returns "234". If the third argument is not
3156: * specified, it returns the substring starting at the position specified
3157: * in the second argument and continuing to the end of the string. For
3158: * example, substring("12345",2) returns "2345". More precisely, each
3159: * character in the string (see [3.6 Strings]) is considered to have a
3160: * numeric position: the position of the first character is 1, the position
3161: * of the second character is 2 and so on. The returned substring contains
3162: * those characters for which the position of the character is greater than
3163: * or equal to the second argument and, if the third argument is specified,
3164: * less than the sum of the second and third arguments; the comparisons
3165: * and addition used for the above follow the standard IEEE 754 rules. Thus:
3166: * - substring("12345", 1.5, 2.6) returns "234"
3167: * - substring("12345", 0, 3) returns "12"
3168: * - substring("12345", 0 div 0, 3) returns ""
3169: * - substring("12345", 1, 0 div 0) returns ""
3170: * - substring("12345", -42, 1 div 0) returns "12345"
3171: * - substring("12345", -1 div 0, 1 div 0) returns ""
3172: */
3173: void
3174: xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3175: xmlXPathObjectPtr str, start, len;
1.10 daniel 3176: double le, in;
1.8 daniel 3177: int i, l;
1.29 daniel 3178: xmlChar *ret;
1.8 daniel 3179:
3180: /*
3181: * Conformance needs to be checked !!!!!
3182: */
3183: if (nargs < 2) {
3184: CHECK_ARITY(2);
3185: }
3186: if (nargs > 3) {
3187: CHECK_ARITY(3);
3188: }
1.9 daniel 3189: if (nargs == 3) {
3190: CHECK_TYPE(XPATH_NUMBER);
3191: len = valuePop(ctxt);
3192: le = len->floatval;
3193: xmlXPathFreeObject(len);
3194: } else {
3195: le = 2000000000;
3196: }
3197: CHECK_TYPE(XPATH_NUMBER);
3198: start = valuePop(ctxt);
3199: in = start->floatval;
3200: xmlXPathFreeObject(start);
1.8 daniel 3201: CHECK_TYPE(XPATH_STRING);
3202: str = valuePop(ctxt);
1.9 daniel 3203: le += in;
3204:
3205: /* integer index of the first char */
1.49 daniel 3206: i = (int) in;
1.10 daniel 3207: if (((double)i) != in) i++;
1.9 daniel 3208:
3209: /* integer index of the last char */
1.49 daniel 3210: l = (int) le;
1.10 daniel 3211: if (((double)l) != le) l++;
1.9 daniel 3212:
3213: /* back to a zero based len */
3214: i--;
3215: l--;
3216:
3217: /* check against the string len */
3218: if (l > 1024) {
3219: l = xmlStrlen(str->stringval);
1.8 daniel 3220: }
3221: if (i < 0) {
3222: i = 0;
3223: }
1.9 daniel 3224:
3225: /* number of chars to copy */
3226: l -= i;
3227:
1.8 daniel 3228: ret = xmlStrsub(str->stringval, i, l);
3229: if (ret == NULL)
1.21 daniel 3230: valuePush(ctxt, xmlXPathNewCString(""));
1.11 veillard 3231: else {
1.8 daniel 3232: valuePush(ctxt, xmlXPathNewString(ret));
1.25 daniel 3233: xmlFree(ret);
1.11 veillard 3234: }
1.8 daniel 3235: xmlXPathFreeObject(str);
1.1 daniel 3236: }
3237:
3238: /**
3239: * xmlXPathSubstringBeforeFunction:
3240: * @ctxt: the XPath Parser context
3241: *
3242: * Implement the substring-before() XPath function
1.8 daniel 3243: * The substring-before function returns the substring of the first
3244: * argument string that precedes the first occurrence of the second
3245: * argument string in the first argument string, or the empty string
3246: * if the first argument string does not contain the second argument
3247: * string. For example, substring-before("1999/04/01","/") returns 1999.
1.1 daniel 3248: */
3249: void
1.8 daniel 3250: xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56 veillard 3251: xmlXPathObjectPtr str;
3252: xmlXPathObjectPtr find;
3253: xmlBufferPtr target;
3254: const xmlChar *point;
3255: int offset;
3256:
3257: CHECK_ARITY(2);
3258: find = valuePop(ctxt);
3259: str = valuePop(ctxt);
3260:
3261: target = xmlBufferCreate();
3262: if (target) {
3263: point = xmlStrstr(str->stringval, find->stringval);
3264: if (point) {
3265: offset = (int)(point - str->stringval);
3266: xmlBufferAdd(target, str->stringval, offset);
3267: }
3268: valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3269: xmlBufferFree(target);
3270: }
3271:
3272: xmlXPathFreeObject(str);
3273: xmlXPathFreeObject(find);
1.1 daniel 3274: }
3275:
3276: /**
3277: * xmlXPathSubstringAfterFunction:
3278: * @ctxt: the XPath Parser context
3279: *
3280: * Implement the substring-after() XPath function
1.8 daniel 3281: * The substring-after function returns the substring of the first
3282: * argument string that follows the first occurrence of the second
3283: * argument string in the first argument string, or the empty stringi
3284: * if the first argument string does not contain the second argument
3285: * string. For example, substring-after("1999/04/01","/") returns 04/01,
3286: * and substring-after("1999/04/01","19") returns 99/04/01.
1.1 daniel 3287: */
3288: void
1.8 daniel 3289: xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56 veillard 3290: xmlXPathObjectPtr str;
3291: xmlXPathObjectPtr find;
3292: xmlBufferPtr target;
3293: const xmlChar *point;
3294: int offset;
3295:
3296: CHECK_ARITY(2);
3297: find = valuePop(ctxt);
3298: str = valuePop(ctxt);
3299:
3300: target = xmlBufferCreate();
3301: if (target) {
3302: point = xmlStrstr(str->stringval, find->stringval);
3303: if (point) {
3304: offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
3305: xmlBufferAdd(target, &str->stringval[offset],
3306: xmlStrlen(str->stringval) - offset);
3307: }
3308: valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3309: xmlBufferFree(target);
3310: }
3311:
3312: xmlXPathFreeObject(str);
3313: xmlXPathFreeObject(find);
1.1 daniel 3314: }
3315:
3316: /**
3317: * xmlXPathNormalizeFunction:
3318: * @ctxt: the XPath Parser context
3319: *
3320: * Implement the normalize() XPath function
1.8 daniel 3321: * The normalize function returns the argument string with white
3322: * space normalized by stripping leading and trailing whitespace
3323: * and replacing sequences of whitespace characters by a single
3324: * space. Whitespace characters are the same allowed by the S production
3325: * in XML. If the argument is omitted, it defaults to the context
3326: * node converted to a string, in other words the value of the context node.
1.1 daniel 3327: */
3328: void
1.8 daniel 3329: xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56 veillard 3330: xmlXPathObjectPtr obj = NULL;
3331: xmlChar *source = NULL;
3332: xmlBufferPtr target;
3333: xmlChar blank;
3334:
3335: if (nargs < 1) {
3336: /* Use current context node */
3337: CHECK_ARITY(0);
3338: TODO /* source = xmlNodeGetContent(ctxt->context->node); */
3339: } else if (nargs >= 1) {
3340: /* Use argument */
1.8 daniel 3341: CHECK_ARITY(1);
1.56 veillard 3342: obj = valuePop(ctxt);
3343: if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
3344: source = obj->stringval;
3345: }
3346: target = xmlBufferCreate();
3347: if (target && source) {
3348:
3349: /* Skip leading whitespaces */
3350: while (IS_BLANK(*source))
3351: source++;
3352:
3353: /* Collapse intermediate whitespaces, and skip trailing whitespaces */
3354: blank = 0;
3355: while (*source) {
3356: if (IS_BLANK(*source)) {
3357: blank = *source;
3358: } else {
3359: if (blank) {
3360: xmlBufferAdd(target, &blank, 1);
3361: blank = 0;
3362: }
3363: xmlBufferAdd(target, source, 1);
3364: }
3365: source++;
3366: }
3367:
3368: valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3369: xmlBufferFree(target);
3370: }
3371: if (obj)
3372: xmlXPathFreeObject(obj);
1.1 daniel 3373: }
3374:
3375: /**
3376: * xmlXPathTranslateFunction:
3377: * @ctxt: the XPath Parser context
3378: *
3379: * Implement the translate() XPath function
1.8 daniel 3380: * The translate function returns the first argument string with
3381: * occurrences of characters in the second argument string replaced
3382: * by the character at the corresponding position in the third argument
3383: * string. For example, translate("bar","abc","ABC") returns the string
3384: * BAr. If there is a character in the second argument string with no
3385: * character at a corresponding position in the third argument string
3386: * (because the second argument string is longer than the third argument
3387: * string), then occurrences of that character in the first argument
3388: * string are removed. For example, translate("--aaa--","abc-","ABC")
3389: * returns "AAA". If a character occurs more than once in second
3390: * argument string, then the first occurrence determines the replacement
3391: * character. If the third argument string is longer than the second
3392: * argument string, then excess characters are ignored.
3393: */
3394: void
3395: xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.56 veillard 3396: xmlXPathObjectPtr str;
3397: xmlXPathObjectPtr from;
3398: xmlXPathObjectPtr to;
3399: xmlBufferPtr target;
3400: int i, offset, max;
3401: xmlChar ch;
3402: const xmlChar *point;
3403:
3404: CHECK_ARITY(3);
3405:
3406: to = valuePop(ctxt);
3407: from = valuePop(ctxt);
3408: str = valuePop(ctxt);
3409:
3410: target = xmlBufferCreate();
3411: if (target) {
3412: max = xmlStrlen(to->stringval);
3413: for (i = 0; (ch = str->stringval[i]); i++) {
3414: point = xmlStrchr(from->stringval, ch);
3415: if (point) {
3416: /* Warning: This may not work with UTF-8 */
3417: offset = (int)(point - from->stringval);
3418: if (offset < max)
3419: xmlBufferAdd(target, &to->stringval[offset], 1);
3420: } else
3421: xmlBufferAdd(target, &ch, 1);
3422: }
3423: }
3424: valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
3425: xmlBufferFree(target);
3426: xmlXPathFreeObject(str);
3427: xmlXPathFreeObject(from);
3428: xmlXPathFreeObject(to);
1.1 daniel 3429: }
3430:
3431: /**
3432: * xmlXPathBooleanFunction:
3433: * @ctxt: the XPath Parser context
3434: *
3435: * Implement the boolean() XPath function
1.8 daniel 3436: * he boolean function converts its argument to a boolean as follows:
3437: * - a number is true if and only if it is neither positive or
3438: * negative zero nor NaN
3439: * - a node-set is true if and only if it is non-empty
3440: * - a string is true if and only if its length is non-zero
1.1 daniel 3441: */
3442: void
1.8 daniel 3443: xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3444: xmlXPathObjectPtr cur;
3445: int res = 0;
3446:
3447: CHECK_ARITY(1);
3448: cur = valuePop(ctxt);
1.49 daniel 3449: if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
1.8 daniel 3450: switch (cur->type) {
3451: case XPATH_NODESET:
3452: if ((cur->nodesetval == NULL) ||
3453: (cur->nodesetval->nodeNr == 0)) res = 0;
3454: else
3455: res = 1;
3456: break;
3457: case XPATH_STRING:
3458: if ((cur->stringval == NULL) ||
3459: (cur->stringval[0] == 0)) res = 0;
3460: else
3461: res = 1;
3462: break;
3463: case XPATH_BOOLEAN:
3464: valuePush(ctxt, cur);
3465: return;
3466: case XPATH_NUMBER:
3467: if (cur->floatval) res = 1;
3468: break;
3469: default:
3470: STRANGE
3471: }
3472: xmlXPathFreeObject(cur);
3473: valuePush(ctxt, xmlXPathNewBoolean(res));
1.1 daniel 3474: }
3475:
3476: /**
3477: * xmlXPathNotFunction:
3478: * @ctxt: the XPath Parser context
3479: *
3480: * Implement the not() XPath function
1.8 daniel 3481: * The not function returns true if its argument is false,
3482: * and false otherwise.
1.1 daniel 3483: */
3484: void
1.8 daniel 3485: xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3486: CHECK_ARITY(1);
3487: CHECK_TYPE(XPATH_BOOLEAN);
3488: ctxt->value->boolval = ! ctxt->value->boolval;
1.1 daniel 3489: }
3490:
3491: /**
3492: * xmlXPathTrueFunction:
3493: * @ctxt: the XPath Parser context
3494: *
3495: * Implement the true() XPath function
3496: */
3497: void
1.8 daniel 3498: xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3499: CHECK_ARITY(0);
3500: valuePush(ctxt, xmlXPathNewBoolean(1));
1.1 daniel 3501: }
3502:
3503: /**
3504: * xmlXPathFalseFunction:
3505: * @ctxt: the XPath Parser context
3506: *
3507: * Implement the false() XPath function
3508: */
3509: void
1.8 daniel 3510: xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3511: CHECK_ARITY(0);
3512: valuePush(ctxt, xmlXPathNewBoolean(0));
1.1 daniel 3513: }
3514:
3515: /**
3516: * xmlXPathLangFunction:
3517: * @ctxt: the XPath Parser context
3518: *
3519: * Implement the lang() XPath function
1.8 daniel 3520: * The lang function returns true or false depending on whether the
3521: * language of the context node as specified by xml:lang attributes
3522: * is the same as or is a sublanguage of the language specified by
3523: * the argument string. The language of the context node is determined
3524: * by the value of the xml:lang attribute on the context node, or, if
3525: * the context node has no xml:lang attribute, by the value of the
3526: * xml:lang attribute on the nearest ancestor of the context node that
3527: * has an xml:lang attribute. If there is no such attribute, then lang
3528: * returns false. If there is such an attribute, then lang returns
3529: * true if the attribute value is equal to the argument ignoring case,
3530: * or if there is some suffix starting with - such that the attribute
3531: * value is equal to the argument ignoring that suffix of the attribute
3532: * value and ignoring case.
3533: */
3534: void
3535: xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.19 daniel 3536: xmlXPathObjectPtr val;
1.29 daniel 3537: const xmlChar *theLang;
3538: const xmlChar *lang;
1.19 daniel 3539: int ret = 0;
3540: int i;
3541:
3542: CHECK_ARITY(1);
3543: CHECK_TYPE(XPATH_STRING);
3544: val = valuePop(ctxt);
3545: lang = val->stringval;
3546: theLang = xmlNodeGetLang(ctxt->context->node);
3547: if ((theLang != NULL) && (lang != NULL)) {
3548: for (i = 0;lang[i] != 0;i++)
3549: if (toupper(lang[i]) != toupper(theLang[i]))
3550: goto not_equal;
3551: ret = 1;
3552: }
3553: not_equal:
3554: xmlXPathFreeObject(val);
3555: valuePush(ctxt, xmlXPathNewBoolean(ret));
1.1 daniel 3556: }
3557:
3558: /**
3559: * xmlXPathNumberFunction:
3560: * @ctxt: the XPath Parser context
3561: *
3562: * Implement the number() XPath function
3563: */
3564: void
1.8 daniel 3565: xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.5 daniel 3566: xmlXPathObjectPtr cur;
1.10 daniel 3567: double res;
1.5 daniel 3568:
1.8 daniel 3569: CHECK_ARITY(1);
1.5 daniel 3570: cur = valuePop(ctxt);
3571: switch (cur->type) {
1.59 veillard 3572: case XPATH_UNDEFINED:
3573: #ifdef DEBUG_EXPR
3574: fprintf(xmlXPathDebug, "NUMBER: undefined\n");
3575: #endif
3576: valuePush(ctxt, xmlXPathNewFloat(0.0));
3577: break;
1.5 daniel 3578: case XPATH_NODESET:
3579: valuePush(ctxt, cur);
1.8 daniel 3580: xmlXPathStringFunction(ctxt, 1);
1.5 daniel 3581: cur = valuePop(ctxt);
3582: case XPATH_STRING:
3583: res = xmlXPathStringEvalNumber(cur->stringval);
3584: valuePush(ctxt, xmlXPathNewFloat(res));
3585: xmlXPathFreeObject(cur);
3586: return;
3587: case XPATH_BOOLEAN:
3588: if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
3589: else valuePush(ctxt, xmlXPathNewFloat(0.0));
3590: xmlXPathFreeObject(cur);
3591: return;
3592: case XPATH_NUMBER:
3593: valuePush(ctxt, cur);
3594: return;
1.59 veillard 3595: case XPATH_USERS:
1.62 veillard 3596: case XPATH_POINT:
3597: case XPATH_RANGE:
1.63 veillard 3598: case XPATH_LOCATIONSET:
1.59 veillard 3599: TODO
3600: valuePush(ctxt, xmlXPathNewFloat(0.0));
3601: break;
1.5 daniel 3602: }
3603: STRANGE
1.1 daniel 3604: }
3605:
3606: /**
3607: * xmlXPathSumFunction:
3608: * @ctxt: the XPath Parser context
3609: *
3610: * Implement the sum() XPath function
1.8 daniel 3611: * The sum function returns the sum of the values of the nodes in
3612: * the argument node-set.
1.1 daniel 3613: */
3614: void
1.8 daniel 3615: xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3616: CHECK_ARITY(1);
3617: TODO /* BUG Sum : don't understand the definition */
1.1 daniel 3618: }
3619:
3620: /**
3621: * xmlXPathFloorFunction:
3622: * @ctxt: the XPath Parser context
3623: *
3624: * Implement the floor() XPath function
1.8 daniel 3625: * The floor function returns the largest (closest to positive infinity)
3626: * number that is not greater than the argument and that is an integer.
1.1 daniel 3627: */
3628: void
1.8 daniel 3629: xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
3630: CHECK_ARITY(1);
3631: CHECK_TYPE(XPATH_NUMBER);
1.9 daniel 3632: /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
1.10 daniel 3633: ctxt->value->floatval = (double)((int) ctxt->value->floatval);
1.1 daniel 3634: }
3635:
3636: /**
3637: * xmlXPathCeilingFunction:
3638: * @ctxt: the XPath Parser context
3639: *
3640: * Implement the ceiling() XPath function
1.8 daniel 3641: * The ceiling function returns the smallest (closest to negative infinity)
3642: * number that is not less than the argument and that is an integer.
1.1 daniel 3643: */
3644: void
1.8 daniel 3645: xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.10 daniel 3646: double f;
1.8 daniel 3647:
3648: CHECK_ARITY(1);
3649: CHECK_TYPE(XPATH_NUMBER);
1.10 daniel 3650: f = (double)((int) ctxt->value->floatval);
1.8 daniel 3651: if (f != ctxt->value->floatval)
3652: ctxt->value->floatval = f + 1;
1.1 daniel 3653: }
3654:
3655: /**
3656: * xmlXPathRoundFunction:
3657: * @ctxt: the XPath Parser context
3658: *
3659: * Implement the round() XPath function
1.8 daniel 3660: * The round function returns the number that is closest to the
3661: * argument and that is an integer. If there are two such numbers,
3662: * then the one that is even is returned.
3663: */
3664: void
3665: xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
1.10 daniel 3666: double f;
1.8 daniel 3667:
3668: CHECK_ARITY(1);
3669: CHECK_TYPE(XPATH_NUMBER);
1.9 daniel 3670: /* round(0.50000001) => 0 !!!!! */
1.10 daniel 3671: f = (double)((int) ctxt->value->floatval);
1.8 daniel 3672: if (ctxt->value->floatval < f + 0.5)
3673: ctxt->value->floatval = f;
3674: else if (ctxt->value->floatval == f + 0.5)
3675: ctxt->value->floatval = f; /* !!!! Not following the spec here */
3676: else
3677: ctxt->value->floatval = f + 1;
1.1 daniel 3678: }
3679:
3680: /************************************************************************
3681: * *
3682: * The Parser *
3683: * *
3684: ************************************************************************/
3685:
1.4 daniel 3686: /*
3687: * a couple of forward declarations since we use a recursive call based
3688: * implementation.
3689: */
1.1 daniel 3690: void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
1.4 daniel 3691: void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
3692: void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
3693: void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
1.1 daniel 3694:
3695: /**
3696: * xmlXPathParseNCName:
3697: * @ctxt: the XPath Parser context
3698: *
3699: * parse an XML namespace non qualified name.
3700: *
3701: * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
3702: *
3703: * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
3704: * CombiningChar | Extender
3705: *
3706: * Returns the namespace name or NULL
3707: */
3708:
1.29 daniel 3709: xmlChar *
1.1 daniel 3710: xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
1.29 daniel 3711: const xmlChar *q;
3712: xmlChar *ret = NULL;
1.1 daniel 3713:
3714: if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3715: q = NEXT;
3716:
3717: while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3718: (CUR == '.') || (CUR == '-') ||
3719: (CUR == '_') ||
3720: (IS_COMBINING(CUR)) ||
3721: (IS_EXTENDER(CUR)))
3722: NEXT;
3723:
3724: ret = xmlStrndup(q, CUR_PTR - q);
3725:
3726: return(ret);
3727: }
3728:
3729: /**
3730: * xmlXPathParseQName:
3731: * @ctxt: the XPath Parser context
1.29 daniel 3732: * @prefix: a xmlChar **
1.1 daniel 3733: *
3734: * parse an XML qualified name
3735: *
3736: * [NS 5] QName ::= (Prefix ':')? LocalPart
3737: *
3738: * [NS 6] Prefix ::= NCName
3739: *
3740: * [NS 7] LocalPart ::= NCName
3741: *
3742: * Returns the function returns the local part, and prefix is updated
3743: * to get the Prefix if any.
3744: */
3745:
1.29 daniel 3746: xmlChar *
3747: xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
3748: xmlChar *ret = NULL;
1.1 daniel 3749:
3750: *prefix = NULL;
3751: ret = xmlXPathParseNCName(ctxt);
3752: if (CUR == ':') {
3753: *prefix = ret;
3754: NEXT;
3755: ret = xmlXPathParseNCName(ctxt);
3756: }
3757: return(ret);
3758: }
3759:
3760: /**
1.74 veillard 3761: * xmlXPathParseName:
3762: * @ctxt: the XPointer Parser context
3763: *
3764: * parse an XML name
3765: *
3766: * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
3767: * CombiningChar | Extender
3768: *
3769: * [5] Name ::= (Letter | '_' | ':') (NameChar)*
3770: *
3771: * Returns the namespace name or NULL
3772: */
3773:
3774: xmlChar *
3775: xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
3776: const xmlChar *q;
3777: xmlChar *ret = NULL;
3778:
3779: if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
3780: q = NEXT;
3781:
3782: /* TODO Make this UTF8 compliant !!! */
3783: while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
3784: (CUR == '.') || (CUR == '-') ||
3785: (CUR == '_') || (CUR == ':') ||
3786: (IS_COMBINING(CUR)) ||
3787: (IS_EXTENDER(CUR)))
3788: NEXT;
3789:
3790: ret = xmlStrndup(q, CUR_PTR - q);
3791:
3792: return(ret);
3793: }
3794:
3795: /**
1.5 daniel 3796: * xmlXPathStringEvalNumber:
3797: * @str: A string to scan
3798: *
3799: * [30] Number ::= Digits ('.' Digits)?
3800: * | '.' Digits
3801: * [31] Digits ::= [0-9]+
3802: *
3803: * Parse and evaluate a Number in the string
3804: *
3805: * BUG: "1.' is not valid ... James promised correction
3806: * as Digits ('.' Digits?)?
3807: *
1.10 daniel 3808: * Returns the double value.
1.5 daniel 3809: */
1.10 daniel 3810: double
1.29 daniel 3811: xmlXPathStringEvalNumber(const xmlChar *str) {
3812: const xmlChar *cur = str;
1.10 daniel 3813: double ret = 0.0;
3814: double mult = 1;
1.5 daniel 3815: int ok = 0;
3816:
3817: while (*cur == ' ') cur++;
3818: if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
1.10 daniel 3819: return(xmlXPathNAN);
1.5 daniel 3820: }
3821: while ((*cur >= '0') && (*cur <= '9')) {
3822: ret = ret * 10 + (*cur - '0');
3823: ok = 1;
3824: cur++;
3825: }
3826: if (*cur == '.') {
3827: cur++;
3828: if (((*cur < '0') || (*cur > '9')) && (!ok)) {
1.10 daniel 3829: return(xmlXPathNAN);
1.5 daniel 3830: }
3831: while ((*cur >= '0') && (*cur <= '9')) {
3832: mult /= 10;
3833: ret = ret + (*cur - '0') * mult;
3834: cur++;
3835: }
3836: }
3837: while (*cur == ' ') cur++;
1.10 daniel 3838: if (*cur != 0) return(xmlXPathNAN);
1.5 daniel 3839: return(ret);
3840: }
3841:
3842: /**
1.1 daniel 3843: * xmlXPathEvalNumber:
3844: * @ctxt: the XPath Parser context
3845: *
3846: * [30] Number ::= Digits ('.' Digits)?
3847: * | '.' Digits
3848: * [31] Digits ::= [0-9]+
3849: *
3850: * Parse and evaluate a Number, then push it on the stack
3851: *
1.4 daniel 3852: * BUG: "1.' is not valid ... James promised correction
3853: * as Digits ('.' Digits?)?
1.1 daniel 3854: */
3855: void
3856: xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
1.10 daniel 3857: double ret = 0.0;
3858: double mult = 1;
1.4 daniel 3859: int ok = 0;
1.1 daniel 3860:
3861: CHECK_ERROR;
3862: if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
1.49 daniel 3863: XP_ERROR(XPATH_NUMBER_ERROR);
1.1 daniel 3864: }
3865: while ((CUR >= '0') && (CUR <= '9')) {
3866: ret = ret * 10 + (CUR - '0');
1.4 daniel 3867: ok = 1;
1.1 daniel 3868: NEXT;
3869: }
3870: if (CUR == '.') {
3871: NEXT;
1.4 daniel 3872: if (((CUR < '0') || (CUR > '9')) && (!ok)) {
1.49 daniel 3873: XP_ERROR(XPATH_NUMBER_ERROR);
1.1 daniel 3874: }
3875: while ((CUR >= '0') && (CUR <= '9')) {
3876: mult /= 10;
3877: ret = ret + (CUR - '0') * mult;
3878: NEXT;
3879: }
3880: }
3881: valuePush(ctxt, xmlXPathNewFloat(ret));
3882: }
3883:
3884: /**
3885: * xmlXPathEvalLiteral:
3886: * @ctxt: the XPath Parser context
3887: *
3888: * Parse a Literal and push it on the stack.
3889: *
3890: * [29] Literal ::= '"' [^"]* '"'
3891: * | "'" [^']* "'"
3892: *
1.22 daniel 3893: * TODO: xmlXPathEvalLiteral memory allocation could be improved.
1.1 daniel 3894: */
3895: void
3896: xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
1.29 daniel 3897: const xmlChar *q;
3898: xmlChar *ret = NULL;
1.1 daniel 3899:
3900: if (CUR == '"') {
3901: NEXT;
3902: q = CUR_PTR;
3903: while ((IS_CHAR(CUR)) && (CUR != '"'))
3904: NEXT;
3905: if (!IS_CHAR(CUR)) {
1.49 daniel 3906: XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
1.1 daniel 3907: } else {
3908: ret = xmlStrndup(q, CUR_PTR - q);
3909: NEXT;
3910: }
3911: } else if (CUR == '\'') {
3912: NEXT;
3913: q = CUR_PTR;
3914: while ((IS_CHAR(CUR)) && (CUR != '\''))
3915: NEXT;
3916: if (!IS_CHAR(CUR)) {
1.49 daniel 3917: XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
1.1 daniel 3918: } else {
3919: ret = xmlStrndup(q, CUR_PTR - q);
3920: NEXT;
3921: }
3922: } else {
1.49 daniel 3923: XP_ERROR(XPATH_START_LITERAL_ERROR);
1.1 daniel 3924: }
3925: if (ret == NULL) return;
3926: valuePush(ctxt, xmlXPathNewString(ret));
1.25 daniel 3927: xmlFree(ret);
1.1 daniel 3928: }
3929:
3930: /**
3931: * xmlXPathEvalVariableReference:
3932: * @ctxt: the XPath Parser context
3933: *
3934: * Parse a VariableReference, evaluate it and push it on the stack.
3935: *
3936: * The variable bindings consist of a mapping from variable names
3937: * to variable values. The value of a variable is an object, which
3938: * of any of the types that are possible for the value of an expression,
3939: * and may also be of additional types not specified here.
3940: *
3941: * Early evaluation is possible since:
3942: * The variable bindings [...] used to evaluate a subexpression are
3943: * always the same as those used to evaluate the containing expression.
3944: *
3945: * [36] VariableReference ::= '$' QName
3946: */
3947: void
3948: xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
1.29 daniel 3949: xmlChar *name;
1.1 daniel 3950: xmlXPathObjectPtr value;
3951:
1.68 veillard 3952: SKIP_BLANKS;
1.1 daniel 3953: if (CUR != '$') {
1.49 daniel 3954: XP_ERROR(XPATH_VARIABLE_REF_ERROR);
1.1 daniel 3955: }
1.74 veillard 3956: name = xmlXPathParseName(ctxt);
1.1 daniel 3957: if (name == NULL) {
1.49 daniel 3958: XP_ERROR(XPATH_VARIABLE_REF_ERROR);
1.1 daniel 3959: }
1.74 veillard 3960: value = xmlXPathVariableLookup(ctxt->context, name);
1.1 daniel 3961: if (value == NULL) {
1.49 daniel 3962: XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
1.1 daniel 3963: }
3964: valuePush(ctxt, value);
1.25 daniel 3965: xmlFree(name);
1.68 veillard 3966: SKIP_BLANKS;
1.1 daniel 3967: }
3968:
1.65 veillard 3969: /**
3970: * xmlXPathIsNodeType:
3971: * @ctxt: the XPath Parser context
3972: * @name: a name string
3973: *
3974: * Is the name given a NodeType one.
3975: *
3976: * [38] NodeType ::= 'comment'
3977: * | 'text'
3978: * | 'processing-instruction'
3979: * | 'node'
3980: *
3981: * Returns 1 if true 0 otherwise
3982: */
3983: int
3984: xmlXPathIsNodeType(const xmlChar *name) {
3985: if (name == NULL)
3986: return(0);
3987:
3988: if (xmlStrEqual(name, BAD_CAST "comment"))
3989: return(1);
3990: if (xmlStrEqual(name, BAD_CAST "text"))
3991: return(1);
3992: if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
3993: return(1);
3994: if (xmlStrEqual(name, BAD_CAST "node"))
3995: return(1);
3996: return(0);
3997: }
3998:
1.1 daniel 3999:
4000: /**
1.65 veillard 4001: * xmlXPathIsFunction:
1.1 daniel 4002: * @ctxt: the XPath Parser context
4003: * @name: a name string
4004: *
4005: * Search for a function of the given name
4006: *
4007: * [35] FunctionName ::= QName - NodeType
4008: *
1.22 daniel 4009: * TODO: for the moment the function list is hardcoded from the spec !!!!
1.1 daniel 4010: *
4011: * Returns the xmlXPathFunction if found, or NULL otherwise
4012: */
4013: xmlXPathFunction
1.29 daniel 4014: xmlXPathIsFunction(xmlXPathParserContextPtr ctxt, const xmlChar *name) {
1.74 veillard 4015: if (name == NULL)
4016: return(NULL);
4017:
1.1 daniel 4018: switch (name[0]) {
4019: case 'b':
1.58 veillard 4020: if (xmlStrEqual(name, BAD_CAST "boolean"))
1.9 daniel 4021: return(xmlXPathBooleanFunction);
1.1 daniel 4022: break;
4023: case 'c':
1.58 veillard 4024: if (xmlStrEqual(name, BAD_CAST "ceiling"))
1.9 daniel 4025: return(xmlXPathCeilingFunction);
1.58 veillard 4026: if (xmlStrEqual(name, BAD_CAST "count"))
1.9 daniel 4027: return(xmlXPathCountFunction);
1.58 veillard 4028: if (xmlStrEqual(name, BAD_CAST "concat"))
1.9 daniel 4029: return(xmlXPathConcatFunction);
1.58 veillard 4030: if (xmlStrEqual(name, BAD_CAST "contains"))
1.9 daniel 4031: return(xmlXPathContainsFunction);
1.1 daniel 4032: break;
4033: case 'i':
1.58 veillard 4034: if (xmlStrEqual(name, BAD_CAST "id"))
1.9 daniel 4035: return(xmlXPathIdFunction);
1.1 daniel 4036: break;
4037: case 'f':
1.58 veillard 4038: if (xmlStrEqual(name, BAD_CAST "false"))
1.9 daniel 4039: return(xmlXPathFalseFunction);
1.58 veillard 4040: if (xmlStrEqual(name, BAD_CAST "floor"))
1.9 daniel 4041: return(xmlXPathFloorFunction);
1.1 daniel 4042: break;
4043: case 'l':
1.58 veillard 4044: if (xmlStrEqual(name, BAD_CAST "last"))
1.9 daniel 4045: return(xmlXPathLastFunction);
1.58 veillard 4046: if (xmlStrEqual(name, BAD_CAST "lang"))
1.9 daniel 4047: return(xmlXPathLangFunction);
1.58 veillard 4048: if (xmlStrEqual(name, BAD_CAST "local-part"))
1.9 daniel 4049: return(xmlXPathLocalPartFunction);
1.1 daniel 4050: break;
4051: case 'n':
1.58 veillard 4052: if (xmlStrEqual(name, BAD_CAST "not"))
1.9 daniel 4053: return(xmlXPathNotFunction);
1.58 veillard 4054: if (xmlStrEqual(name, BAD_CAST "name"))
1.9 daniel 4055: return(xmlXPathNameFunction);
1.58 veillard 4056: if (xmlStrEqual(name, BAD_CAST "namespace"))
1.9 daniel 4057: return(xmlXPathNamespaceFunction);
1.58 veillard 4058: if (xmlStrEqual(name, BAD_CAST "normalize-space"))
1.30 daniel 4059: return(xmlXPathNormalizeFunction);
1.58 veillard 4060: if (xmlStrEqual(name, BAD_CAST "normalize"))
1.9 daniel 4061: return(xmlXPathNormalizeFunction);
1.58 veillard 4062: if (xmlStrEqual(name, BAD_CAST "number"))
1.9 daniel 4063: return(xmlXPathNumberFunction);
1.1 daniel 4064: break;
4065: case 'p':
1.58 veillard 4066: if (xmlStrEqual(name, BAD_CAST "position"))
1.9 daniel 4067: return(xmlXPathPositionFunction);
1.1 daniel 4068: break;
4069: case 'r':
1.58 veillard 4070: if (xmlStrEqual(name, BAD_CAST "round"))
1.9 daniel 4071: return(xmlXPathRoundFunction);
1.1 daniel 4072: break;
4073: case 's':
1.58 veillard 4074: if (xmlStrEqual(name, BAD_CAST "string"))
1.9 daniel 4075: return(xmlXPathStringFunction);
1.58 veillard 4076: if (xmlStrEqual(name, BAD_CAST "string-length"))
1.9 daniel 4077: return(xmlXPathStringLengthFunction);
1.58 veillard 4078: if (xmlStrEqual(name, BAD_CAST "starts-with"))
1.9 daniel 4079: return(xmlXPathStartsWithFunction);
1.58 veillard 4080: if (xmlStrEqual(name, BAD_CAST "substring"))
1.9 daniel 4081: return(xmlXPathSubstringFunction);
1.58 veillard 4082: if (xmlStrEqual(name, BAD_CAST "substring-before"))
1.9 daniel 4083: return(xmlXPathSubstringBeforeFunction);
1.58 veillard 4084: if (xmlStrEqual(name, BAD_CAST "substring-after"))
1.9 daniel 4085: return(xmlXPathSubstringAfterFunction);
1.58 veillard 4086: if (xmlStrEqual(name, BAD_CAST "sum"))
1.9 daniel 4087: return(xmlXPathSumFunction);
1.1 daniel 4088: break;
4089: case 't':
1.58 veillard 4090: if (xmlStrEqual(name, BAD_CAST "true"))
1.9 daniel 4091: return(xmlXPathTrueFunction);
1.58 veillard 4092: if (xmlStrEqual(name, BAD_CAST "translate"))
1.9 daniel 4093: return(xmlXPathTranslateFunction);
1.1 daniel 4094: break;
4095: }
1.74 veillard 4096: return(xmlXPathFunctionLookup(ctxt->context, name));
1.1 daniel 4097: }
4098:
4099: /**
4100: * xmlXPathEvalFunctionCall:
4101: * @ctxt: the XPath Parser context
4102: *
4103: * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
4104: * [17] Argument ::= Expr
4105: *
1.5 daniel 4106: * Parse and evaluate a function call, the evaluation of all arguments are
4107: * pushed on the stack
1.1 daniel 4108: */
4109: void
4110: xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
1.29 daniel 4111: xmlChar *name;
4112: xmlChar *prefix;
1.4 daniel 4113: xmlXPathFunction func;
1.8 daniel 4114: int nbargs = 0;
1.4 daniel 4115:
4116: name = xmlXPathParseQName(ctxt, &prefix);
4117: if (name == NULL) {
1.49 daniel 4118: XP_ERROR(XPATH_EXPR_ERROR);
1.4 daniel 4119: }
1.30 daniel 4120: SKIP_BLANKS;
1.4 daniel 4121: func = xmlXPathIsFunction(ctxt, name);
4122: if (func == NULL) {
1.25 daniel 4123: xmlFree(name);
1.49 daniel 4124: XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
1.4 daniel 4125: }
1.6 daniel 4126: #ifdef DEBUG_EXPR
1.9 daniel 4127: fprintf(xmlXPathDebug, "Calling function %s\n", name);
1.6 daniel 4128: #endif
4129:
1.5 daniel 4130: if (CUR != '(') {
1.25 daniel 4131: xmlFree(name);
1.49 daniel 4132: XP_ERROR(XPATH_EXPR_ERROR);
1.5 daniel 4133: }
4134: NEXT;
1.30 daniel 4135: SKIP_BLANKS;
1.8 daniel 4136:
1.5 daniel 4137: while (CUR != ')') {
4138: xmlXPathEvalExpr(ctxt);
1.8 daniel 4139: nbargs++;
1.5 daniel 4140: if (CUR == ')') break;
4141: if (CUR != ',') {
1.25 daniel 4142: xmlFree(name);
1.49 daniel 4143: XP_ERROR(XPATH_EXPR_ERROR);
1.5 daniel 4144: }
1.9 daniel 4145: NEXT;
1.30 daniel 4146: SKIP_BLANKS;
1.5 daniel 4147: }
4148: NEXT;
1.30 daniel 4149: SKIP_BLANKS;
1.25 daniel 4150: xmlFree(name);
1.8 daniel 4151: func(ctxt, nbargs);
1.1 daniel 4152: }
4153:
4154: /**
4155: * xmlXPathEvalPrimaryExpr:
4156: * @ctxt: the XPath Parser context
4157: *
4158: * [15] PrimaryExpr ::= VariableReference
4159: * | '(' Expr ')'
4160: * | Literal
4161: * | Number
4162: * | FunctionCall
4163: *
4164: * Parse and evaluate a primary expression, then push the result on the stack
4165: */
4166: void
4167: xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
1.30 daniel 4168: SKIP_BLANKS;
1.1 daniel 4169: if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
4170: else if (CUR == '(') {
1.65 veillard 4171: NEXT;
1.30 daniel 4172: SKIP_BLANKS;
1.65 veillard 4173: xmlXPathEvalExpr(ctxt);
1.1 daniel 4174: if (CUR != ')') {
1.49 daniel 4175: XP_ERROR(XPATH_EXPR_ERROR);
1.1 daniel 4176: }
4177: NEXT;
1.30 daniel 4178: SKIP_BLANKS;
1.1 daniel 4179: } else if (IS_DIGIT(CUR)) {
1.65 veillard 4180: xmlXPathEvalNumber(ctxt);
1.1 daniel 4181: } else if ((CUR == '\'') || (CUR == '"')) {
1.65 veillard 4182: xmlXPathEvalLiteral(ctxt);
1.1 daniel 4183: } else {
1.65 veillard 4184: xmlXPathEvalFunctionCall(ctxt);
1.1 daniel 4185: }
1.68 veillard 4186: SKIP_BLANKS;
1.1 daniel 4187: }
4188:
4189: /**
1.4 daniel 4190: * xmlXPathEvalFilterExpr:
4191: * @ctxt: the XPath Parser context
4192: *
4193: * [20] FilterExpr ::= PrimaryExpr
4194: * | FilterExpr Predicate
4195: *
4196: * Parse and evaluate a filter expression, then push the result on the stack
1.8 daniel 4197: * Square brackets are used to filter expressions in the same way that
4198: * they are used in location paths. It is an error if the expression to
4199: * be filtered does not evaluate to a node-set. The context node list
4200: * used for evaluating the expression in square brackets is the node-set
4201: * to be filtered listed in document order.
1.4 daniel 4202: */
4203:
4204: void
4205: xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
4206: xmlXPathEvalPrimaryExpr(ctxt);
4207: CHECK_ERROR;
1.30 daniel 4208: SKIP_BLANKS;
1.8 daniel 4209:
4210: if (CUR != '[') return;
4211:
4212: CHECK_TYPE(XPATH_NODESET);
4213:
1.4 daniel 4214: while (CUR == '[') {
4215: xmlXPathEvalPredicate(ctxt);
1.30 daniel 4216: SKIP_BLANKS;
1.8 daniel 4217: }
1.4 daniel 4218:
1.8 daniel 4219:
1.4 daniel 4220: }
4221:
4222: /**
1.19 daniel 4223: * xmlXPathScanName:
4224: * @ctxt: the XPath Parser context
4225: *
4226: * Trickery: parse an XML name but without consuming the input flow
1.66 veillard 4227: * Needed to avoid insanity in the parser state.
1.19 daniel 4228: *
4229: * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
4230: * CombiningChar | Extender
4231: *
4232: * [5] Name ::= (Letter | '_' | ':') (NameChar)*
4233: *
4234: * [6] Names ::= Name (S Name)*
4235: *
4236: * Returns the Name parsed or NULL
4237: */
4238:
1.29 daniel 4239: xmlChar *
1.19 daniel 4240: xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
1.29 daniel 4241: xmlChar buf[XML_MAX_NAMELEN];
1.19 daniel 4242: int len = 0;
4243:
1.30 daniel 4244: SKIP_BLANKS;
1.19 daniel 4245: if (!IS_LETTER(CUR) && (CUR != '_') &&
4246: (CUR != ':')) {
4247: return(NULL);
4248: }
4249:
4250: while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4251: (NXT(len) == '.') || (NXT(len) == '-') ||
4252: (NXT(len) == '_') || (NXT(len) == ':') ||
4253: (IS_COMBINING(NXT(len))) ||
4254: (IS_EXTENDER(NXT(len)))) {
4255: buf[len] = NXT(len);
4256: len++;
4257: if (len >= XML_MAX_NAMELEN) {
4258: fprintf(stderr,
4259: "xmlScanName: reached XML_MAX_NAMELEN limit\n");
4260: while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
4261: (NXT(len) == '.') || (NXT(len) == '-') ||
4262: (NXT(len) == '_') || (NXT(len) == ':') ||
4263: (IS_COMBINING(NXT(len))) ||
4264: (IS_EXTENDER(NXT(len))))
4265: len++;
4266: break;
4267: }
4268: }
4269: return(xmlStrndup(buf, len));
4270: }
4271:
4272: /**
1.4 daniel 4273: * xmlXPathEvalPathExpr:
4274: * @ctxt: the XPath Parser context
4275: *
4276: * [19] PathExpr ::= LocationPath
4277: * | FilterExpr
4278: * | FilterExpr '/' RelativeLocationPath
4279: * | FilterExpr '//' RelativeLocationPath
4280: *
4281: * Parse and evaluate a path expression, then push the result on the stack
1.8 daniel 4282: * The / operator and // operators combine an arbitrary expression
4283: * and a relative location path. It is an error if the expression
4284: * does not evaluate to a node-set.
4285: * The / operator does composition in the same way as when / is
4286: * used in a location path. As in location paths, // is short for
4287: * /descendant-or-self::node()/.
1.4 daniel 4288: */
4289:
4290: void
4291: xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
1.65 veillard 4292: int lc = 1; /* Should we branch to LocationPath ? */
4293: xmlChar *name = NULL; /* we may have to preparse a name to find out */
4294:
1.30 daniel 4295: SKIP_BLANKS;
1.4 daniel 4296: if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
4297: (CUR == '\'') || (CUR == '"')) {
1.65 veillard 4298: lc = 0;
4299: } else if (CUR == '/') {
1.66 veillard 4300: /* relative or absolute location path */
4301: lc = 1;
4302: } else if (CUR == '@') {
4303: /* relative abbreviated attribute location path */
1.65 veillard 4304: lc = 1;
1.68 veillard 4305: } else if (CUR == '.') {
4306: /* relative abbreviated attribute location path */
4307: lc = 1;
1.65 veillard 4308: } else {
4309: /*
4310: * Problem is finding if we have a name here whether it's:
4311: * - a nodetype
4312: * - a function call in which case it's followed by '('
4313: * - an axis in which case it's followed by ':'
4314: * - a element name
4315: * We do an a priori analysis here rather than having to
4316: * maintain parsed token content through the recursive function
4317: * calls. This looks uglier but makes the code quite easier to
4318: * read/write/debug.
4319: */
4320: SKIP_BLANKS;
4321: name = xmlXPathScanName(ctxt);
4322: if (name != NULL) {
4323: int len =xmlStrlen(name);
4324: int blank = 0;
4325:
4326: while (NXT(len) != 0) {
4327: if (NXT(len) == '/') {
4328: /* element name */
4329: #ifdef DEBUG_STEP
4330: fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4331: #endif
4332: lc = 1;
4333: break;
4334: } else if (IS_BLANK(NXT(len))) {
4335: /* skip to next */
4336: blank = 1;
4337: } else if (NXT(len) == ':') {
4338: #ifdef DEBUG_STEP
4339: fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4340: #endif
4341: lc = 1;
4342: break;
4343: } else if ((NXT(len) == '(')) {
4344: /* Note Type or Function */
4345: if (xmlXPathIsNodeType(name)) {
4346: #ifdef DEBUG_STEP
4347: fprintf(xmlXPathDebug, "PathExpr: Type search\n");
4348: #endif
4349: lc = 1;
4350: } else {
4351: #ifdef DEBUG_STEP
4352: fprintf(xmlXPathDebug, "PathExpr: function call\n");
4353: #endif
4354: lc = 0;
4355: }
4356: break;
1.68 veillard 4357: } else if ((NXT(len) == '[')) {
4358: /* element name */
4359: #ifdef DEBUG_STEP
4360: fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4361: #endif
4362: lc = 1;
4363: break;
1.65 veillard 4364: } else {
4365: XP_ERROR(XPATH_EXPR_ERROR);
4366: }
4367: len++;
4368: }
4369: if (NXT(len) == 0) {
4370: #ifdef DEBUG_STEP
4371: fprintf(xmlXPathDebug, "PathExpr: AbbrRelLocation\n");
4372: #endif
4373: /* element name */
4374: lc = 1;
4375: }
4376: xmlFree(name);
4377: } else {
1.66 veillard 4378: /* make sure all cases are covered explicitely */
1.65 veillard 4379: XP_ERROR(XPATH_EXPR_ERROR);
4380: }
4381: }
1.66 veillard 4382:
1.65 veillard 4383: if (lc) {
4384: xmlXPathEvalLocationPath(ctxt);
4385: } else {
1.4 daniel 4386: xmlXPathEvalFilterExpr(ctxt);
4387: CHECK_ERROR;
4388: if ((CUR == '/') && (NXT(1) == '/')) {
1.8 daniel 4389: SKIP(2);
1.30 daniel 4390: SKIP_BLANKS;
1.59 veillard 4391: xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
1.8 daniel 4392: NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
4393: ctxt->context->node = NULL;
1.4 daniel 4394: xmlXPathEvalRelativeLocationPath(ctxt);
4395: } else if (CUR == '/') {
4396: xmlXPathEvalRelativeLocationPath(ctxt);
4397: }
1.65 veillard 4398: }
1.68 veillard 4399: SKIP_BLANKS;
1.4 daniel 4400: }
4401:
4402: /**
4403: * xmlXPathEvalUnionExpr:
4404: * @ctxt: the XPath Parser context
4405: *
4406: * [18] UnionExpr ::= PathExpr
4407: * | UnionExpr '|' PathExpr
4408: *
4409: * Parse and evaluate an union expression, then push the result on the stack
4410: */
4411:
4412: void
4413: xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
4414: xmlXPathEvalPathExpr(ctxt);
4415: CHECK_ERROR;
1.30 daniel 4416: SKIP_BLANKS;
1.4 daniel 4417: if (CUR == '|') {
1.59 veillard 4418: xmlXPathObjectPtr obj1,obj2;
4419:
4420: CHECK_TYPE(XPATH_NODESET);
4421: obj1 = valuePop(ctxt);
4422: valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
1.4 daniel 4423:
1.30 daniel 4424: NEXT;
4425: SKIP_BLANKS;
1.4 daniel 4426: xmlXPathEvalPathExpr(ctxt);
4427:
1.59 veillard 4428: CHECK_TYPE(XPATH_NODESET);
4429: obj2 = valuePop(ctxt);
4430: obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
4431: obj2->nodesetval);
4432: xmlXPathFreeObject(obj2);
1.68 veillard 4433: SKIP_BLANKS;
1.4 daniel 4434: }
4435: }
4436:
4437: /**
1.1 daniel 4438: * xmlXPathEvalUnaryExpr:
4439: * @ctxt: the XPath Parser context
4440: *
4441: * [27] UnaryExpr ::= UnionExpr
4442: * | '-' UnaryExpr
4443: *
4444: * Parse and evaluate an unary expression, then push the result on the stack
4445: */
4446:
4447: void
4448: xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
4449: int minus = 0;
4450:
1.30 daniel 4451: SKIP_BLANKS;
1.1 daniel 4452: if (CUR == '-') {
4453: minus = 1;
4454: NEXT;
1.30 daniel 4455: SKIP_BLANKS;
1.1 daniel 4456: }
1.19 daniel 4457: xmlXPathEvalUnionExpr(ctxt);
1.1 daniel 4458: CHECK_ERROR;
4459: if (minus) {
1.6 daniel 4460: xmlXPathValueFlipSign(ctxt);
1.1 daniel 4461: }
4462: }
4463:
4464: /**
4465: * xmlXPathEvalMultiplicativeExpr:
4466: * @ctxt: the XPath Parser context
4467: *
4468: * [26] MultiplicativeExpr ::= UnaryExpr
4469: * | MultiplicativeExpr MultiplyOperator UnaryExpr
4470: * | MultiplicativeExpr 'div' UnaryExpr
4471: * | MultiplicativeExpr 'mod' UnaryExpr
4472: * [34] MultiplyOperator ::= '*'
4473: *
4474: * Parse and evaluate an Additive expression, then push the result on the stack
4475: */
4476:
4477: void
4478: xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
4479: xmlXPathEvalUnaryExpr(ctxt);
4480: CHECK_ERROR;
1.30 daniel 4481: SKIP_BLANKS;
1.1 daniel 4482: while ((CUR == '*') ||
4483: ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
4484: ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
4485: int op = -1;
4486:
4487: if (CUR == '*') {
4488: op = 0;
4489: NEXT;
4490: } else if (CUR == 'd') {
4491: op = 1;
4492: SKIP(3);
4493: } else if (CUR == 'm') {
4494: op = 2;
4495: SKIP(3);
4496: }
1.30 daniel 4497: SKIP_BLANKS;
1.1 daniel 4498: xmlXPathEvalUnaryExpr(ctxt);
4499: CHECK_ERROR;
4500: switch (op) {
4501: case 0:
1.6 daniel 4502: xmlXPathMultValues(ctxt);
1.1 daniel 4503: break;
4504: case 1:
1.6 daniel 4505: xmlXPathDivValues(ctxt);
1.1 daniel 4506: break;
4507: case 2:
1.6 daniel 4508: xmlXPathModValues(ctxt);
1.1 daniel 4509: break;
4510: }
1.68 veillard 4511: SKIP_BLANKS;
1.1 daniel 4512: }
4513: }
4514:
4515: /**
4516: * xmlXPathEvalAdditiveExpr:
4517: * @ctxt: the XPath Parser context
4518: *
4519: * [25] AdditiveExpr ::= MultiplicativeExpr
4520: * | AdditiveExpr '+' MultiplicativeExpr
4521: * | AdditiveExpr '-' MultiplicativeExpr
4522: *
4523: * Parse and evaluate an Additive expression, then push the result on the stack
4524: */
4525:
4526: void
4527: xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
4528: xmlXPathEvalMultiplicativeExpr(ctxt);
4529: CHECK_ERROR;
1.30 daniel 4530: SKIP_BLANKS;
1.1 daniel 4531: while ((CUR == '+') || (CUR == '-')) {
4532: int plus;
4533:
4534: if (CUR == '+') plus = 1;
4535: else plus = 0;
4536: NEXT;
1.30 daniel 4537: SKIP_BLANKS;
1.1 daniel 4538: xmlXPathEvalMultiplicativeExpr(ctxt);
4539: CHECK_ERROR;
1.6 daniel 4540: if (plus) xmlXPathAddValues(ctxt);
4541: else xmlXPathSubValues(ctxt);
1.68 veillard 4542: SKIP_BLANKS;
1.1 daniel 4543: }
4544: }
4545:
4546: /**
4547: * xmlXPathEvalRelationalExpr:
4548: * @ctxt: the XPath Parser context
4549: *
4550: * [24] RelationalExpr ::= AdditiveExpr
4551: * | RelationalExpr '<' AdditiveExpr
4552: * | RelationalExpr '>' AdditiveExpr
4553: * | RelationalExpr '<=' AdditiveExpr
4554: * | RelationalExpr '>=' AdditiveExpr
4555: *
1.8 daniel 4556: * A <= B > C is allowed ? Answer from James, yes with
4557: * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
4558: * which is basically what got implemented.
4559: *
4560: * Parse and evaluate a Relational expression, then push the result
4561: * on the stack
1.1 daniel 4562: */
4563:
4564: void
4565: xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
4566: xmlXPathEvalAdditiveExpr(ctxt);
4567: CHECK_ERROR;
1.30 daniel 4568: SKIP_BLANKS;
1.1 daniel 4569: while ((CUR == '<') ||
4570: (CUR == '>') ||
4571: ((CUR == '<') && (NXT(1) == '=')) ||
4572: ((CUR == '>') && (NXT(1) == '='))) {
1.18 daniel 4573: int inf, strict, ret;
1.1 daniel 4574:
4575: if (CUR == '<') inf = 1;
4576: else inf = 0;
4577: if (NXT(1) == '=') strict = 0;
4578: else strict = 1;
4579: NEXT;
4580: if (!strict) NEXT;
1.30 daniel 4581: SKIP_BLANKS;
1.1 daniel 4582: xmlXPathEvalAdditiveExpr(ctxt);
4583: CHECK_ERROR;
1.18 daniel 4584: ret = xmlXPathCompareValues(ctxt, inf, strict);
4585: valuePush(ctxt, xmlXPathNewBoolean(ret));
1.68 veillard 4586: SKIP_BLANKS;
1.1 daniel 4587: }
4588: }
4589:
4590: /**
4591: * xmlXPathEvalEqualityExpr:
4592: * @ctxt: the XPath Parser context
4593: *
4594: * [23] EqualityExpr ::= RelationalExpr
4595: * | EqualityExpr '=' RelationalExpr
4596: * | EqualityExpr '!=' RelationalExpr
4597: *
1.8 daniel 4598: * A != B != C is allowed ? Answer from James, yes with
4599: * (RelationalExpr = RelationalExpr) = RelationalExpr
4600: * (RelationalExpr != RelationalExpr) != RelationalExpr
4601: * which is basically what got implemented.
1.1 daniel 4602: *
4603: * Parse and evaluate an Equality expression, then push the result on the stack
4604: *
4605: */
4606: void
4607: xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
4608: xmlXPathEvalRelationalExpr(ctxt);
4609: CHECK_ERROR;
1.30 daniel 4610: SKIP_BLANKS;
1.1 daniel 4611: while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
1.18 daniel 4612: xmlXPathObjectPtr res;
1.1 daniel 4613: int eq, equal;
4614:
4615: if (CUR == '=') eq = 1;
4616: else eq = 0;
4617: NEXT;
4618: if (!eq) NEXT;
1.30 daniel 4619: SKIP_BLANKS;
1.1 daniel 4620: xmlXPathEvalRelationalExpr(ctxt);
4621: CHECK_ERROR;
1.18 daniel 4622: equal = xmlXPathEqualValues(ctxt);
1.1 daniel 4623: if (eq) res = xmlXPathNewBoolean(equal);
4624: else res = xmlXPathNewBoolean(!equal);
4625: valuePush(ctxt, res);
1.68 veillard 4626: SKIP_BLANKS;
1.1 daniel 4627: }
4628: }
4629:
4630: /**
4631: * xmlXPathEvalAndExpr:
4632: * @ctxt: the XPath Parser context
4633: *
4634: * [22] AndExpr ::= EqualityExpr
4635: * | AndExpr 'and' EqualityExpr
4636: *
4637: * Parse and evaluate an AND expression, then push the result on the stack
4638: *
4639: */
4640: void
4641: xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
4642: xmlXPathEvalEqualityExpr(ctxt);
4643: CHECK_ERROR;
1.30 daniel 4644: SKIP_BLANKS;
1.48 daniel 4645: while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
1.1 daniel 4646: xmlXPathObjectPtr arg1, arg2;
4647:
4648: SKIP(3);
1.30 daniel 4649: SKIP_BLANKS;
1.1 daniel 4650: xmlXPathEvalEqualityExpr(ctxt);
4651: CHECK_ERROR;
4652: arg2 = valuePop(ctxt);
4653: arg1 = valuePop(ctxt);
4654: arg1->boolval &= arg2->boolval;
4655: valuePush(ctxt, arg1);
4656: xmlXPathFreeObject(arg2);
1.68 veillard 4657: SKIP_BLANKS;
1.1 daniel 4658: }
4659: }
4660:
4661: /**
4662: * xmlXPathEvalExpr:
4663: * @ctxt: the XPath Parser context
4664: *
4665: * [14] Expr ::= OrExpr
4666: * [21] OrExpr ::= AndExpr
4667: * | OrExpr 'or' AndExpr
4668: *
4669: * Parse and evaluate an expression, then push the result on the stack
4670: *
4671: */
4672: void
4673: xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
4674: xmlXPathEvalAndExpr(ctxt);
4675: CHECK_ERROR;
1.30 daniel 4676: SKIP_BLANKS;
1.1 daniel 4677: while ((CUR == 'o') && (NXT(1) == 'r')) {
4678: xmlXPathObjectPtr arg1, arg2;
4679:
4680: SKIP(2);
1.30 daniel 4681: SKIP_BLANKS;
1.1 daniel 4682: xmlXPathEvalAndExpr(ctxt);
4683: CHECK_ERROR;
4684: arg2 = valuePop(ctxt);
4685: arg1 = valuePop(ctxt);
4686: arg1->boolval |= arg2->boolval;
4687: valuePush(ctxt, arg1);
4688: xmlXPathFreeObject(arg2);
1.68 veillard 4689: SKIP_BLANKS;
1.1 daniel 4690: }
4691: }
4692:
4693: /**
1.5 daniel 4694: * xmlXPathEvaluatePredicateResult:
4695: * @ctxt: the XPath Parser context
4696: * @res: the Predicate Expression evaluation result
4697: * @index: index of the current node in the current list
4698: *
4699: * Evaluate a predicate result for the current node.
4700: * A PredicateExpr is evaluated by evaluating the Expr and converting
4701: * the result to a boolean. If the result is a number, the result will
4702: * be converted to true if the number is equal to the position of the
4703: * context node in the context node list (as returned by the position
4704: * function) and will be converted to false otherwise; if the result
4705: * is not a number, then the result will be converted as if by a call
4706: * to the boolean function.
4707: */
4708: int
4709: xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
1.57 veillard 4710: xmlXPathObjectPtr res) {
1.5 daniel 4711: if (res == NULL) return(0);
4712: switch (res->type) {
4713: case XPATH_BOOLEAN:
4714: return(res->boolval);
4715: case XPATH_NUMBER:
1.57 veillard 4716: return(res->floatval == ctxt->context->proximityPosition);
1.5 daniel 4717: case XPATH_NODESET:
4718: return(res->nodesetval->nodeNr != 0);
4719: case XPATH_STRING:
4720: return((res->stringval != NULL) &&
4721: (xmlStrlen(res->stringval) != 0));
4722: default:
1.6 daniel 4723: STRANGE
1.5 daniel 4724: }
4725: return(0);
4726: }
4727:
4728: /**
1.1 daniel 4729: * xmlXPathEvalPredicate:
4730: * @ctxt: the XPath Parser context
4731: *
4732: * [8] Predicate ::= '[' PredicateExpr ']'
4733: * [9] PredicateExpr ::= Expr
4734: *
1.57 veillard 4735: * ---------------------
4736: * For each node in the node-set to be filtered, the PredicateExpr is
4737: * evaluated with that node as the context node, with the number of nodes
4738: * in the node-set as the context size, and with the proximity position
4739: * of the node in the node-set with respect to the axis as the context
4740: * position; if PredicateExpr evaluates to true for that node, the node
4741: * is included in the new node-set; otherwise, it is not included.
4742: * ---------------------
4743: *
1.4 daniel 4744: * Parse and evaluate a predicate for all the elements of the
4745: * current node list. Then refine the list by removing all
4746: * nodes where the predicate is false.
1.1 daniel 4747: */
4748: void
4749: xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
1.29 daniel 4750: const xmlChar *cur;
1.57 veillard 4751: xmlXPathObjectPtr res;
1.59 veillard 4752: xmlXPathObjectPtr obj, tmp;
1.5 daniel 4753: xmlNodeSetPtr newset = NULL;
1.57 veillard 4754: xmlNodeSetPtr oldset;
1.4 daniel 4755: int i;
4756:
1.30 daniel 4757: SKIP_BLANKS;
1.1 daniel 4758: if (CUR != '[') {
1.49 daniel 4759: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
1.1 daniel 4760: }
4761: NEXT;
1.30 daniel 4762: SKIP_BLANKS;
1.57 veillard 4763:
4764: /*
4765: * Extract the old set, and then evaluate the result of the
4766: * expression for all the element in the set. use it to grow
4767: * up a new set.
4768: */
1.59 veillard 4769: CHECK_TYPE(XPATH_NODESET);
4770: obj = valuePop(ctxt);
4771: oldset = obj->nodesetval;
1.57 veillard 4772: ctxt->context->node = NULL;
4773:
4774: if ((oldset == NULL) || (oldset->nodeNr == 0)) {
1.4 daniel 4775: xmlXPathEvalExpr(ctxt);
4776: CHECK_ERROR;
1.57 veillard 4777: ctxt->context->contextSize = 0;
4778: ctxt->context->proximityPosition = 0;
1.4 daniel 4779: res = valuePop(ctxt);
1.5 daniel 4780: if (res != NULL)
4781: xmlXPathFreeObject(res);
1.59 veillard 4782: valuePush(ctxt, obj);
1.4 daniel 4783: } else {
1.57 veillard 4784: /*
4785: * Save the expression pointer since we will have to evaluate
4786: * it multiple times. Initialize the new set.
4787: */
1.4 daniel 4788: cur = ctxt->cur;
1.5 daniel 4789: newset = xmlXPathNodeSetCreate(NULL);
1.47 daniel 4790:
1.57 veillard 4791: for (i = 0; i < oldset->nodeNr; i++) {
1.4 daniel 4792: ctxt->cur = cur;
1.47 daniel 4793:
1.57 veillard 4794: /*
4795: * Run the evaluation with a node list made of a single item
4796: * in the nodeset.
4797: */
4798: ctxt->context->node = oldset->nodeTab[i];
1.59 veillard 4799: tmp = xmlXPathNewNodeSet(ctxt->context->node);
4800: valuePush(ctxt, tmp);
1.57 veillard 4801: ctxt->context->contextSize = oldset->nodeNr;
4802: ctxt->context->proximityPosition = i + 1;
1.47 daniel 4803:
1.4 daniel 4804: xmlXPathEvalExpr(ctxt);
4805: CHECK_ERROR;
1.57 veillard 4806:
4807: /*
4808: * The result of the evaluation need to be tested to
4809: * decided whether the filter succeeded or not
4810: */
1.4 daniel 4811: res = valuePop(ctxt);
1.57 veillard 4812: if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
4813: xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
4814: }
1.59 veillard 4815:
4816: /*
4817: * Cleanup
4818: */
1.5 daniel 4819: if (res != NULL)
1.57 veillard 4820: xmlXPathFreeObject(res);
1.59 veillard 4821: if (ctxt->value == tmp) {
4822: res = valuePop(ctxt);
4823: xmlXPathFreeObject(res);
4824: }
1.47 daniel 4825:
1.57 veillard 4826: ctxt->context->node = NULL;
1.4 daniel 4827: }
1.57 veillard 4828:
4829: /*
4830: * The result is used as the new evaluation set.
4831: */
1.59 veillard 4832: xmlXPathFreeObject(obj);
1.5 daniel 4833: ctxt->context->node = NULL;
1.57 veillard 4834: ctxt->context->contextSize = -1;
4835: ctxt->context->proximityPosition = -1;
1.59 veillard 4836: valuePush(ctxt, xmlXPathWrapNodeSet(newset));
1.4 daniel 4837: }
1.1 daniel 4838: if (CUR != ']') {
1.49 daniel 4839: XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
1.1 daniel 4840: }
1.57 veillard 4841:
1.1 daniel 4842: NEXT;
1.30 daniel 4843: SKIP_BLANKS;
1.4 daniel 4844: #ifdef DEBUG_STEP
1.9 daniel 4845: fprintf(xmlXPathDebug, "After predicate : ");
1.66 veillard 4846: xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->value->nodesetval);
1.4 daniel 4847: #endif
1.1 daniel 4848: }
4849:
4850: /**
1.65 veillard 4851: * xmlXPathEvalNodeTest:
1.2 daniel 4852: * @ctxt: the XPath Parser context
1.65 veillard 4853: * @test: pointer to a xmlXPathTestVal
4854: * @type: pointer to a xmlXPathTypeVal
4855: * @prefix: placeholder for a possible name prefix
4856: *
4857: * [7] NodeTest ::= NameTest
4858: * | NodeType '(' ')'
4859: * | 'processing-instruction' '(' Literal ')'
4860: *
4861: * [37] NameTest ::= '*'
4862: * | NCName ':' '*'
4863: * | QName
4864: * [38] NodeType ::= 'comment'
4865: * | 'text'
4866: * | 'processing-instruction'
4867: * | 'node'
1.2 daniel 4868: *
1.65 veillard 4869: * Returns the name found and update @test, @type and @prefix appropriately
1.2 daniel 4870: */
1.65 veillard 4871: xmlChar *
4872: xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
4873: xmlXPathTypeVal *type, xmlChar **prefix, xmlChar *name) {
4874: int blanks;
4875:
4876: if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
4877: STRANGE;
4878: return(NULL);
4879: }
4880: *type = 0;
4881: *test = 0;
4882: *prefix = NULL;
4883: SKIP_BLANKS;
4884:
4885: if ((name == NULL) && (CUR == '*')) {
4886: /*
4887: * All elements
4888: */
4889: NEXT;
4890: *test = NODE_TEST_ALL;
4891: return(NULL);
4892: }
1.2 daniel 4893:
1.65 veillard 4894: if (name == NULL)
4895: name = xmlXPathParseNCName(ctxt);
4896: if (name == NULL) {
4897: XP_ERROR0(XPATH_EXPR_ERROR);
4898: }
1.19 daniel 4899:
1.65 veillard 4900: blanks = IS_BLANK(CUR);
4901: SKIP_BLANKS;
4902: if (CUR == '(') {
4903: NEXT;
4904: /*
4905: * NodeType or PI search
4906: */
4907: if (xmlStrEqual(name, BAD_CAST "comment"))
4908: *type = NODE_TYPE_COMMENT;
4909: else if (xmlStrEqual(name, BAD_CAST "node"))
4910: *type = NODE_TYPE_NODE;
4911: else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
4912: *type = NODE_TYPE_PI;
4913: else if (xmlStrEqual(name, BAD_CAST "text"))
4914: *type = NODE_TYPE_TEXT;
4915: else
4916: XP_ERROR0(XPATH_EXPR_ERROR);
1.19 daniel 4917:
1.65 veillard 4918: *test = NODE_TEST_TYPE;
1.2 daniel 4919:
1.65 veillard 4920: SKIP_BLANKS;
4921: if (*type == NODE_TYPE_PI) {
1.2 daniel 4922: /*
1.65 veillard 4923: * Specific case: search a PI by name.
1.2 daniel 4924: */
1.65 veillard 4925: xmlXPathObjectPtr cur;
4926:
4927: if (name != NULL)
4928: xmlFree(name);
4929:
4930: xmlXPathEvalLiteral(ctxt);
4931: CHECK_ERROR 0;
4932: xmlXPathStringFunction(ctxt, 1);
4933: CHECK_ERROR0;
4934: cur = valuePop(ctxt);
4935: name = xmlStrdup(cur->stringval);
4936: xmlXPathFreeObject(cur);
4937: SKIP_BLANKS;
4938: }
4939: if (CUR != ')')
4940: XP_ERROR0(XPATH_UNCLOSED_ERROR);
4941: NEXT;
4942: return(name);
4943: }
4944: *test = NODE_TEST_NAME;
4945: if ((!blanks) && (CUR == ':')) {
4946: NEXT;
4947:
4948: *prefix = name;
4949:
4950: if (CUR == '*') {
1.3 daniel 4951: /*
1.65 veillard 4952: * All elements
1.3 daniel 4953: */
1.65 veillard 4954: NEXT;
4955: *test = NODE_TEST_ALL;
4956: return(NULL);
4957: }
4958:
4959: name = xmlXPathParseNCName(ctxt);
4960: if (name == NULL) {
4961: XP_ERROR0(XPATH_EXPR_ERROR);
1.3 daniel 4962: }
1.4 daniel 4963: }
1.65 veillard 4964: return(name);
4965: }
4966:
4967: /**
4968: * xmlXPathIsAxisName:
4969: * @name: a preparsed name token
4970: *
4971: * [6] AxisName ::= 'ancestor'
4972: * | 'ancestor-or-self'
4973: * | 'attribute'
4974: * | 'child'
4975: * | 'descendant'
4976: * | 'descendant-or-self'
4977: * | 'following'
4978: * | 'following-sibling'
4979: * | 'namespace'
4980: * | 'parent'
4981: * | 'preceding'
4982: * | 'preceding-sibling'
4983: * | 'self'
4984: *
4985: * Returns the axis or 0
4986: */
4987: xmlXPathAxisVal
4988: xmlXPathIsAxisName(const xmlChar *name) {
4989: xmlXPathAxisVal ret = 0;
4990: switch (name[0]) {
4991: case 'a':
4992: if (xmlStrEqual(name, BAD_CAST "ancestor"))
4993: ret = AXIS_ANCESTOR;
4994: if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
4995: ret = AXIS_ANCESTOR_OR_SELF;
4996: if (xmlStrEqual(name, BAD_CAST "attribute"))
4997: ret = AXIS_ATTRIBUTE;
4998: break;
4999: case 'c':
5000: if (xmlStrEqual(name, BAD_CAST "child"))
5001: ret = AXIS_CHILD;
5002: break;
5003: case 'd':
5004: if (xmlStrEqual(name, BAD_CAST "descendant"))
5005: ret = AXIS_DESCENDANT;
5006: if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
5007: ret = AXIS_DESCENDANT_OR_SELF;
5008: break;
5009: case 'f':
5010: if (xmlStrEqual(name, BAD_CAST "following"))
5011: ret = AXIS_FOLLOWING;
5012: if (xmlStrEqual(name, BAD_CAST "following-sibling"))
5013: ret = AXIS_FOLLOWING_SIBLING;
5014: break;
5015: case 'n':
5016: if (xmlStrEqual(name, BAD_CAST "namespace"))
5017: ret = AXIS_NAMESPACE;
5018: break;
5019: case 'p':
5020: if (xmlStrEqual(name, BAD_CAST "parent"))
5021: ret = AXIS_PARENT;
5022: if (xmlStrEqual(name, BAD_CAST "preceding"))
5023: ret = AXIS_PRECEDING;
5024: if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
5025: ret = AXIS_PRECEDING_SIBLING;
5026: break;
5027: case 's':
5028: if (xmlStrEqual(name, BAD_CAST "self"))
5029: ret = AXIS_SELF;
5030: break;
5031: }
5032: return(ret);
5033: }
5034:
5035: /**
5036: * xmlXPathEvalAxisSpecifier:
5037: * @ctxt: the XPath Parser context
5038: *
5039: *
5040: * Returns the axis found
5041: */
5042: xmlXPathAxisVal
5043: xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
5044: xmlXPathAxisVal ret = AXIS_CHILD;
5045: int blank = 0;
5046: xmlChar *name;
5047:
5048: if (CUR == '@') {
5049: NEXT;
5050: return(AXIS_ATTRIBUTE);
5051: } else {
5052: name = xmlXPathParseNCName(ctxt);
5053: if (name == NULL) {
5054: XP_ERROR0(XPATH_EXPR_ERROR);
5055: }
5056: if (IS_BLANK(CUR))
5057: blank = 1;
5058: SKIP_BLANKS;
5059: if ((CUR == ':') && (NXT(1) == ':')) {
5060: ret = xmlXPathIsAxisName(name);
5061: } else if ((blank) && (CUR == ':'))
5062: XP_ERROR0(XPATH_EXPR_ERROR);
1.2 daniel 5063:
1.65 veillard 5064: xmlFree(name);
5065: }
5066: return(ret);
1.2 daniel 5067: }
5068:
5069: /**
5070: * xmlXPathEvalStep:
5071: * @ctxt: the XPath Parser context
5072: *
1.65 veillard 5073: * [4] Step ::= AxisSpecifier NodeTest Predicate*
5074: * | AbbreviatedStep
1.61 veillard 5075: *
1.65 veillard 5076: * [12] AbbreviatedStep ::= '.' | '..'
5077: *
5078: * [5] AxisSpecifier ::= AxisName '::'
5079: * | AbbreviatedAxisSpecifier
5080: *
5081: * [13] AbbreviatedAxisSpecifier ::= '@'?
1.61 veillard 5082: *
1.62 veillard 5083: * Modified for XPtr range support as:
1.61 veillard 5084: *
5085: * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
5086: * | AbbreviatedStep
1.63 veillard 5087: * | 'range-to' '(' Expr ')' Predicate*
1.2 daniel 5088: *
5089: * Evaluate one step in a Location Path
1.7 daniel 5090: * A location step of . is short for self::node(). This is
5091: * particularly useful in conjunction with //. For example, the
5092: * location path .//para is short for
5093: * self::node()/descendant-or-self::node()/child::para
5094: * and so will select all para descendant elements of the context
5095: * node.
5096: * Similarly, a location step of .. is short for parent::node().
5097: * For example, ../title is short for parent::node()/child::title
5098: * and so will select the title children of the parent of the context
5099: * node.
1.2 daniel 5100: */
5101: void
5102: xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
1.30 daniel 5103: SKIP_BLANKS;
1.2 daniel 5104: if ((CUR == '.') && (NXT(1) == '.')) {
1.7 daniel 5105: SKIP(2);
1.30 daniel 5106: SKIP_BLANKS;
1.59 veillard 5107: xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
1.7 daniel 5108: NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
1.2 daniel 5109: } else if (CUR == '.') {
1.6 daniel 5110: NEXT;
1.30 daniel 5111: SKIP_BLANKS;
1.2 daniel 5112: } else {
1.65 veillard 5113: xmlChar *name = NULL;
5114: xmlChar *prefix = NULL;
5115: xmlXPathTestVal test;
5116: xmlXPathAxisVal axis;
5117: xmlXPathTypeVal type;
5118:
1.67 veillard 5119: /*
5120: * The modification needed for XPointer change to the production
5121: */
1.61 veillard 5122: #ifdef LIBXML_XPTR_ENABLED
1.65 veillard 5123: if (ctxt->context->xptr) {
5124: name = xmlXPathParseNCName(ctxt);
5125: if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
5126: xmlFree(name);
5127: SKIP_BLANKS;
5128: if (CUR != '(') {
5129: XP_ERROR(XPATH_EXPR_ERROR);
5130: }
5131: NEXT;
5132: SKIP_BLANKS;
1.61 veillard 5133:
1.65 veillard 5134: xmlXPtrRangeToFunction(ctxt, 1);
1.61 veillard 5135: CHECK_ERROR;
5136:
1.65 veillard 5137: SKIP_BLANKS;
5138: if (CUR != ')') {
5139: XP_ERROR(XPATH_EXPR_ERROR);
1.61 veillard 5140: }
1.65 veillard 5141: NEXT;
5142: goto eval_predicates;
5143: }
5144: }
5145: #endif
5146: if (name == NULL)
5147: name = xmlXPathParseNCName(ctxt);
5148: if (name != NULL) {
5149: axis = xmlXPathIsAxisName(name);
5150: if (axis != 0) {
5151: SKIP_BLANKS;
5152: if ((CUR == ':') && (NXT(1) == ':')) {
5153: SKIP(2);
5154: xmlFree(name);
5155: name = NULL;
5156: } else {
5157: /* an element name can conflict with an axis one :-\ */
5158: axis = AXIS_CHILD;
1.61 veillard 5159: }
1.65 veillard 5160: } else {
5161: axis = AXIS_CHILD;
1.61 veillard 5162: }
1.65 veillard 5163: } else if (CUR == '@') {
5164: NEXT;
5165: axis = AXIS_ATTRIBUTE;
5166: } else {
5167: axis = AXIS_CHILD;
5168: }
5169:
5170: CHECK_ERROR;
1.61 veillard 5171:
1.65 veillard 5172: name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
5173: if (test == 0)
5174: return;
1.61 veillard 5175:
1.65 veillard 5176: #ifdef DEBUG_STEP
5177: fprintf(xmlXPathDebug, "Basis : computing new set\n");
5178: #endif
5179: xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
5180: #ifdef DEBUG_STEP
5181: fprintf(xmlXPathDebug, "Basis : ");
1.66 veillard 5182: xmlXPathDebugNodeSet(stdout, ctxt->value->nodesetval);
1.61 veillard 5183: #endif
1.65 veillard 5184: if (name != NULL)
5185: xmlFree(name);
5186: if (prefix != NULL)
5187: xmlFree(prefix);
5188:
5189: eval_predicates:
1.30 daniel 5190: SKIP_BLANKS;
1.2 daniel 5191: while (CUR == '[') {
5192: xmlXPathEvalPredicate(ctxt);
5193: }
5194: }
1.4 daniel 5195: #ifdef DEBUG_STEP
1.9 daniel 5196: fprintf(xmlXPathDebug, "Step : ");
1.66 veillard 5197: xmlXPathDebugNodeSet(xmlXPathDebug, ctxt->value->nodesetval);
1.4 daniel 5198: #endif
1.2 daniel 5199: }
5200:
5201: /**
1.1 daniel 5202: * xmlXPathEvalRelativeLocationPath:
5203: * @ctxt: the XPath Parser context
5204: *
5205: * [3] RelativeLocationPath ::= Step
5206: * | RelativeLocationPath '/' Step
5207: * | AbbreviatedRelativeLocationPath
5208: * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
5209: *
5210: */
5211: void
1.2 daniel 5212: xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt) {
1.30 daniel 5213: SKIP_BLANKS;
1.73 veillard 5214: if ((CUR == '/') && (NXT(1) == '/')) {
5215: SKIP(2);
5216: SKIP_BLANKS;
5217: xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
5218: NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
5219: } else if (CUR == '/') {
5220: NEXT;
5221: SKIP_BLANKS;
5222: }
1.2 daniel 5223: xmlXPathEvalStep(ctxt);
1.30 daniel 5224: SKIP_BLANKS;
1.7 daniel 5225: while (CUR == '/') {
5226: if ((CUR == '/') && (NXT(1) == '/')) {
5227: SKIP(2);
1.30 daniel 5228: SKIP_BLANKS;
1.59 veillard 5229: xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
1.7 daniel 5230: NODE_TEST_TYPE, XML_ELEMENT_NODE, NULL, NULL);
5231: xmlXPathEvalStep(ctxt);
5232: } else if (CUR == '/') {
5233: NEXT;
1.30 daniel 5234: SKIP_BLANKS;
1.7 daniel 5235: xmlXPathEvalStep(ctxt);
5236: }
1.30 daniel 5237: SKIP_BLANKS;
1.1 daniel 5238: }
5239: }
5240:
5241: /**
5242: * xmlXPathEvalLocationPath:
5243: * @ctxt: the XPath Parser context
5244: *
5245: * [1] LocationPath ::= RelativeLocationPath
5246: * | AbsoluteLocationPath
5247: * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
5248: * | AbbreviatedAbsoluteLocationPath
5249: * [10] AbbreviatedAbsoluteLocationPath ::=
5250: * '//' RelativeLocationPath
1.7 daniel 5251: *
5252: * // is short for /descendant-or-self::node()/. For example,
5253: * //para is short for /descendant-or-self::node()/child::para and
5254: * so will select any para element in the document (even a para element
5255: * that is a document element will be selected by //para since the
5256: * document element node is a child of the root node); div//para is
5257: * short for div/descendant-or-self::node()/child::para and so will
5258: * select all para descendants of div children.
1.1 daniel 5259: */
5260: void
5261: xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
1.30 daniel 5262: SKIP_BLANKS;
5263: if (CUR != '/') {
5264: xmlXPathEvalRelativeLocationPath(ctxt);
5265: } else {
5266: while (CUR == '/') {
5267: if ((CUR == '/') && (NXT(1) == '/')) {
5268: SKIP(2);
5269: SKIP_BLANKS;
1.59 veillard 5270: xmlXPathNodeCollectAndTest(ctxt,
1.30 daniel 5271: AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
5272: XML_ELEMENT_NODE, NULL, NULL);
5273: xmlXPathEvalRelativeLocationPath(ctxt);
5274: } else if (CUR == '/') {
5275: NEXT;
5276: SKIP_BLANKS;
1.7 daniel 5277: xmlXPathRoot(ctxt);
1.30 daniel 5278: if (CUR != 0)
5279: xmlXPathEvalRelativeLocationPath(ctxt);
5280: }
1.7 daniel 5281: }
1.1 daniel 5282: }
5283: }
5284:
5285: /**
5286: * xmlXPathEval:
5287: * @str: the XPath expression
1.59 veillard 5288: * @ctx: the XPath context
1.1 daniel 5289: *
1.9 daniel 5290: * Evaluate the XPath Location Path in the given context.
1.1 daniel 5291: *
5292: * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
5293: * the caller has to free the object.
5294: */
5295: xmlXPathObjectPtr
1.59 veillard 5296: xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
5297: xmlXPathParserContextPtr ctxt;
1.19 daniel 5298: xmlXPathObjectPtr res = NULL, tmp;
1.68 veillard 5299: xmlXPathObjectPtr init = NULL;
1.35 daniel 5300: int stack = 0;
1.2 daniel 5301:
1.10 daniel 5302: xmlXPathInit();
5303:
1.59 veillard 5304: CHECK_CONTEXT(ctx)
1.1 daniel 5305:
1.9 daniel 5306: if (xmlXPathDebug == NULL)
5307: xmlXPathDebug = stderr;
1.59 veillard 5308: ctxt = xmlXPathNewParserContext(str, ctx);
1.68 veillard 5309: if (ctx->node != NULL) {
5310: init = xmlXPathNewNodeSet(ctx->node);
5311: valuePush(ctxt, init);
5312: }
1.35 daniel 5313: if (str[0] == '/')
1.68 veillard 5314: xmlXPathRoot(ctxt);
1.65 veillard 5315: xmlXPathEvalExpr(ctxt);
1.59 veillard 5316:
5317: if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NODESET)) {
1.63 veillard 5318: fprintf(xmlXPathDebug,
5319: "xmlXPathEval: evaluation failed to return a node set\n");
5320: } else {
5321: res = valuePop(ctxt);
5322: }
5323:
5324: do {
5325: tmp = valuePop(ctxt);
5326: if (tmp != NULL) {
5327: xmlXPathFreeObject(tmp);
1.68 veillard 5328: if (tmp != init)
5329: stack++;
1.63 veillard 5330: }
5331: } while (tmp != NULL);
5332: if (stack != 0) {
5333: fprintf(xmlXPathDebug, "xmlXPathEval: %d object left on the stack\n",
1.35 daniel 5334: stack);
5335: }
1.59 veillard 5336: if (ctxt->error != XPATH_EXPRESSION_OK) {
5337: xmlXPathFreeObject(res);
5338: res = NULL;
5339: }
1.48 daniel 5340:
1.59 veillard 5341: xmlXPathFreeParserContext(ctxt);
1.9 daniel 5342: return(res);
5343: }
5344:
5345: /**
5346: * xmlXPathEvalExpression:
5347: * @str: the XPath expression
5348: * @ctxt: the XPath context
5349: *
5350: * Evaluate the XPath expression in the given context.
5351: *
1.19 daniel 5352: * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
1.9 daniel 5353: * the caller has to free the object.
5354: */
5355: xmlXPathObjectPtr
1.29 daniel 5356: xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
1.9 daniel 5357: xmlXPathParserContextPtr pctxt;
5358: xmlXPathObjectPtr res, tmp;
1.35 daniel 5359: int stack = 0;
1.10 daniel 5360:
5361: xmlXPathInit();
1.9 daniel 5362:
1.59 veillard 5363: CHECK_CONTEXT(ctxt)
1.9 daniel 5364:
5365: if (xmlXPathDebug == NULL)
5366: xmlXPathDebug = stderr;
5367: pctxt = xmlXPathNewParserContext(str, ctxt);
5368: xmlXPathEvalExpr(pctxt);
5369:
5370: res = valuePop(pctxt);
5371: do {
5372: tmp = valuePop(pctxt);
1.35 daniel 5373: if (tmp != NULL) {
1.11 veillard 5374: xmlXPathFreeObject(tmp);
1.35 daniel 5375: stack++;
5376: }
1.9 daniel 5377: } while (tmp != NULL);
1.35 daniel 5378: if (stack != 0) {
1.64 veillard 5379: fprintf(xmlXPathDebug, "xmlXPathEvalExpression: %d object left on the stack\n",
1.35 daniel 5380: stack);
5381: }
1.1 daniel 5382: xmlXPathFreeParserContext(pctxt);
5383: return(res);
5384: }
5385:
1.45 daniel 5386: #endif /* LIBXML_XPATH_ENABLED */
Webmaster