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