xpath.c revision 088bf1163080cbbb72ba9d4a52ab08cc7c8ff6c7
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.com 14 * 15 * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath 16 * for VMS 17 */ 18 19#define IN_LIBXML 20#include "libxml.h" 21#ifdef LIBXML_XPATH_ENABLED 22 23#include <string.h> 24 25#ifdef HAVE_SYS_TYPES_H 26#include <sys/types.h> 27#endif 28#ifdef HAVE_MATH_H 29#include <math.h> 30#endif 31#ifdef HAVE_FLOAT_H 32#include <float.h> 33#endif 34#ifdef HAVE_CTYPE_H 35#include <ctype.h> 36#endif 37#ifdef HAVE_SIGNAL_H 38#include <signal.h> 39#endif 40 41#include <libxml/xmlmemory.h> 42#include <libxml/tree.h> 43#include <libxml/valid.h> 44#include <libxml/xpath.h> 45#include <libxml/xpathInternals.h> 46#include <libxml/parserInternals.h> 47#include <libxml/hash.h> 48#ifdef LIBXML_XPTR_ENABLED 49#include <libxml/xpointer.h> 50#endif 51#ifdef LIBXML_DEBUG_ENABLED 52#include <libxml/debugXML.h> 53#endif 54#include <libxml/xmlerror.h> 55#include <libxml/threads.h> 56#include <libxml/globals.h> 57 58/* #define DEBUG */ 59/* #define DEBUG_STEP */ 60/* #define DEBUG_STEP_NTH */ 61/* #define DEBUG_EXPR */ 62/* #define DEBUG_EVAL_COUNTS */ 63 64double xmlXPathDivideBy(double f, double fzero); 65 66static xmlNs xmlXPathXMLNamespaceStruct = { 67 NULL, 68 XML_NAMESPACE_DECL, 69 XML_XML_NAMESPACE, 70 BAD_CAST "xml" 71}; 72static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct; 73#ifndef LIBXML_THREAD_ENABLED 74/* 75 * Optimizer is disabled only when threaded apps are detected while 76 * the library ain't compiled for thread safety. 77 */ 78static int xmlXPathDisableOptimizer = 0; 79#endif 80 81/************************************************************************ 82 * * 83 * Floating point stuff * 84 * * 85 ************************************************************************/ 86 87#ifndef TRIO_REPLACE_STDIO 88#define TRIO_PUBLIC static 89#endif 90#include "trionan.c" 91 92/* 93 * The lack of portability of this section of the libc is annoying ! 94 */ 95double xmlXPathNAN = 0; 96double xmlXPathPINF = 1; 97double xmlXPathNINF = -1; 98double xmlXPathNZERO = 0; 99static int xmlXPathInitialized = 0; 100 101/** 102 * xmlXPathInit: 103 * 104 * Initialize the XPath environment 105 */ 106void 107xmlXPathInit(void) { 108 if (xmlXPathInitialized) return; 109 110 xmlXPathPINF = trio_pinf(); 111 xmlXPathNINF = trio_ninf(); 112 xmlXPathNAN = trio_nan(); 113 xmlXPathNZERO = trio_nzero(); 114 115 xmlXPathInitialized = 1; 116} 117 118/** 119 * xmlXPathIsNaN: 120 * @val: a double value 121 * 122 * Provides a portable isnan() function to detect whether a double 123 * is a NotaNumber. Based on trio code 124 * http://sourceforge.net/projects/ctrio/ 125 * 126 * Returns 1 if the value is a NaN, 0 otherwise 127 */ 128int 129xmlXPathIsNaN(double val) { 130 return(trio_isnan(val)); 131} 132 133/** 134 * xmlXPathIsInf: 135 * @val: a double value 136 * 137 * Provides a portable isinf() function to detect whether a double 138 * is a +Infinite or -Infinite. Based on trio code 139 * http://sourceforge.net/projects/ctrio/ 140 * 141 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise 142 */ 143int 144xmlXPathIsInf(double val) { 145 return(trio_isinf(val)); 146} 147 148/** 149 * xmlXPathGetSign: 150 * @val: a double value 151 * 152 * Provides a portable function to detect the sign of a double 153 * Modified from trio code 154 * http://sourceforge.net/projects/ctrio/ 155 * 156 * Returns 1 if the value is Negative, 0 if positive 157 */ 158static int 159xmlXPathGetSign(double val) { 160 return(trio_signbit(val)); 161} 162 163 164/************************************************************************ 165 * * 166 * Parser Types * 167 * * 168 ************************************************************************/ 169 170/* 171 * Types are private: 172 */ 173 174typedef enum { 175 XPATH_OP_END=0, 176 XPATH_OP_AND, 177 XPATH_OP_OR, 178 XPATH_OP_EQUAL, 179 XPATH_OP_CMP, 180 XPATH_OP_PLUS, 181 XPATH_OP_MULT, 182 XPATH_OP_UNION, 183 XPATH_OP_ROOT, 184 XPATH_OP_NODE, 185 XPATH_OP_RESET, 186 XPATH_OP_COLLECT, 187 XPATH_OP_VALUE, 188 XPATH_OP_VARIABLE, 189 XPATH_OP_FUNCTION, 190 XPATH_OP_ARG, 191 XPATH_OP_PREDICATE, 192 XPATH_OP_FILTER, 193 XPATH_OP_SORT 194#ifdef LIBXML_XPTR_ENABLED 195 ,XPATH_OP_RANGETO 196#endif 197} xmlXPathOp; 198 199typedef enum { 200 AXIS_ANCESTOR = 1, 201 AXIS_ANCESTOR_OR_SELF, 202 AXIS_ATTRIBUTE, 203 AXIS_CHILD, 204 AXIS_DESCENDANT, 205 AXIS_DESCENDANT_OR_SELF, 206 AXIS_FOLLOWING, 207 AXIS_FOLLOWING_SIBLING, 208 AXIS_NAMESPACE, 209 AXIS_PARENT, 210 AXIS_PRECEDING, 211 AXIS_PRECEDING_SIBLING, 212 AXIS_SELF 213} xmlXPathAxisVal; 214 215typedef enum { 216 NODE_TEST_NONE = 0, 217 NODE_TEST_TYPE = 1, 218 NODE_TEST_PI = 2, 219 NODE_TEST_ALL = 3, 220 NODE_TEST_NS = 4, 221 NODE_TEST_NAME = 5 222} xmlXPathTestVal; 223 224typedef enum { 225 NODE_TYPE_NODE = 0, 226 NODE_TYPE_COMMENT = XML_COMMENT_NODE, 227 NODE_TYPE_TEXT = XML_TEXT_NODE, 228 NODE_TYPE_PI = XML_PI_NODE 229} xmlXPathTypeVal; 230 231 232typedef struct _xmlXPathStepOp xmlXPathStepOp; 233typedef xmlXPathStepOp *xmlXPathStepOpPtr; 234struct _xmlXPathStepOp { 235 xmlXPathOp op; 236 int ch1; 237 int ch2; 238 int value; 239 int value2; 240 int value3; 241 void *value4; 242 void *value5; 243 void *cache; 244 void *cacheURI; 245}; 246 247struct _xmlXPathCompExpr { 248 int nbStep; 249 int maxStep; 250 xmlXPathStepOp *steps; /* ops for computation */ 251 int last; 252#ifdef DEBUG_EVAL_COUNTS 253 int nb; 254 xmlChar *string; 255#endif 256}; 257 258/************************************************************************ 259 * * 260 * Parser Type functions * 261 * * 262 ************************************************************************/ 263 264/** 265 * xmlXPathNewCompExpr: 266 * 267 * Create a new Xpath component 268 * 269 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error 270 */ 271static xmlXPathCompExprPtr 272xmlXPathNewCompExpr(void) { 273 xmlXPathCompExprPtr cur; 274 275 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr)); 276 if (cur == NULL) { 277 xmlGenericError(xmlGenericErrorContext, 278 "xmlXPathNewCompExpr : malloc failed\n"); 279 return(NULL); 280 } 281 memset(cur, 0, sizeof(xmlXPathCompExpr)); 282 cur->maxStep = 10; 283 cur->nbStep = 0; 284 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep * 285 sizeof(xmlXPathStepOp)); 286 if (cur->steps == NULL) { 287 xmlGenericError(xmlGenericErrorContext, 288 "xmlXPathNewCompExpr : malloc failed\n"); 289 xmlFree(cur); 290 return(NULL); 291 } 292 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp)); 293 cur->last = -1; 294#ifdef DEBUG_EVAL_COUNTS 295 cur->nb = 0; 296#endif 297 return(cur); 298} 299 300/** 301 * xmlXPathFreeCompExpr: 302 * @comp: an XPATH comp 303 * 304 * Free up the memory allocated by @comp 305 */ 306void 307xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp) 308{ 309 xmlXPathStepOpPtr op; 310 int i; 311 312 if (comp == NULL) 313 return; 314 for (i = 0; i < comp->nbStep; i++) { 315 op = &comp->steps[i]; 316 if (op->value4 != NULL) { 317 if (op->op == XPATH_OP_VALUE) 318 xmlXPathFreeObject(op->value4); 319 else 320 xmlFree(op->value4); 321 } 322 if (op->value5 != NULL) 323 xmlFree(op->value5); 324 } 325 if (comp->steps != NULL) { 326 xmlFree(comp->steps); 327 } 328#ifdef DEBUG_EVAL_COUNTS 329 if (comp->string != NULL) { 330 xmlFree(comp->string); 331 } 332#endif 333 334 xmlFree(comp); 335} 336 337/** 338 * xmlXPathCompExprAdd: 339 * @comp: the compiled expression 340 * @ch1: first child index 341 * @ch2: second child index 342 * @op: an op 343 * @value: the first int value 344 * @value2: the second int value 345 * @value3: the third int value 346 * @value4: the first string value 347 * @value5: the second string value 348 * 349 * Add an step to an XPath Compiled Expression 350 * 351 * Returns -1 in case of failure, the index otherwise 352 */ 353static int 354xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2, 355 xmlXPathOp op, int value, 356 int value2, int value3, void *value4, void *value5) { 357 if (comp->nbStep >= comp->maxStep) { 358 xmlXPathStepOp *real; 359 360 comp->maxStep *= 2; 361 real = (xmlXPathStepOp *) xmlRealloc(comp->steps, 362 comp->maxStep * sizeof(xmlXPathStepOp)); 363 if (real == NULL) { 364 comp->maxStep /= 2; 365 xmlGenericError(xmlGenericErrorContext, 366 "xmlXPathCompExprAdd : realloc failed\n"); 367 return(-1); 368 } 369 comp->steps = real; 370 } 371 comp->last = comp->nbStep; 372 comp->steps[comp->nbStep].ch1 = ch1; 373 comp->steps[comp->nbStep].ch2 = ch2; 374 comp->steps[comp->nbStep].op = op; 375 comp->steps[comp->nbStep].value = value; 376 comp->steps[comp->nbStep].value2 = value2; 377 comp->steps[comp->nbStep].value3 = value3; 378 comp->steps[comp->nbStep].value4 = value4; 379 comp->steps[comp->nbStep].value5 = value5; 380 comp->steps[comp->nbStep].cache = NULL; 381 return(comp->nbStep++); 382} 383 384/** 385 * xmlXPathCompSwap: 386 * @comp: the compiled expression 387 * @op: operation index 388 * 389 * Swaps 2 operations in the compiled expression 390 */ 391static void 392xmlXPathCompSwap(xmlXPathStepOpPtr op) { 393 int tmp; 394 395#ifndef LIBXML_THREAD_ENABLED 396 /* 397 * Since this manipulates possibly shared variables, this is 398 * disable if one detects that the library is used in a multithreaded 399 * application 400 */ 401 if (xmlXPathDisableOptimizer) 402 return; 403#endif 404 405 tmp = op->ch1; 406 op->ch1 = op->ch2; 407 op->ch2 = tmp; 408} 409 410#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \ 411 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \ 412 (op), (val), (val2), (val3), (val4), (val5)) 413#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \ 414 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \ 415 (op), (val), (val2), (val3), (val4), (val5)) 416 417#define PUSH_LEAVE_EXPR(op, val, val2) \ 418xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL) 419 420#define PUSH_UNARY_EXPR(op, ch, val, val2) \ 421xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL) 422 423#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \ 424xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL) 425 426/************************************************************************ 427 * * 428 * Debugging related functions * 429 * * 430 ************************************************************************/ 431 432#define TODO \ 433 xmlGenericError(xmlGenericErrorContext, \ 434 "Unimplemented block at %s:%d\n", \ 435 __FILE__, __LINE__); 436 437#define STRANGE \ 438 xmlGenericError(xmlGenericErrorContext, \ 439 "Internal error at %s:%d\n", \ 440 __FILE__, __LINE__); 441 442#ifdef LIBXML_DEBUG_ENABLED 443static void 444xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) { 445 int i; 446 char shift[100]; 447 448 for (i = 0;((i < depth) && (i < 25));i++) 449 shift[2 * i] = shift[2 * i + 1] = ' '; 450 shift[2 * i] = shift[2 * i + 1] = 0; 451 if (cur == NULL) { 452 fprintf(output, shift); 453 fprintf(output, "Node is NULL !\n"); 454 return; 455 456 } 457 458 if ((cur->type == XML_DOCUMENT_NODE) || 459 (cur->type == XML_HTML_DOCUMENT_NODE)) { 460 fprintf(output, shift); 461 fprintf(output, " /\n"); 462 } else if (cur->type == XML_ATTRIBUTE_NODE) 463 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth); 464 else 465 xmlDebugDumpOneNode(output, cur, depth); 466} 467static void 468xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) { 469 xmlNodePtr tmp; 470 int i; 471 char shift[100]; 472 473 for (i = 0;((i < depth) && (i < 25));i++) 474 shift[2 * i] = shift[2 * i + 1] = ' '; 475 shift[2 * i] = shift[2 * i + 1] = 0; 476 if (cur == NULL) { 477 fprintf(output, shift); 478 fprintf(output, "Node is NULL !\n"); 479 return; 480 481 } 482 483 while (cur != NULL) { 484 tmp = cur; 485 cur = cur->next; 486 xmlDebugDumpOneNode(output, tmp, depth); 487 } 488} 489 490static void 491xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) { 492 int i; 493 char shift[100]; 494 495 for (i = 0;((i < depth) && (i < 25));i++) 496 shift[2 * i] = shift[2 * i + 1] = ' '; 497 shift[2 * i] = shift[2 * i + 1] = 0; 498 499 if (cur == NULL) { 500 fprintf(output, shift); 501 fprintf(output, "NodeSet is NULL !\n"); 502 return; 503 504 } 505 506 if (cur != NULL) { 507 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr); 508 for (i = 0;i < cur->nodeNr;i++) { 509 fprintf(output, shift); 510 fprintf(output, "%d", i + 1); 511 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1); 512 } 513 } 514} 515 516static void 517xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) { 518 int i; 519 char shift[100]; 520 521 for (i = 0;((i < depth) && (i < 25));i++) 522 shift[2 * i] = shift[2 * i + 1] = ' '; 523 shift[2 * i] = shift[2 * i + 1] = 0; 524 525 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) { 526 fprintf(output, shift); 527 fprintf(output, "Value Tree is NULL !\n"); 528 return; 529 530 } 531 532 fprintf(output, shift); 533 fprintf(output, "%d", i + 1); 534 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1); 535} 536#if defined(LIBXML_XPTR_ENABLED) 537static void 538xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) { 539 int i; 540 char shift[100]; 541 542 for (i = 0;((i < depth) && (i < 25));i++) 543 shift[2 * i] = shift[2 * i + 1] = ' '; 544 shift[2 * i] = shift[2 * i + 1] = 0; 545 546 if (cur == NULL) { 547 fprintf(output, shift); 548 fprintf(output, "LocationSet is NULL !\n"); 549 return; 550 551 } 552 553 for (i = 0;i < cur->locNr;i++) { 554 fprintf(output, shift); 555 fprintf(output, "%d : ", i + 1); 556 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1); 557 } 558} 559#endif /* LIBXML_XPTR_ENABLED */ 560 561/** 562 * xmlXPathDebugDumpObject: 563 * @output: the FILE * to dump the output 564 * @cur: the object to inspect 565 * @depth: indentation level 566 * 567 * Dump the content of the object for debugging purposes 568 */ 569void 570xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) { 571 int i; 572 char shift[100]; 573 574 for (i = 0;((i < depth) && (i < 25));i++) 575 shift[2 * i] = shift[2 * i + 1] = ' '; 576 shift[2 * i] = shift[2 * i + 1] = 0; 577 578 fprintf(output, shift); 579 580 if (cur == NULL) { 581 fprintf(output, "Object is empty (NULL)\n"); 582 return; 583 } 584 switch(cur->type) { 585 case XPATH_UNDEFINED: 586 fprintf(output, "Object is uninitialized\n"); 587 break; 588 case XPATH_NODESET: 589 fprintf(output, "Object is a Node Set :\n"); 590 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth); 591 break; 592 case XPATH_XSLT_TREE: 593 fprintf(output, "Object is an XSLT value tree :\n"); 594 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth); 595 break; 596 case XPATH_BOOLEAN: 597 fprintf(output, "Object is a Boolean : "); 598 if (cur->boolval) fprintf(output, "true\n"); 599 else fprintf(output, "false\n"); 600 break; 601 case XPATH_NUMBER: 602 switch (xmlXPathIsInf(cur->floatval)) { 603 case 1: 604 fprintf(output, "Object is a number : Infinity\n"); 605 break; 606 case -1: 607 fprintf(output, "Object is a number : -Infinity\n"); 608 break; 609 default: 610 if (xmlXPathIsNaN(cur->floatval)) { 611 fprintf(output, "Object is a number : NaN\n"); 612 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) { 613 fprintf(output, "Object is a number : 0\n"); 614 } else { 615 fprintf(output, "Object is a number : %0g\n", cur->floatval); 616 } 617 } 618 break; 619 case XPATH_STRING: 620 fprintf(output, "Object is a string : "); 621 xmlDebugDumpString(output, cur->stringval); 622 fprintf(output, "\n"); 623 break; 624 case XPATH_POINT: 625 fprintf(output, "Object is a point : index %d in node", cur->index); 626 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1); 627 fprintf(output, "\n"); 628 break; 629 case XPATH_RANGE: 630 if ((cur->user2 == NULL) || 631 ((cur->user2 == cur->user) && (cur->index == cur->index2))) { 632 fprintf(output, "Object is a collapsed range :\n"); 633 fprintf(output, shift); 634 if (cur->index >= 0) 635 fprintf(output, "index %d in ", cur->index); 636 fprintf(output, "node\n"); 637 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 638 depth + 1); 639 } else { 640 fprintf(output, "Object is a range :\n"); 641 fprintf(output, shift); 642 fprintf(output, "From "); 643 if (cur->index >= 0) 644 fprintf(output, "index %d in ", cur->index); 645 fprintf(output, "node\n"); 646 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, 647 depth + 1); 648 fprintf(output, shift); 649 fprintf(output, "To "); 650 if (cur->index2 >= 0) 651 fprintf(output, "index %d in ", cur->index2); 652 fprintf(output, "node\n"); 653 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2, 654 depth + 1); 655 fprintf(output, "\n"); 656 } 657 break; 658 case XPATH_LOCATIONSET: 659#if defined(LIBXML_XPTR_ENABLED) 660 fprintf(output, "Object is a Location Set:\n"); 661 xmlXPathDebugDumpLocationSet(output, 662 (xmlLocationSetPtr) cur->user, depth); 663#endif 664 break; 665 case XPATH_USERS: 666 fprintf(output, "Object is user defined\n"); 667 break; 668 } 669} 670 671static void 672xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp, 673 xmlXPathStepOpPtr op, int depth) { 674 int i; 675 char shift[100]; 676 677 for (i = 0;((i < depth) && (i < 25));i++) 678 shift[2 * i] = shift[2 * i + 1] = ' '; 679 shift[2 * i] = shift[2 * i + 1] = 0; 680 681 fprintf(output, shift); 682 if (op == NULL) { 683 fprintf(output, "Step is NULL\n"); 684 return; 685 } 686 switch (op->op) { 687 case XPATH_OP_END: 688 fprintf(output, "END"); break; 689 case XPATH_OP_AND: 690 fprintf(output, "AND"); break; 691 case XPATH_OP_OR: 692 fprintf(output, "OR"); break; 693 case XPATH_OP_EQUAL: 694 if (op->value) 695 fprintf(output, "EQUAL ="); 696 else 697 fprintf(output, "EQUAL !="); 698 break; 699 case XPATH_OP_CMP: 700 if (op->value) 701 fprintf(output, "CMP <"); 702 else 703 fprintf(output, "CMP >"); 704 if (!op->value2) 705 fprintf(output, "="); 706 break; 707 case XPATH_OP_PLUS: 708 if (op->value == 0) 709 fprintf(output, "PLUS -"); 710 else if (op->value == 1) 711 fprintf(output, "PLUS +"); 712 else if (op->value == 2) 713 fprintf(output, "PLUS unary -"); 714 else if (op->value == 3) 715 fprintf(output, "PLUS unary - -"); 716 break; 717 case XPATH_OP_MULT: 718 if (op->value == 0) 719 fprintf(output, "MULT *"); 720 else if (op->value == 1) 721 fprintf(output, "MULT div"); 722 else 723 fprintf(output, "MULT mod"); 724 break; 725 case XPATH_OP_UNION: 726 fprintf(output, "UNION"); break; 727 case XPATH_OP_ROOT: 728 fprintf(output, "ROOT"); break; 729 case XPATH_OP_NODE: 730 fprintf(output, "NODE"); break; 731 case XPATH_OP_RESET: 732 fprintf(output, "RESET"); break; 733 case XPATH_OP_SORT: 734 fprintf(output, "SORT"); break; 735 case XPATH_OP_COLLECT: { 736 xmlXPathAxisVal axis = op->value; 737 xmlXPathTestVal test = op->value2; 738 xmlXPathTypeVal type = op->value3; 739 const xmlChar *prefix = op->value4; 740 const xmlChar *name = op->value5; 741 742 fprintf(output, "COLLECT "); 743 switch (axis) { 744 case AXIS_ANCESTOR: 745 fprintf(output, " 'ancestors' "); break; 746 case AXIS_ANCESTOR_OR_SELF: 747 fprintf(output, " 'ancestors-or-self' "); break; 748 case AXIS_ATTRIBUTE: 749 fprintf(output, " 'attributes' "); break; 750 case AXIS_CHILD: 751 fprintf(output, " 'child' "); break; 752 case AXIS_DESCENDANT: 753 fprintf(output, " 'descendant' "); break; 754 case AXIS_DESCENDANT_OR_SELF: 755 fprintf(output, " 'descendant-or-self' "); break; 756 case AXIS_FOLLOWING: 757 fprintf(output, " 'following' "); break; 758 case AXIS_FOLLOWING_SIBLING: 759 fprintf(output, " 'following-siblings' "); break; 760 case AXIS_NAMESPACE: 761 fprintf(output, " 'namespace' "); break; 762 case AXIS_PARENT: 763 fprintf(output, " 'parent' "); break; 764 case AXIS_PRECEDING: 765 fprintf(output, " 'preceding' "); break; 766 case AXIS_PRECEDING_SIBLING: 767 fprintf(output, " 'preceding-sibling' "); break; 768 case AXIS_SELF: 769 fprintf(output, " 'self' "); break; 770 } 771 switch (test) { 772 case NODE_TEST_NONE: 773 fprintf(output, "'none' "); break; 774 case NODE_TEST_TYPE: 775 fprintf(output, "'type' "); break; 776 case NODE_TEST_PI: 777 fprintf(output, "'PI' "); break; 778 case NODE_TEST_ALL: 779 fprintf(output, "'all' "); break; 780 case NODE_TEST_NS: 781 fprintf(output, "'namespace' "); break; 782 case NODE_TEST_NAME: 783 fprintf(output, "'name' "); break; 784 } 785 switch (type) { 786 case NODE_TYPE_NODE: 787 fprintf(output, "'node' "); break; 788 case NODE_TYPE_COMMENT: 789 fprintf(output, "'comment' "); break; 790 case NODE_TYPE_TEXT: 791 fprintf(output, "'text' "); break; 792 case NODE_TYPE_PI: 793 fprintf(output, "'PI' "); break; 794 } 795 if (prefix != NULL) 796 fprintf(output, "%s:", prefix); 797 if (name != NULL) 798 fprintf(output, "%s", name); 799 break; 800 801 } 802 case XPATH_OP_VALUE: { 803 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4; 804 805 fprintf(output, "ELEM "); 806 xmlXPathDebugDumpObject(output, object, 0); 807 goto finish; 808 } 809 case XPATH_OP_VARIABLE: { 810 const xmlChar *prefix = op->value5; 811 const xmlChar *name = op->value4; 812 813 if (prefix != NULL) 814 fprintf(output, "VARIABLE %s:%s", prefix, name); 815 else 816 fprintf(output, "VARIABLE %s", name); 817 break; 818 } 819 case XPATH_OP_FUNCTION: { 820 int nbargs = op->value; 821 const xmlChar *prefix = op->value5; 822 const xmlChar *name = op->value4; 823 824 if (prefix != NULL) 825 fprintf(output, "FUNCTION %s:%s(%d args)", 826 prefix, name, nbargs); 827 else 828 fprintf(output, "FUNCTION %s(%d args)", name, nbargs); 829 break; 830 } 831 case XPATH_OP_ARG: fprintf(output, "ARG"); break; 832 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break; 833 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break; 834#ifdef LIBXML_XPTR_ENABLED 835 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break; 836#endif 837 default: 838 fprintf(output, "UNKNOWN %d\n", op->op); return; 839 } 840 fprintf(output, "\n"); 841finish: 842 if (op->ch1 >= 0) 843 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1); 844 if (op->ch2 >= 0) 845 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1); 846} 847 848/** 849 * xmlXPathDebugDumpCompExpr: 850 * @output: the FILE * for the output 851 * @comp: the precompiled XPath expression 852 * @depth: the indentation level. 853 * 854 * Dumps the tree of the compiled XPath expression. 855 */ 856void 857xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp, 858 int depth) { 859 int i; 860 char shift[100]; 861 862 for (i = 0;((i < depth) && (i < 25));i++) 863 shift[2 * i] = shift[2 * i + 1] = ' '; 864 shift[2 * i] = shift[2 * i + 1] = 0; 865 866 fprintf(output, shift); 867 868 if (comp == NULL) { 869 fprintf(output, "Compiled Expression is NULL\n"); 870 return; 871 } 872 fprintf(output, "Compiled Expression : %d elements\n", 873 comp->nbStep); 874 i = comp->last; 875 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1); 876} 877#endif /* LIBXML_DEBUG_ENABLED */ 878 879/************************************************************************ 880 * * 881 * Parser stacks related functions and macros * 882 * * 883 ************************************************************************/ 884 885/* 886 * Generic function for accessing stacks in the Parser Context 887 */ 888 889#define PUSH_AND_POP(type, name) \ 890extern int name##Push(xmlXPathParserContextPtr ctxt, type value) { \ 891 if (ctxt->name##Nr >= ctxt->name##Max) { \ 892 ctxt->name##Max *= 2; \ 893 ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab, \ 894 ctxt->name##Max * sizeof(ctxt->name##Tab[0])); \ 895 if (ctxt->name##Tab == NULL) { \ 896 xmlGenericError(xmlGenericErrorContext, \ 897 "realloc failed !\n"); \ 898 return(0); \ 899 } \ 900 } \ 901 ctxt->name##Tab[ctxt->name##Nr] = value; \ 902 ctxt->name = value; \ 903 return(ctxt->name##Nr++); \ 904} \ 905extern type name##Pop(xmlXPathParserContextPtr ctxt) { \ 906 type ret; \ 907 if (ctxt->name##Nr <= 0) return(0); \ 908 ctxt->name##Nr--; \ 909 if (ctxt->name##Nr > 0) \ 910 ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1]; \ 911 else \ 912 ctxt->name = NULL; \ 913 ret = ctxt->name##Tab[ctxt->name##Nr]; \ 914 ctxt->name##Tab[ctxt->name##Nr] = 0; \ 915 return(ret); \ 916} \ 917 918/** 919 * valuePop: 920 * @ctxt: an XPath evaluation context 921 * 922 * Pops the top XPath object from the value stack 923 * 924 * Returns the XPath object just removed 925 */ 926/** 927 * valuePush: 928 * @ctxt: an XPath evaluation context 929 * @value: the XPath object 930 * 931 * Pushes a new XPath object on top of the value stack 932 * 933 * returns the number of items on the value stack 934 */ 935PUSH_AND_POP(xmlXPathObjectPtr, value) 936 937/** 938 * xmlXPathPopBoolean: 939 * @ctxt: an XPath parser context 940 * 941 * Pops a boolean from the stack, handling conversion if needed. 942 * Check error with #xmlXPathCheckError. 943 * 944 * Returns the boolean 945 */ 946int 947xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) { 948 xmlXPathObjectPtr obj; 949 int ret; 950 951 obj = valuePop(ctxt); 952 if (obj == NULL) { 953 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 954 return(0); 955 } 956 ret = xmlXPathCastToBoolean(obj); 957 xmlXPathFreeObject(obj); 958 return(ret); 959} 960 961/** 962 * xmlXPathPopNumber: 963 * @ctxt: an XPath parser context 964 * 965 * Pops a number from the stack, handling conversion if needed. 966 * Check error with #xmlXPathCheckError. 967 * 968 * Returns the number 969 */ 970double 971xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) { 972 xmlXPathObjectPtr obj; 973 double ret; 974 975 obj = valuePop(ctxt); 976 if (obj == NULL) { 977 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 978 return(0); 979 } 980 ret = xmlXPathCastToNumber(obj); 981 xmlXPathFreeObject(obj); 982 return(ret); 983} 984 985/** 986 * xmlXPathPopString: 987 * @ctxt: an XPath parser context 988 * 989 * Pops a string from the stack, handling conversion if needed. 990 * Check error with #xmlXPathCheckError. 991 * 992 * Returns the string 993 */ 994xmlChar * 995xmlXPathPopString (xmlXPathParserContextPtr ctxt) { 996 xmlXPathObjectPtr obj; 997 xmlChar * ret; 998 999 obj = valuePop(ctxt); 1000 if (obj == NULL) { 1001 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 1002 return(NULL); 1003 } 1004 ret = xmlXPathCastToString(obj); 1005 /* TODO: needs refactoring somewhere else */ 1006 if (obj->stringval == ret) 1007 obj->stringval = NULL; 1008 xmlXPathFreeObject(obj); 1009 return(ret); 1010} 1011 1012/** 1013 * xmlXPathPopNodeSet: 1014 * @ctxt: an XPath parser context 1015 * 1016 * Pops a node-set from the stack, handling conversion if needed. 1017 * Check error with #xmlXPathCheckError. 1018 * 1019 * Returns the node-set 1020 */ 1021xmlNodeSetPtr 1022xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) { 1023 xmlXPathObjectPtr obj; 1024 xmlNodeSetPtr ret; 1025 1026 if (ctxt->value == NULL) { 1027 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 1028 return(NULL); 1029 } 1030 if (!xmlXPathStackIsNodeSet(ctxt)) { 1031 xmlXPathSetTypeError(ctxt); 1032 return(NULL); 1033 } 1034 obj = valuePop(ctxt); 1035 ret = obj->nodesetval; 1036 xmlXPathFreeNodeSetList(obj); 1037 return(ret); 1038} 1039 1040/** 1041 * xmlXPathPopExternal: 1042 * @ctxt: an XPath parser context 1043 * 1044 * Pops an external object from the stack, handling conversion if needed. 1045 * Check error with #xmlXPathCheckError. 1046 * 1047 * Returns the object 1048 */ 1049void * 1050xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) { 1051 xmlXPathObjectPtr obj; 1052 void * ret; 1053 1054 if (ctxt->value == NULL) { 1055 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND); 1056 return(NULL); 1057 } 1058 if (ctxt->value->type != XPATH_USERS) { 1059 xmlXPathSetTypeError(ctxt); 1060 return(NULL); 1061 } 1062 obj = valuePop(ctxt); 1063 ret = obj->user; 1064 xmlXPathFreeObject(obj); 1065 return(ret); 1066} 1067 1068/* 1069 * Macros for accessing the content. Those should be used only by the parser, 1070 * and not exported. 1071 * 1072 * Dirty macros, i.e. one need to make assumption on the context to use them 1073 * 1074 * CUR_PTR return the current pointer to the xmlChar to be parsed. 1075 * CUR returns the current xmlChar value, i.e. a 8 bit value 1076 * in ISO-Latin or UTF-8. 1077 * This should be used internally by the parser 1078 * only to compare to ASCII values otherwise it would break when 1079 * running with UTF-8 encoding. 1080 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only 1081 * to compare on ASCII based substring. 1082 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined 1083 * strings within the parser. 1084 * CURRENT Returns the current char value, with the full decoding of 1085 * UTF-8 if we are using this mode. It returns an int. 1086 * NEXT Skip to the next character, this does the proper decoding 1087 * in UTF-8 mode. It also pop-up unfinished entities on the fly. 1088 * It returns the pointer to the current xmlChar. 1089 */ 1090 1091#define CUR (*ctxt->cur) 1092#define SKIP(val) ctxt->cur += (val) 1093#define NXT(val) ctxt->cur[(val)] 1094#define CUR_PTR ctxt->cur 1095#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l) 1096 1097#define COPY_BUF(l,b,i,v) \ 1098 if (l == 1) b[i++] = (xmlChar) v; \ 1099 else i += xmlCopyChar(l,&b[i],v) 1100 1101#define NEXTL(l) ctxt->cur += l 1102 1103#define SKIP_BLANKS \ 1104 while (IS_BLANK(*(ctxt->cur))) NEXT 1105 1106#define CURRENT (*ctxt->cur) 1107#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur) 1108 1109 1110#ifndef DBL_DIG 1111#define DBL_DIG 16 1112#endif 1113#ifndef DBL_EPSILON 1114#define DBL_EPSILON 1E-9 1115#endif 1116 1117#define UPPER_DOUBLE 1E9 1118#define LOWER_DOUBLE 1E-5 1119 1120#define INTEGER_DIGITS DBL_DIG 1121#define FRACTION_DIGITS (DBL_DIG + 1) 1122#define EXPONENT_DIGITS (3 + 2) 1123 1124/** 1125 * xmlXPathFormatNumber: 1126 * @number: number to format 1127 * @buffer: output buffer 1128 * @buffersize: size of output buffer 1129 * 1130 * Convert the number into a string representation. 1131 */ 1132static void 1133xmlXPathFormatNumber(double number, char buffer[], int buffersize) 1134{ 1135 switch (xmlXPathIsInf(number)) { 1136 case 1: 1137 if (buffersize > (int)sizeof("Infinity")) 1138 sprintf(buffer, "Infinity"); 1139 break; 1140 case -1: 1141 if (buffersize > (int)sizeof("-Infinity")) 1142 sprintf(buffer, "-Infinity"); 1143 break; 1144 default: 1145 if (xmlXPathIsNaN(number)) { 1146 if (buffersize > (int)sizeof("NaN")) 1147 sprintf(buffer, "NaN"); 1148 } else if (number == 0 && xmlXPathGetSign(number) != 0) { 1149 sprintf(buffer, "0"); 1150 } else if (number == ((int) number)) { 1151 char work[30]; 1152 char *ptr, *cur; 1153 int res, value = (int) number; 1154 1155 ptr = &buffer[0]; 1156 if (value < 0) { 1157 *ptr++ = '-'; 1158 value = -value; 1159 } 1160 if (value == 0) { 1161 *ptr++ = '0'; 1162 } else { 1163 cur = &work[0]; 1164 while (value != 0) { 1165 res = value % 10; 1166 value = value / 10; 1167 *cur++ = '0' + res; 1168 } 1169 cur--; 1170 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) { 1171 *ptr++ = *cur--; 1172 } 1173 } 1174 if (ptr - buffer < buffersize) { 1175 *ptr = 0; 1176 } else if (buffersize > 0) { 1177 ptr--; 1178 *ptr = 0; 1179 } 1180 } else { 1181 /* 3 is sign, decimal point, and terminating zero */ 1182 char work[DBL_DIG + EXPONENT_DIGITS + 3]; 1183 int integer_place, fraction_place; 1184 char *ptr; 1185 char *after_fraction; 1186 double absolute_value; 1187 int size; 1188 1189 absolute_value = fabs(number); 1190 1191 /* 1192 * First choose format - scientific or regular floating point. 1193 * In either case, result is in work, and after_fraction points 1194 * just past the fractional part. 1195 */ 1196 if ( ((absolute_value > UPPER_DOUBLE) || 1197 (absolute_value < LOWER_DOUBLE)) && 1198 (absolute_value != 0.0) ) { 1199 /* Use scientific notation */ 1200 integer_place = DBL_DIG + EXPONENT_DIGITS + 1; 1201 fraction_place = DBL_DIG - 1; 1202 snprintf(work, sizeof(work),"%*.*e", 1203 integer_place, fraction_place, number); 1204 after_fraction = strchr(work + DBL_DIG, 'e'); 1205 } 1206 else { 1207 /* Use regular notation */ 1208 if (absolute_value > 0.0) 1209 integer_place = 1 + (int)log10(absolute_value); 1210 else 1211 integer_place = 0; 1212 fraction_place = (integer_place > 0) 1213 ? DBL_DIG - integer_place 1214 : DBL_DIG; 1215 size = snprintf(work, sizeof(work), "%0.*f", 1216 fraction_place, number); 1217 after_fraction = work + size; 1218 } 1219 1220 /* Remove fractional trailing zeroes */ 1221 ptr = after_fraction; 1222 while (*(--ptr) == '0') 1223 ; 1224 if (*ptr != '.') 1225 ptr++; 1226 strcpy(ptr, after_fraction); 1227 1228 /* Finally copy result back to caller */ 1229 size = strlen(work) + 1; 1230 if (size > buffersize) { 1231 work[buffersize - 1] = 0; 1232 size = buffersize; 1233 } 1234 memcpy(buffer, work, size); 1235 } 1236 break; 1237 } 1238} 1239 1240/************************************************************************ 1241 * * 1242 * Error handling routines * 1243 * * 1244 ************************************************************************/ 1245 1246 1247static const char *xmlXPathErrorMessages[] = { 1248 "Ok", 1249 "Number encoding", 1250 "Unfinished literal", 1251 "Start of literal", 1252 "Expected $ for variable reference", 1253 "Undefined variable", 1254 "Invalid predicate", 1255 "Invalid expression", 1256 "Missing closing curly brace", 1257 "Unregistered function", 1258 "Invalid operand", 1259 "Invalid type", 1260 "Invalid number of arguments", 1261 "Invalid context size", 1262 "Invalid context position", 1263 "Memory allocation error", 1264 "Syntax error", 1265 "Resource error", 1266 "Sub resource error", 1267 "Undefined namespace prefix", 1268 "Encoding error", 1269 "Char out of XML range" 1270}; 1271 1272/** 1273 * xmlXPatherror: 1274 * @ctxt: the XPath Parser context 1275 * @file: the file name 1276 * @line: the line number 1277 * @no: the error number 1278 * 1279 * Formats an error message. 1280 */ 1281void 1282xmlXPatherror(xmlXPathParserContextPtr ctxt, ATTRIBUTE_UNUSED const char *file, 1283 ATTRIBUTE_UNUSED int line, int no) { 1284 int n; 1285 const xmlChar *cur; 1286 const xmlChar *base; 1287 1288/* xmlGenericError(xmlGenericErrorContext, 1289 "Error %s:%d: %s\n", file, line, 1290 xmlXPathErrorMessages[no]); 1291*/ 1292 xmlGenericError(xmlGenericErrorContext, 1293 "Error %s\n", xmlXPathErrorMessages[no]); 1294 1295 cur = ctxt->cur; 1296 base = ctxt->base; 1297 if ((cur == NULL) || (base == NULL)) 1298 return; 1299 1300 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) { 1301 cur--; 1302 } 1303 n = 0; 1304 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r')) 1305 cur--; 1306 if ((*cur == '\n') || (*cur == '\r')) cur++; 1307 base = cur; 1308 n = 0; 1309 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) { 1310 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++); 1311 n++; 1312 } 1313 xmlGenericError(xmlGenericErrorContext, "\n"); 1314 cur = ctxt->cur; 1315 while ((*cur == '\n') || (*cur == '\r')) 1316 cur--; 1317 n = 0; 1318 while ((cur != base) && (n++ < 80)) { 1319 xmlGenericError(xmlGenericErrorContext, " "); 1320 base++; 1321 } 1322 xmlGenericError(xmlGenericErrorContext,"^\n"); 1323} 1324 1325 1326/************************************************************************ 1327 * * 1328 * Routines to handle NodeSets * 1329 * * 1330 ************************************************************************/ 1331 1332/** 1333 * xmlXPathCmpNodes: 1334 * @node1: the first node 1335 * @node2: the second node 1336 * 1337 * Compare two nodes w.r.t document order 1338 * 1339 * Returns -2 in case of error 1 if first point < second point, 0 if 1340 * that's the same node, -1 otherwise 1341 */ 1342int 1343xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) { 1344 int depth1, depth2; 1345 xmlNodePtr cur, root; 1346 1347 if ((node1 == NULL) || (node2 == NULL)) 1348 return(-2); 1349 /* 1350 * a couple of optimizations which will avoid computations in most cases 1351 */ 1352 if (node1 == node2) 1353 return(0); 1354 if ((node1->type == XML_NAMESPACE_DECL) || 1355 (node2->type == XML_NAMESPACE_DECL)) 1356 return(1); 1357 if (node1 == node2->prev) 1358 return(1); 1359 if (node1 == node2->next) 1360 return(-1); 1361 1362 /* 1363 * compute depth to root 1364 */ 1365 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) { 1366 if (cur == node1) 1367 return(1); 1368 depth2++; 1369 } 1370 root = cur; 1371 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) { 1372 if (cur == node2) 1373 return(-1); 1374 depth1++; 1375 } 1376 /* 1377 * Distinct document (or distinct entities :-( ) case. 1378 */ 1379 if (root != cur) { 1380 return(-2); 1381 } 1382 /* 1383 * get the nearest common ancestor. 1384 */ 1385 while (depth1 > depth2) { 1386 depth1--; 1387 node1 = node1->parent; 1388 } 1389 while (depth2 > depth1) { 1390 depth2--; 1391 node2 = node2->parent; 1392 } 1393 while (node1->parent != node2->parent) { 1394 node1 = node1->parent; 1395 node2 = node2->parent; 1396 /* should not happen but just in case ... */ 1397 if ((node1 == NULL) || (node2 == NULL)) 1398 return(-2); 1399 } 1400 /* 1401 * Find who's first. 1402 */ 1403 if (node1 == node2->next) 1404 return(-1); 1405 for (cur = node1->next;cur != NULL;cur = cur->next) 1406 if (cur == node2) 1407 return(1); 1408 return(-1); /* assume there is no sibling list corruption */ 1409} 1410 1411/** 1412 * xmlXPathNodeSetSort: 1413 * @set: the node set 1414 * 1415 * Sort the node set in document order 1416 */ 1417void 1418xmlXPathNodeSetSort(xmlNodeSetPtr set) { 1419 int i, j, incr, len; 1420 xmlNodePtr tmp; 1421 1422 if (set == NULL) 1423 return; 1424 1425 /* Use Shell's sort to sort the node-set */ 1426 len = set->nodeNr; 1427 for (incr = len / 2; incr > 0; incr /= 2) { 1428 for (i = incr; i < len; i++) { 1429 j = i - incr; 1430 while (j >= 0) { 1431 if (xmlXPathCmpNodes(set->nodeTab[j], 1432 set->nodeTab[j + incr]) == -1) { 1433 tmp = set->nodeTab[j]; 1434 set->nodeTab[j] = set->nodeTab[j + incr]; 1435 set->nodeTab[j + incr] = tmp; 1436 j -= incr; 1437 } else 1438 break; 1439 } 1440 } 1441 } 1442} 1443 1444#define XML_NODESET_DEFAULT 10 1445/** 1446 * xmlXPathNodeSetDupNs: 1447 * @node: the parent node of the namespace XPath node 1448 * @ns: the libxml namespace declaration node. 1449 * 1450 * Namespace node in libxml don't match the XPath semantic. In a node set 1451 * the namespace nodes are duplicated and the next pointer is set to the 1452 * parent node in the XPath semantic. 1453 * 1454 * Returns the newly created object. 1455 */ 1456static xmlNodePtr 1457xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) { 1458 xmlNsPtr cur; 1459 1460 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 1461 return(NULL); 1462 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL)) 1463 return((xmlNodePtr) ns); 1464 1465 /* 1466 * Allocate a new Namespace and fill the fields. 1467 */ 1468 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs)); 1469 if (cur == NULL) { 1470 xmlGenericError(xmlGenericErrorContext, 1471 "xmlXPathNodeSetDupNs : malloc failed\n"); 1472 return(NULL); 1473 } 1474 memset(cur, 0, sizeof(xmlNs)); 1475 cur->type = XML_NAMESPACE_DECL; 1476 if (ns->href != NULL) 1477 cur->href = xmlStrdup(ns->href); 1478 if (ns->prefix != NULL) 1479 cur->prefix = xmlStrdup(ns->prefix); 1480 cur->next = (xmlNsPtr) node; 1481 return((xmlNodePtr) cur); 1482} 1483 1484/** 1485 * xmlXPathNodeSetFreeNs: 1486 * @ns: the XPath namespace node found in a nodeset. 1487 * 1488 * Namespace node in libxml don't match the XPath semantic. In a node set 1489 * the namespace nodes are duplicated and the next pointer is set to the 1490 * parent node in the XPath semantic. Check if such a node need to be freed 1491 */ 1492static void 1493xmlXPathNodeSetFreeNs(xmlNsPtr ns) { 1494 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL)) 1495 return; 1496 1497 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) { 1498 if (ns->href != NULL) 1499 xmlFree((xmlChar *)ns->href); 1500 if (ns->prefix != NULL) 1501 xmlFree((xmlChar *)ns->prefix); 1502 xmlFree(ns); 1503 } 1504} 1505 1506/** 1507 * xmlXPathNodeSetCreate: 1508 * @val: an initial xmlNodePtr, or NULL 1509 * 1510 * Create a new xmlNodeSetPtr of type double and of value @val 1511 * 1512 * Returns the newly created object. 1513 */ 1514xmlNodeSetPtr 1515xmlXPathNodeSetCreate(xmlNodePtr val) { 1516 xmlNodeSetPtr ret; 1517 1518 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet)); 1519 if (ret == NULL) { 1520 xmlGenericError(xmlGenericErrorContext, 1521 "xmlXPathNodeSetCreate: out of memory\n"); 1522 return(NULL); 1523 } 1524 memset(ret, 0 , (size_t) sizeof(xmlNodeSet)); 1525 if (val != NULL) { 1526 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1527 sizeof(xmlNodePtr)); 1528 if (ret->nodeTab == NULL) { 1529 xmlGenericError(xmlGenericErrorContext, 1530 "xmlXPathNodeSetCreate: out of memory\n"); 1531 return(NULL); 1532 } 1533 memset(ret->nodeTab, 0 , 1534 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1535 ret->nodeMax = XML_NODESET_DEFAULT; 1536 if (val->type == XML_NAMESPACE_DECL) { 1537 xmlNsPtr ns = (xmlNsPtr) val; 1538 1539 ret->nodeTab[ret->nodeNr++] = 1540 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1541 } else 1542 ret->nodeTab[ret->nodeNr++] = val; 1543 } 1544 return(ret); 1545} 1546 1547/** 1548 * xmlXPathNodeSetContains: 1549 * @cur: the node-set 1550 * @val: the node 1551 * 1552 * checks whether @cur contains @val 1553 * 1554 * Returns true (1) if @cur contains @val, false (0) otherwise 1555 */ 1556int 1557xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) { 1558 int i; 1559 1560 if (val->type == XML_NAMESPACE_DECL) { 1561 for (i = 0; i < cur->nodeNr; i++) { 1562 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) { 1563 xmlNsPtr ns1, ns2; 1564 1565 ns1 = (xmlNsPtr) val; 1566 ns2 = (xmlNsPtr) cur->nodeTab[i]; 1567 if (ns1 == ns2) 1568 return(1); 1569 if ((ns1->next != NULL) && (ns2->next == ns1->next) && 1570 (xmlStrEqual(ns1->prefix, ns2->prefix))) 1571 return(1); 1572 } 1573 } 1574 } else { 1575 for (i = 0; i < cur->nodeNr; i++) { 1576 if (cur->nodeTab[i] == val) 1577 return(1); 1578 } 1579 } 1580 return(0); 1581} 1582 1583/** 1584 * xmlXPathNodeSetAddNs: 1585 * @cur: the initial node set 1586 * @node: the hosting node 1587 * @ns: a the namespace node 1588 * 1589 * add a new namespace node to an existing NodeSet 1590 */ 1591void 1592xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) { 1593 int i; 1594 1595 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) || 1596 (node->type != XML_ELEMENT_NODE)) 1597 return; 1598 1599 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1600 /* 1601 * check against doublons 1602 */ 1603 for (i = 0;i < cur->nodeNr;i++) { 1604 if ((cur->nodeTab[i] != NULL) && 1605 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) && 1606 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) && 1607 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix))) 1608 return; 1609 } 1610 1611 /* 1612 * grow the nodeTab if needed 1613 */ 1614 if (cur->nodeMax == 0) { 1615 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1616 sizeof(xmlNodePtr)); 1617 if (cur->nodeTab == NULL) { 1618 xmlGenericError(xmlGenericErrorContext, 1619 "xmlXPathNodeSetAdd: out of memory\n"); 1620 return; 1621 } 1622 memset(cur->nodeTab, 0 , 1623 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1624 cur->nodeMax = XML_NODESET_DEFAULT; 1625 } else if (cur->nodeNr == cur->nodeMax) { 1626 xmlNodePtr *temp; 1627 1628 cur->nodeMax *= 2; 1629 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 1630 sizeof(xmlNodePtr)); 1631 if (temp == NULL) { 1632 xmlGenericError(xmlGenericErrorContext, 1633 "xmlXPathNodeSetAdd: out of memory\n"); 1634 return; 1635 } 1636 cur->nodeTab = temp; 1637 } 1638 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns); 1639} 1640 1641/** 1642 * xmlXPathNodeSetAdd: 1643 * @cur: the initial node set 1644 * @val: a new xmlNodePtr 1645 * 1646 * add a new xmlNodePtr to an existing NodeSet 1647 */ 1648void 1649xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) { 1650 int i; 1651 1652 if (val == NULL) return; 1653 1654 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1655 /* 1656 * check against doublons 1657 */ 1658 for (i = 0;i < cur->nodeNr;i++) 1659 if (cur->nodeTab[i] == val) return; 1660 1661 /* 1662 * grow the nodeTab if needed 1663 */ 1664 if (cur->nodeMax == 0) { 1665 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1666 sizeof(xmlNodePtr)); 1667 if (cur->nodeTab == NULL) { 1668 xmlGenericError(xmlGenericErrorContext, 1669 "xmlXPathNodeSetAdd: out of memory\n"); 1670 return; 1671 } 1672 memset(cur->nodeTab, 0 , 1673 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1674 cur->nodeMax = XML_NODESET_DEFAULT; 1675 } else if (cur->nodeNr == cur->nodeMax) { 1676 xmlNodePtr *temp; 1677 1678 cur->nodeMax *= 2; 1679 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 1680 sizeof(xmlNodePtr)); 1681 if (temp == NULL) { 1682 xmlGenericError(xmlGenericErrorContext, 1683 "xmlXPathNodeSetAdd: out of memory\n"); 1684 return; 1685 } 1686 cur->nodeTab = temp; 1687 } 1688 if (val->type == XML_NAMESPACE_DECL) { 1689 xmlNsPtr ns = (xmlNsPtr) val; 1690 1691 cur->nodeTab[cur->nodeNr++] = 1692 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1693 } else 1694 cur->nodeTab[cur->nodeNr++] = val; 1695} 1696 1697/** 1698 * xmlXPathNodeSetAddUnique: 1699 * @cur: the initial node set 1700 * @val: a new xmlNodePtr 1701 * 1702 * add a new xmlNodePtr to an existing NodeSet, optimized version 1703 * when we are sure the node is not already in the set. 1704 */ 1705void 1706xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) { 1707 if (val == NULL) return; 1708 1709 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1710 /* 1711 * grow the nodeTab if needed 1712 */ 1713 if (cur->nodeMax == 0) { 1714 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1715 sizeof(xmlNodePtr)); 1716 if (cur->nodeTab == NULL) { 1717 xmlGenericError(xmlGenericErrorContext, 1718 "xmlXPathNodeSetAddUnique: out of memory\n"); 1719 return; 1720 } 1721 memset(cur->nodeTab, 0 , 1722 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1723 cur->nodeMax = XML_NODESET_DEFAULT; 1724 } else if (cur->nodeNr == cur->nodeMax) { 1725 xmlNodePtr *temp; 1726 1727 cur->nodeMax *= 2; 1728 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 1729 sizeof(xmlNodePtr)); 1730 if (temp == NULL) { 1731 xmlGenericError(xmlGenericErrorContext, 1732 "xmlXPathNodeSetAddUnique: out of memory\n"); 1733 return; 1734 } 1735 cur->nodeTab = temp; 1736 } 1737 if (val->type == XML_NAMESPACE_DECL) { 1738 xmlNsPtr ns = (xmlNsPtr) val; 1739 1740 cur->nodeTab[cur->nodeNr++] = 1741 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1742 } else 1743 cur->nodeTab[cur->nodeNr++] = val; 1744} 1745 1746/** 1747 * xmlXPathNodeSetMerge: 1748 * @val1: the first NodeSet or NULL 1749 * @val2: the second NodeSet 1750 * 1751 * Merges two nodesets, all nodes from @val2 are added to @val1 1752 * if @val1 is NULL, a new set is created and copied from @val2 1753 * 1754 * Returns @val1 once extended or NULL in case of error. 1755 */ 1756xmlNodeSetPtr 1757xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 1758 int i, j, initNr, skip; 1759 1760 if (val2 == NULL) return(val1); 1761 if (val1 == NULL) { 1762 val1 = xmlXPathNodeSetCreate(NULL); 1763 } 1764 1765 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1766 initNr = val1->nodeNr; 1767 1768 for (i = 0;i < val2->nodeNr;i++) { 1769 /* 1770 * check against doublons 1771 */ 1772 skip = 0; 1773 for (j = 0; j < initNr; j++) { 1774 if (val1->nodeTab[j] == val2->nodeTab[i]) { 1775 skip = 1; 1776 break; 1777 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) && 1778 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) { 1779 xmlNsPtr ns1, ns2; 1780 ns1 = (xmlNsPtr) val1->nodeTab[j]; 1781 ns2 = (xmlNsPtr) val2->nodeTab[i]; 1782 if ((ns1->next == ns2->next) && 1783 (xmlStrEqual(ns1->prefix, ns2->prefix))) { 1784 skip = 1; 1785 break; 1786 } 1787 } 1788 } 1789 if (skip) 1790 continue; 1791 1792 /* 1793 * grow the nodeTab if needed 1794 */ 1795 if (val1->nodeMax == 0) { 1796 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1797 sizeof(xmlNodePtr)); 1798 if (val1->nodeTab == NULL) { 1799 xmlGenericError(xmlGenericErrorContext, 1800 "xmlXPathNodeSetMerge: out of memory\n"); 1801 return(NULL); 1802 } 1803 memset(val1->nodeTab, 0 , 1804 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1805 val1->nodeMax = XML_NODESET_DEFAULT; 1806 } else if (val1->nodeNr == val1->nodeMax) { 1807 xmlNodePtr *temp; 1808 1809 val1->nodeMax *= 2; 1810 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 1811 sizeof(xmlNodePtr)); 1812 if (temp == NULL) { 1813 xmlGenericError(xmlGenericErrorContext, 1814 "xmlXPathNodeSetMerge: out of memory\n"); 1815 return(NULL); 1816 } 1817 val1->nodeTab = temp; 1818 } 1819 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 1820 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 1821 1822 val1->nodeTab[val1->nodeNr++] = 1823 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1824 } else 1825 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 1826 } 1827 1828 return(val1); 1829} 1830 1831/** 1832 * xmlXPathNodeSetMergeUnique: 1833 * @val1: the first NodeSet or NULL 1834 * @val2: the second NodeSet 1835 * 1836 * Merges two nodesets, all nodes from @val2 are added to @val1 1837 * if @val1 is NULL, a new set is created and copied from @val2 1838 * 1839 * Returns @val1 once extended or NULL in case of error. 1840 */ 1841static xmlNodeSetPtr 1842xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) { 1843 int i, initNr; 1844 1845 if (val2 == NULL) return(val1); 1846 if (val1 == NULL) { 1847 val1 = xmlXPathNodeSetCreate(NULL); 1848 } 1849 1850 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1851 initNr = val1->nodeNr; 1852 1853 for (i = 0;i < val2->nodeNr;i++) { 1854 /* 1855 * grow the nodeTab if needed 1856 */ 1857 if (val1->nodeMax == 0) { 1858 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT * 1859 sizeof(xmlNodePtr)); 1860 if (val1->nodeTab == NULL) { 1861 xmlGenericError(xmlGenericErrorContext, 1862 "xmlXPathNodeSetMerge: out of memory\n"); 1863 return(NULL); 1864 } 1865 memset(val1->nodeTab, 0 , 1866 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr)); 1867 val1->nodeMax = XML_NODESET_DEFAULT; 1868 } else if (val1->nodeNr == val1->nodeMax) { 1869 xmlNodePtr *temp; 1870 1871 val1->nodeMax *= 2; 1872 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 1873 sizeof(xmlNodePtr)); 1874 if (temp == NULL) { 1875 xmlGenericError(xmlGenericErrorContext, 1876 "xmlXPathNodeSetMerge: out of memory\n"); 1877 return(NULL); 1878 } 1879 val1->nodeTab = temp; 1880 } 1881 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) { 1882 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i]; 1883 1884 val1->nodeTab[val1->nodeNr++] = 1885 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); 1886 } else 1887 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i]; 1888 } 1889 1890 return(val1); 1891} 1892 1893/** 1894 * xmlXPathNodeSetDel: 1895 * @cur: the initial node set 1896 * @val: an xmlNodePtr 1897 * 1898 * Removes an xmlNodePtr from an existing NodeSet 1899 */ 1900void 1901xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) { 1902 int i; 1903 1904 if (cur == NULL) return; 1905 if (val == NULL) return; 1906 1907 /* 1908 * check against doublons 1909 */ 1910 for (i = 0;i < cur->nodeNr;i++) 1911 if (cur->nodeTab[i] == val) break; 1912 1913 if (i >= cur->nodeNr) { 1914#ifdef DEBUG 1915 xmlGenericError(xmlGenericErrorContext, 1916 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n", 1917 val->name); 1918#endif 1919 return; 1920 } 1921 if ((cur->nodeTab[i] != NULL) && 1922 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL)) 1923 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]); 1924 cur->nodeNr--; 1925 for (;i < cur->nodeNr;i++) 1926 cur->nodeTab[i] = cur->nodeTab[i + 1]; 1927 cur->nodeTab[cur->nodeNr] = NULL; 1928} 1929 1930/** 1931 * xmlXPathNodeSetRemove: 1932 * @cur: the initial node set 1933 * @val: the index to remove 1934 * 1935 * Removes an entry from an existing NodeSet list. 1936 */ 1937void 1938xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) { 1939 if (cur == NULL) return; 1940 if (val >= cur->nodeNr) return; 1941 if ((cur->nodeTab[val] != NULL) && 1942 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL)) 1943 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]); 1944 cur->nodeNr--; 1945 for (;val < cur->nodeNr;val++) 1946 cur->nodeTab[val] = cur->nodeTab[val + 1]; 1947 cur->nodeTab[cur->nodeNr] = NULL; 1948} 1949 1950/** 1951 * xmlXPathFreeNodeSet: 1952 * @obj: the xmlNodeSetPtr to free 1953 * 1954 * Free the NodeSet compound (not the actual nodes !). 1955 */ 1956void 1957xmlXPathFreeNodeSet(xmlNodeSetPtr obj) { 1958 if (obj == NULL) return; 1959 if (obj->nodeTab != NULL) { 1960 int i; 1961 1962 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 1963 for (i = 0;i < obj->nodeNr;i++) 1964 if ((obj->nodeTab[i] != NULL) && 1965 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL)) 1966 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 1967 xmlFree(obj->nodeTab); 1968 } 1969 xmlFree(obj); 1970} 1971 1972/** 1973 * xmlXPathFreeValueTree: 1974 * @obj: the xmlNodeSetPtr to free 1975 * 1976 * Free the NodeSet compound and the actual tree, this is different 1977 * from xmlXPathFreeNodeSet() 1978 */ 1979static void 1980xmlXPathFreeValueTree(xmlNodeSetPtr obj) { 1981 int i; 1982 1983 if (obj == NULL) return; 1984 1985 if (obj->nodeTab != NULL) { 1986 for (i = 0;i < obj->nodeNr;i++) { 1987 if (obj->nodeTab[i] != NULL) { 1988 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) { 1989 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]); 1990 } else { 1991 xmlFreeNodeList(obj->nodeTab[i]); 1992 } 1993 } 1994 } 1995 xmlFree(obj->nodeTab); 1996 } 1997 xmlFree(obj); 1998} 1999 2000#if defined(DEBUG) || defined(DEBUG_STEP) 2001/** 2002 * xmlGenericErrorContextNodeSet: 2003 * @output: a FILE * for the output 2004 * @obj: the xmlNodeSetPtr to free 2005 * 2006 * Quick display of a NodeSet 2007 */ 2008void 2009xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) { 2010 int i; 2011 2012 if (output == NULL) output = xmlGenericErrorContext; 2013 if (obj == NULL) { 2014 fprintf(output, "NodeSet == NULL !\n"); 2015 return; 2016 } 2017 if (obj->nodeNr == 0) { 2018 fprintf(output, "NodeSet is empty\n"); 2019 return; 2020 } 2021 if (obj->nodeTab == NULL) { 2022 fprintf(output, " nodeTab == NULL !\n"); 2023 return; 2024 } 2025 for (i = 0; i < obj->nodeNr; i++) { 2026 if (obj->nodeTab[i] == NULL) { 2027 fprintf(output, " NULL !\n"); 2028 return; 2029 } 2030 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) || 2031 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE)) 2032 fprintf(output, " /"); 2033 else if (obj->nodeTab[i]->name == NULL) 2034 fprintf(output, " noname!"); 2035 else fprintf(output, " %s", obj->nodeTab[i]->name); 2036 } 2037 fprintf(output, "\n"); 2038} 2039#endif 2040 2041/** 2042 * xmlXPathNewNodeSet: 2043 * @val: the NodePtr value 2044 * 2045 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 2046 * it with the single Node @val 2047 * 2048 * Returns the newly created object. 2049 */ 2050xmlXPathObjectPtr 2051xmlXPathNewNodeSet(xmlNodePtr val) { 2052 xmlXPathObjectPtr ret; 2053 2054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2055 if (ret == NULL) { 2056 xmlGenericError(xmlGenericErrorContext, 2057 "xmlXPathNewNodeSet: out of memory\n"); 2058 return(NULL); 2059 } 2060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2061 ret->type = XPATH_NODESET; 2062 ret->boolval = 0; 2063 ret->nodesetval = xmlXPathNodeSetCreate(val); 2064 /* @@ with_ns to check wether namespace nodes should be looked at @@ */ 2065 return(ret); 2066} 2067 2068/** 2069 * xmlXPathNewValueTree: 2070 * @val: the NodePtr value 2071 * 2072 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize 2073 * it with the tree root @val 2074 * 2075 * Returns the newly created object. 2076 */ 2077xmlXPathObjectPtr 2078xmlXPathNewValueTree(xmlNodePtr val) { 2079 xmlXPathObjectPtr ret; 2080 2081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2082 if (ret == NULL) { 2083 xmlGenericError(xmlGenericErrorContext, 2084 "xmlXPathNewNodeSet: out of memory\n"); 2085 return(NULL); 2086 } 2087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2088 ret->type = XPATH_XSLT_TREE; 2089 ret->boolval = 1; 2090 ret->user = (void *) val; 2091 ret->nodesetval = xmlXPathNodeSetCreate(val); 2092 return(ret); 2093} 2094 2095/** 2096 * xmlXPathNewNodeSetList: 2097 * @val: an existing NodeSet 2098 * 2099 * Create a new xmlXPathObjectPtr of type NodeSet and initialize 2100 * it with the Nodeset @val 2101 * 2102 * Returns the newly created object. 2103 */ 2104xmlXPathObjectPtr 2105xmlXPathNewNodeSetList(xmlNodeSetPtr val) 2106{ 2107 xmlXPathObjectPtr ret; 2108 int i; 2109 2110 if (val == NULL) 2111 ret = NULL; 2112 else if (val->nodeTab == NULL) 2113 ret = xmlXPathNewNodeSet(NULL); 2114 else { 2115 ret = xmlXPathNewNodeSet(val->nodeTab[0]); 2116 for (i = 1; i < val->nodeNr; ++i) 2117 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]); 2118 } 2119 2120 return (ret); 2121} 2122 2123/** 2124 * xmlXPathWrapNodeSet: 2125 * @val: the NodePtr value 2126 * 2127 * Wrap the Nodeset @val in a new xmlXPathObjectPtr 2128 * 2129 * Returns the newly created object. 2130 */ 2131xmlXPathObjectPtr 2132xmlXPathWrapNodeSet(xmlNodeSetPtr val) { 2133 xmlXPathObjectPtr ret; 2134 2135 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2136 if (ret == NULL) { 2137 xmlGenericError(xmlGenericErrorContext, 2138 "xmlXPathWrapNodeSet: out of memory\n"); 2139 return(NULL); 2140 } 2141 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2142 ret->type = XPATH_NODESET; 2143 ret->nodesetval = val; 2144 return(ret); 2145} 2146 2147/** 2148 * xmlXPathFreeNodeSetList: 2149 * @obj: an existing NodeSetList object 2150 * 2151 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in 2152 * the list contrary to xmlXPathFreeObject(). 2153 */ 2154void 2155xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) { 2156 if (obj == NULL) return; 2157 xmlFree(obj); 2158} 2159 2160/** 2161 * xmlXPathDifference: 2162 * @nodes1: a node-set 2163 * @nodes2: a node-set 2164 * 2165 * Implements the EXSLT - Sets difference() function: 2166 * node-set set:difference (node-set, node-set) 2167 * 2168 * Returns the difference between the two node sets, or nodes1 if 2169 * nodes2 is empty 2170 */ 2171xmlNodeSetPtr 2172xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2173 xmlNodeSetPtr ret; 2174 int i, l1; 2175 xmlNodePtr cur; 2176 2177 if (xmlXPathNodeSetIsEmpty(nodes2)) 2178 return(nodes1); 2179 2180 ret = xmlXPathNodeSetCreate(NULL); 2181 if (xmlXPathNodeSetIsEmpty(nodes1)) 2182 return(ret); 2183 2184 l1 = xmlXPathNodeSetGetLength(nodes1); 2185 2186 for (i = 0; i < l1; i++) { 2187 cur = xmlXPathNodeSetItem(nodes1, i); 2188 if (!xmlXPathNodeSetContains(nodes2, cur)) 2189 xmlXPathNodeSetAddUnique(ret, cur); 2190 } 2191 return(ret); 2192} 2193 2194/** 2195 * xmlXPathIntersection: 2196 * @nodes1: a node-set 2197 * @nodes2: a node-set 2198 * 2199 * Implements the EXSLT - Sets intersection() function: 2200 * node-set set:intersection (node-set, node-set) 2201 * 2202 * Returns a node set comprising the nodes that are within both the 2203 * node sets passed as arguments 2204 */ 2205xmlNodeSetPtr 2206xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2207 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL); 2208 int i, l1; 2209 xmlNodePtr cur; 2210 2211 if (xmlXPathNodeSetIsEmpty(nodes1)) 2212 return(ret); 2213 if (xmlXPathNodeSetIsEmpty(nodes2)) 2214 return(ret); 2215 2216 l1 = xmlXPathNodeSetGetLength(nodes1); 2217 2218 for (i = 0; i < l1; i++) { 2219 cur = xmlXPathNodeSetItem(nodes1, i); 2220 if (xmlXPathNodeSetContains(nodes2, cur)) 2221 xmlXPathNodeSetAddUnique(ret, cur); 2222 } 2223 return(ret); 2224} 2225 2226/** 2227 * xmlXPathDistinctSorted: 2228 * @nodes: a node-set, sorted by document order 2229 * 2230 * Implements the EXSLT - Sets distinct() function: 2231 * node-set set:distinct (node-set) 2232 * 2233 * Returns a subset of the nodes contained in @nodes, or @nodes if 2234 * it is empty 2235 */ 2236xmlNodeSetPtr 2237xmlXPathDistinctSorted (xmlNodeSetPtr nodes) { 2238 xmlNodeSetPtr ret; 2239 xmlHashTablePtr hash; 2240 int i, l; 2241 xmlChar * strval; 2242 xmlNodePtr cur; 2243 2244 if (xmlXPathNodeSetIsEmpty(nodes)) 2245 return(nodes); 2246 2247 ret = xmlXPathNodeSetCreate(NULL); 2248 l = xmlXPathNodeSetGetLength(nodes); 2249 hash = xmlHashCreate (l); 2250 for (i = 0; i < l; i++) { 2251 cur = xmlXPathNodeSetItem(nodes, i); 2252 strval = xmlXPathCastNodeToString(cur); 2253 if (xmlHashLookup(hash, strval) == NULL) { 2254 xmlHashAddEntry(hash, strval, strval); 2255 xmlXPathNodeSetAddUnique(ret, cur); 2256 } else { 2257 xmlFree(strval); 2258 } 2259 } 2260 xmlHashFree(hash, (xmlHashDeallocator) xmlFree); 2261 return(ret); 2262} 2263 2264/** 2265 * xmlXPathDistinct: 2266 * @nodes: a node-set 2267 * 2268 * Implements the EXSLT - Sets distinct() function: 2269 * node-set set:distinct (node-set) 2270 * @nodes is sorted by document order, then #exslSetsDistinctSorted 2271 * is called with the sorted node-set 2272 * 2273 * Returns a subset of the nodes contained in @nodes, or @nodes if 2274 * it is empty 2275 */ 2276xmlNodeSetPtr 2277xmlXPathDistinct (xmlNodeSetPtr nodes) { 2278 if (xmlXPathNodeSetIsEmpty(nodes)) 2279 return(nodes); 2280 2281 xmlXPathNodeSetSort(nodes); 2282 return(xmlXPathDistinctSorted(nodes)); 2283} 2284 2285/** 2286 * xmlXPathHasSameNodes: 2287 * @nodes1: a node-set 2288 * @nodes2: a node-set 2289 * 2290 * Implements the EXSLT - Sets has-same-nodes function: 2291 * boolean set:has-same-node(node-set, node-set) 2292 * 2293 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0) 2294 * otherwise 2295 */ 2296int 2297xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2298 int i, l; 2299 xmlNodePtr cur; 2300 2301 if (xmlXPathNodeSetIsEmpty(nodes1) || 2302 xmlXPathNodeSetIsEmpty(nodes2)) 2303 return(0); 2304 2305 l = xmlXPathNodeSetGetLength(nodes1); 2306 for (i = 0; i < l; i++) { 2307 cur = xmlXPathNodeSetItem(nodes1, i); 2308 if (xmlXPathNodeSetContains(nodes2, cur)) 2309 return(1); 2310 } 2311 return(0); 2312} 2313 2314/** 2315 * xmlXPathNodeLeadingSorted: 2316 * @nodes: a node-set, sorted by document order 2317 * @node: a node 2318 * 2319 * Implements the EXSLT - Sets leading() function: 2320 * node-set set:leading (node-set, node-set) 2321 * 2322 * Returns the nodes in @nodes that precede @node in document order, 2323 * @nodes if @node is NULL or an empty node-set if @nodes 2324 * doesn't contain @node 2325 */ 2326xmlNodeSetPtr 2327xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 2328 int i, l; 2329 xmlNodePtr cur; 2330 xmlNodeSetPtr ret; 2331 2332 if (node == NULL) 2333 return(nodes); 2334 2335 ret = xmlXPathNodeSetCreate(NULL); 2336 if (xmlXPathNodeSetIsEmpty(nodes) || 2337 (!xmlXPathNodeSetContains(nodes, node))) 2338 return(ret); 2339 2340 l = xmlXPathNodeSetGetLength(nodes); 2341 for (i = 0; i < l; i++) { 2342 cur = xmlXPathNodeSetItem(nodes, i); 2343 if (cur == node) 2344 break; 2345 xmlXPathNodeSetAddUnique(ret, cur); 2346 } 2347 return(ret); 2348} 2349 2350/** 2351 * xmlXPathNodeLeading: 2352 * @nodes: a node-set 2353 * @node: a node 2354 * 2355 * Implements the EXSLT - Sets leading() function: 2356 * node-set set:leading (node-set, node-set) 2357 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted 2358 * is called. 2359 * 2360 * Returns the nodes in @nodes that precede @node in document order, 2361 * @nodes if @node is NULL or an empty node-set if @nodes 2362 * doesn't contain @node 2363 */ 2364xmlNodeSetPtr 2365xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) { 2366 xmlXPathNodeSetSort(nodes); 2367 return(xmlXPathNodeLeadingSorted(nodes, node)); 2368} 2369 2370/** 2371 * xmlXPathLeadingSorted: 2372 * @nodes1: a node-set, sorted by document order 2373 * @nodes2: a node-set, sorted by document order 2374 * 2375 * Implements the EXSLT - Sets leading() function: 2376 * node-set set:leading (node-set, node-set) 2377 * 2378 * Returns the nodes in @nodes1 that precede the first node in @nodes2 2379 * in document order, @nodes1 if @nodes2 is NULL or empty or 2380 * an empty node-set if @nodes1 doesn't contain @nodes2 2381 */ 2382xmlNodeSetPtr 2383xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2384 if (xmlXPathNodeSetIsEmpty(nodes2)) 2385 return(nodes1); 2386 return(xmlXPathNodeLeadingSorted(nodes1, 2387 xmlXPathNodeSetItem(nodes2, 1))); 2388} 2389 2390/** 2391 * xmlXPathLeading: 2392 * @nodes1: a node-set 2393 * @nodes2: a node-set 2394 * 2395 * Implements the EXSLT - Sets leading() function: 2396 * node-set set:leading (node-set, node-set) 2397 * @nodes1 and @nodes2 are sorted by document order, then 2398 * #exslSetsLeadingSorted is called. 2399 * 2400 * Returns the nodes in @nodes1 that precede the first node in @nodes2 2401 * in document order, @nodes1 if @nodes2 is NULL or empty or 2402 * an empty node-set if @nodes1 doesn't contain @nodes2 2403 */ 2404xmlNodeSetPtr 2405xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2406 if (xmlXPathNodeSetIsEmpty(nodes2)) 2407 return(nodes1); 2408 if (xmlXPathNodeSetIsEmpty(nodes1)) 2409 return(xmlXPathNodeSetCreate(NULL)); 2410 xmlXPathNodeSetSort(nodes1); 2411 xmlXPathNodeSetSort(nodes2); 2412 return(xmlXPathNodeLeadingSorted(nodes1, 2413 xmlXPathNodeSetItem(nodes2, 1))); 2414} 2415 2416/** 2417 * xmlXPathNodeTrailingSorted: 2418 * @nodes: a node-set, sorted by document order 2419 * @node: a node 2420 * 2421 * Implements the EXSLT - Sets trailing() function: 2422 * node-set set:trailing (node-set, node-set) 2423 * 2424 * Returns the nodes in @nodes that follow @node in document order, 2425 * @nodes if @node is NULL or an empty node-set if @nodes 2426 * doesn't contain @node 2427 */ 2428xmlNodeSetPtr 2429xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) { 2430 int i, l; 2431 xmlNodePtr cur; 2432 xmlNodeSetPtr ret; 2433 2434 if (node == NULL) 2435 return(nodes); 2436 2437 ret = xmlXPathNodeSetCreate(NULL); 2438 if (xmlXPathNodeSetIsEmpty(nodes) || 2439 (!xmlXPathNodeSetContains(nodes, node))) 2440 return(ret); 2441 2442 l = xmlXPathNodeSetGetLength(nodes); 2443 for (i = l; i > 0; i--) { 2444 cur = xmlXPathNodeSetItem(nodes, i); 2445 if (cur == node) 2446 break; 2447 xmlXPathNodeSetAddUnique(ret, cur); 2448 } 2449 return(ret); 2450} 2451 2452/** 2453 * xmlXPathNodeTrailing: 2454 * @nodes: a node-set 2455 * @node: a node 2456 * 2457 * Implements the EXSLT - Sets trailing() function: 2458 * node-set set:trailing (node-set, node-set) 2459 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted 2460 * is called. 2461 * 2462 * Returns the nodes in @nodes that follow @node in document order, 2463 * @nodes if @node is NULL or an empty node-set if @nodes 2464 * doesn't contain @node 2465 */ 2466xmlNodeSetPtr 2467xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) { 2468 xmlXPathNodeSetSort(nodes); 2469 return(xmlXPathNodeTrailingSorted(nodes, node)); 2470} 2471 2472/** 2473 * xmlXPathTrailingSorted: 2474 * @nodes1: a node-set, sorted by document order 2475 * @nodes2: a node-set, sorted by document order 2476 * 2477 * Implements the EXSLT - Sets trailing() function: 2478 * node-set set:trailing (node-set, node-set) 2479 * 2480 * Returns the nodes in @nodes1 that follow the first node in @nodes2 2481 * in document order, @nodes1 if @nodes2 is NULL or empty or 2482 * an empty node-set if @nodes1 doesn't contain @nodes2 2483 */ 2484xmlNodeSetPtr 2485xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2486 if (xmlXPathNodeSetIsEmpty(nodes2)) 2487 return(nodes1); 2488 return(xmlXPathNodeTrailingSorted(nodes1, 2489 xmlXPathNodeSetItem(nodes2, 0))); 2490} 2491 2492/** 2493 * xmlXPathTrailing: 2494 * @nodes1: a node-set 2495 * @nodes2: a node-set 2496 * 2497 * Implements the EXSLT - Sets trailing() function: 2498 * node-set set:trailing (node-set, node-set) 2499 * @nodes1 and @nodes2 are sorted by document order, then 2500 * #xmlXPathTrailingSorted is called. 2501 * 2502 * Returns the nodes in @nodes1 that follow the first node in @nodes2 2503 * in document order, @nodes1 if @nodes2 is NULL or empty or 2504 * an empty node-set if @nodes1 doesn't contain @nodes2 2505 */ 2506xmlNodeSetPtr 2507xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) { 2508 if (xmlXPathNodeSetIsEmpty(nodes2)) 2509 return(nodes1); 2510 if (xmlXPathNodeSetIsEmpty(nodes1)) 2511 return(xmlXPathNodeSetCreate(NULL)); 2512 xmlXPathNodeSetSort(nodes1); 2513 xmlXPathNodeSetSort(nodes2); 2514 return(xmlXPathNodeTrailingSorted(nodes1, 2515 xmlXPathNodeSetItem(nodes2, 0))); 2516} 2517 2518/************************************************************************ 2519 * * 2520 * Routines to handle extra functions * 2521 * * 2522 ************************************************************************/ 2523 2524/** 2525 * xmlXPathRegisterFunc: 2526 * @ctxt: the XPath context 2527 * @name: the function name 2528 * @f: the function implementation or NULL 2529 * 2530 * Register a new function. If @f is NULL it unregisters the function 2531 * 2532 * Returns 0 in case of success, -1 in case of error 2533 */ 2534int 2535xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name, 2536 xmlXPathFunction f) { 2537 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f)); 2538} 2539 2540/** 2541 * xmlXPathRegisterFuncNS: 2542 * @ctxt: the XPath context 2543 * @name: the function name 2544 * @ns_uri: the function namespace URI 2545 * @f: the function implementation or NULL 2546 * 2547 * Register a new function. If @f is NULL it unregisters the function 2548 * 2549 * Returns 0 in case of success, -1 in case of error 2550 */ 2551int 2552xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2553 const xmlChar *ns_uri, xmlXPathFunction f) { 2554 if (ctxt == NULL) 2555 return(-1); 2556 if (name == NULL) 2557 return(-1); 2558 2559 if (ctxt->funcHash == NULL) 2560 ctxt->funcHash = xmlHashCreate(0); 2561 if (ctxt->funcHash == NULL) 2562 return(-1); 2563 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f)); 2564} 2565 2566/** 2567 * xmlXPathRegisterFuncLookup: 2568 * @ctxt: the XPath context 2569 * @f: the lookup function 2570 * @funcCtxt: the lookup data 2571 * 2572 * Registers an external mechanism to do function lookup. 2573 */ 2574void 2575xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt, 2576 xmlXPathFuncLookupFunc f, 2577 void *funcCtxt) { 2578 if (ctxt == NULL) 2579 return; 2580 ctxt->funcLookupFunc = (void *) f; 2581 ctxt->funcLookupData = funcCtxt; 2582} 2583 2584/** 2585 * xmlXPathFunctionLookup: 2586 * @ctxt: the XPath context 2587 * @name: the function name 2588 * 2589 * Search in the Function array of the context for the given 2590 * function. 2591 * 2592 * Returns the xmlXPathFunction or NULL if not found 2593 */ 2594xmlXPathFunction 2595xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 2596 if (ctxt == NULL) 2597 return (NULL); 2598 2599 if (ctxt->funcLookupFunc != NULL) { 2600 xmlXPathFunction ret; 2601 xmlXPathFuncLookupFunc f; 2602 2603 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc; 2604 ret = f(ctxt->funcLookupData, name, NULL); 2605 if (ret != NULL) 2606 return(ret); 2607 } 2608 return(xmlXPathFunctionLookupNS(ctxt, name, NULL)); 2609} 2610 2611/** 2612 * xmlXPathFunctionLookupNS: 2613 * @ctxt: the XPath context 2614 * @name: the function name 2615 * @ns_uri: the function namespace URI 2616 * 2617 * Search in the Function array of the context for the given 2618 * function. 2619 * 2620 * Returns the xmlXPathFunction or NULL if not found 2621 */ 2622xmlXPathFunction 2623xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2624 const xmlChar *ns_uri) { 2625 if (ctxt == NULL) 2626 return(NULL); 2627 if (name == NULL) 2628 return(NULL); 2629 2630 if (ctxt->funcLookupFunc != NULL) { 2631 xmlXPathFunction ret; 2632 xmlXPathFuncLookupFunc f; 2633 2634 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc; 2635 ret = f(ctxt->funcLookupData, name, ns_uri); 2636 if (ret != NULL) 2637 return(ret); 2638 } 2639 2640 if (ctxt->funcHash == NULL) 2641 return(NULL); 2642 2643 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri)); 2644} 2645 2646/** 2647 * xmlXPathRegisteredFuncsCleanup: 2648 * @ctxt: the XPath context 2649 * 2650 * Cleanup the XPath context data associated to registered functions 2651 */ 2652void 2653xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) { 2654 if (ctxt == NULL) 2655 return; 2656 2657 xmlHashFree(ctxt->funcHash, NULL); 2658 ctxt->funcHash = NULL; 2659} 2660 2661/************************************************************************ 2662 * * 2663 * Routines to handle Variable * 2664 * * 2665 ************************************************************************/ 2666 2667/** 2668 * xmlXPathRegisterVariable: 2669 * @ctxt: the XPath context 2670 * @name: the variable name 2671 * @value: the variable value or NULL 2672 * 2673 * Register a new variable value. If @value is NULL it unregisters 2674 * the variable 2675 * 2676 * Returns 0 in case of success, -1 in case of error 2677 */ 2678int 2679xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name, 2680 xmlXPathObjectPtr value) { 2681 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value)); 2682} 2683 2684/** 2685 * xmlXPathRegisterVariableNS: 2686 * @ctxt: the XPath context 2687 * @name: the variable name 2688 * @ns_uri: the variable namespace URI 2689 * @value: the variable value or NULL 2690 * 2691 * Register a new variable value. If @value is NULL it unregisters 2692 * the variable 2693 * 2694 * Returns 0 in case of success, -1 in case of error 2695 */ 2696int 2697xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2698 const xmlChar *ns_uri, 2699 xmlXPathObjectPtr value) { 2700 if (ctxt == NULL) 2701 return(-1); 2702 if (name == NULL) 2703 return(-1); 2704 2705 if (ctxt->varHash == NULL) 2706 ctxt->varHash = xmlHashCreate(0); 2707 if (ctxt->varHash == NULL) 2708 return(-1); 2709 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri, 2710 (void *) value, 2711 (xmlHashDeallocator)xmlXPathFreeObject)); 2712} 2713 2714/** 2715 * xmlXPathRegisterVariableLookup: 2716 * @ctxt: the XPath context 2717 * @f: the lookup function 2718 * @data: the lookup data 2719 * 2720 * register an external mechanism to do variable lookup 2721 */ 2722void 2723xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt, 2724 xmlXPathVariableLookupFunc f, void *data) { 2725 if (ctxt == NULL) 2726 return; 2727 ctxt->varLookupFunc = (void *) f; 2728 ctxt->varLookupData = data; 2729} 2730 2731/** 2732 * xmlXPathVariableLookup: 2733 * @ctxt: the XPath context 2734 * @name: the variable name 2735 * 2736 * Search in the Variable array of the context for the given 2737 * variable value. 2738 * 2739 * Returns a copy of the value or NULL if not found 2740 */ 2741xmlXPathObjectPtr 2742xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) { 2743 if (ctxt == NULL) 2744 return(NULL); 2745 2746 if (ctxt->varLookupFunc != NULL) { 2747 xmlXPathObjectPtr ret; 2748 2749 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 2750 (ctxt->varLookupData, name, NULL); 2751 return(ret); 2752 } 2753 return(xmlXPathVariableLookupNS(ctxt, name, NULL)); 2754} 2755 2756/** 2757 * xmlXPathVariableLookupNS: 2758 * @ctxt: the XPath context 2759 * @name: the variable name 2760 * @ns_uri: the variable namespace URI 2761 * 2762 * Search in the Variable array of the context for the given 2763 * variable value. 2764 * 2765 * Returns the a copy of the value or NULL if not found 2766 */ 2767xmlXPathObjectPtr 2768xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name, 2769 const xmlChar *ns_uri) { 2770 if (ctxt == NULL) 2771 return(NULL); 2772 2773 if (ctxt->varLookupFunc != NULL) { 2774 xmlXPathObjectPtr ret; 2775 2776 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc) 2777 (ctxt->varLookupData, name, ns_uri); 2778 if (ret != NULL) return(ret); 2779 } 2780 2781 if (ctxt->varHash == NULL) 2782 return(NULL); 2783 if (name == NULL) 2784 return(NULL); 2785 2786 return(xmlXPathObjectCopy((xmlXPathObjectPtr) 2787 xmlHashLookup2(ctxt->varHash, name, ns_uri))); 2788} 2789 2790/** 2791 * xmlXPathRegisteredVariablesCleanup: 2792 * @ctxt: the XPath context 2793 * 2794 * Cleanup the XPath context data associated to registered variables 2795 */ 2796void 2797xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) { 2798 if (ctxt == NULL) 2799 return; 2800 2801 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject); 2802 ctxt->varHash = NULL; 2803} 2804 2805/** 2806 * xmlXPathRegisterNs: 2807 * @ctxt: the XPath context 2808 * @prefix: the namespace prefix 2809 * @ns_uri: the namespace name 2810 * 2811 * Register a new namespace. If @ns_uri is NULL it unregisters 2812 * the namespace 2813 * 2814 * Returns 0 in case of success, -1 in case of error 2815 */ 2816int 2817xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix, 2818 const xmlChar *ns_uri) { 2819 if (ctxt == NULL) 2820 return(-1); 2821 if (prefix == NULL) 2822 return(-1); 2823 2824 if (ctxt->nsHash == NULL) 2825 ctxt->nsHash = xmlHashCreate(10); 2826 if (ctxt->nsHash == NULL) 2827 return(-1); 2828 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri, 2829 (xmlHashDeallocator)xmlFree)); 2830} 2831 2832/** 2833 * xmlXPathNsLookup: 2834 * @ctxt: the XPath context 2835 * @prefix: the namespace prefix value 2836 * 2837 * Search in the namespace declaration array of the context for the given 2838 * namespace name associated to the given prefix 2839 * 2840 * Returns the value or NULL if not found 2841 */ 2842const xmlChar * 2843xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) { 2844 if (ctxt == NULL) 2845 return(NULL); 2846 if (prefix == NULL) 2847 return(NULL); 2848 2849#ifdef XML_XML_NAMESPACE 2850 if (xmlStrEqual(prefix, (const xmlChar *) "xml")) 2851 return(XML_XML_NAMESPACE); 2852#endif 2853 2854 if (ctxt->namespaces != NULL) { 2855 int i; 2856 2857 for (i = 0;i < ctxt->nsNr;i++) { 2858 if ((ctxt->namespaces[i] != NULL) && 2859 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix))) 2860 return(ctxt->namespaces[i]->href); 2861 } 2862 } 2863 2864 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix)); 2865} 2866 2867/** 2868 * xmlXPathRegisteredNsCleanup: 2869 * @ctxt: the XPath context 2870 * 2871 * Cleanup the XPath context data associated to registered variables 2872 */ 2873void 2874xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) { 2875 if (ctxt == NULL) 2876 return; 2877 2878 xmlHashFree(ctxt->nsHash, NULL); 2879 ctxt->nsHash = NULL; 2880} 2881 2882/************************************************************************ 2883 * * 2884 * Routines to handle Values * 2885 * * 2886 ************************************************************************/ 2887 2888/* Allocations are terrible, one need to optimize all this !!! */ 2889 2890/** 2891 * xmlXPathNewFloat: 2892 * @val: the double value 2893 * 2894 * Create a new xmlXPathObjectPtr of type double and of value @val 2895 * 2896 * Returns the newly created object. 2897 */ 2898xmlXPathObjectPtr 2899xmlXPathNewFloat(double val) { 2900 xmlXPathObjectPtr ret; 2901 2902 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2903 if (ret == NULL) { 2904 xmlGenericError(xmlGenericErrorContext, 2905 "xmlXPathNewFloat: out of memory\n"); 2906 return(NULL); 2907 } 2908 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2909 ret->type = XPATH_NUMBER; 2910 ret->floatval = val; 2911 return(ret); 2912} 2913 2914/** 2915 * xmlXPathNewBoolean: 2916 * @val: the boolean value 2917 * 2918 * Create a new xmlXPathObjectPtr of type boolean and of value @val 2919 * 2920 * Returns the newly created object. 2921 */ 2922xmlXPathObjectPtr 2923xmlXPathNewBoolean(int val) { 2924 xmlXPathObjectPtr ret; 2925 2926 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2927 if (ret == NULL) { 2928 xmlGenericError(xmlGenericErrorContext, 2929 "xmlXPathNewBoolean: out of memory\n"); 2930 return(NULL); 2931 } 2932 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2933 ret->type = XPATH_BOOLEAN; 2934 ret->boolval = (val != 0); 2935 return(ret); 2936} 2937 2938/** 2939 * xmlXPathNewString: 2940 * @val: the xmlChar * value 2941 * 2942 * Create a new xmlXPathObjectPtr of type string and of value @val 2943 * 2944 * Returns the newly created object. 2945 */ 2946xmlXPathObjectPtr 2947xmlXPathNewString(const xmlChar *val) { 2948 xmlXPathObjectPtr ret; 2949 2950 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2951 if (ret == NULL) { 2952 xmlGenericError(xmlGenericErrorContext, 2953 "xmlXPathNewString: out of memory\n"); 2954 return(NULL); 2955 } 2956 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2957 ret->type = XPATH_STRING; 2958 if (val != NULL) 2959 ret->stringval = xmlStrdup(val); 2960 else 2961 ret->stringval = xmlStrdup((const xmlChar *)""); 2962 return(ret); 2963} 2964 2965/** 2966 * xmlXPathWrapString: 2967 * @val: the xmlChar * value 2968 * 2969 * Wraps the @val string into an XPath object. 2970 * 2971 * Returns the newly created object. 2972 */ 2973xmlXPathObjectPtr 2974xmlXPathWrapString (xmlChar *val) { 2975 xmlXPathObjectPtr ret; 2976 2977 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 2978 if (ret == NULL) { 2979 xmlGenericError(xmlGenericErrorContext, 2980 "xmlXPathWrapString: out of memory\n"); 2981 return(NULL); 2982 } 2983 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 2984 ret->type = XPATH_STRING; 2985 ret->stringval = val; 2986 return(ret); 2987} 2988 2989/** 2990 * xmlXPathNewCString: 2991 * @val: the char * value 2992 * 2993 * Create a new xmlXPathObjectPtr of type string and of value @val 2994 * 2995 * Returns the newly created object. 2996 */ 2997xmlXPathObjectPtr 2998xmlXPathNewCString(const char *val) { 2999 xmlXPathObjectPtr ret; 3000 3001 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3002 if (ret == NULL) { 3003 xmlGenericError(xmlGenericErrorContext, 3004 "xmlXPathNewCString: out of memory\n"); 3005 return(NULL); 3006 } 3007 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3008 ret->type = XPATH_STRING; 3009 ret->stringval = xmlStrdup(BAD_CAST val); 3010 return(ret); 3011} 3012 3013/** 3014 * xmlXPathWrapCString: 3015 * @val: the char * value 3016 * 3017 * Wraps a string into an XPath object. 3018 * 3019 * Returns the newly created object. 3020 */ 3021xmlXPathObjectPtr 3022xmlXPathWrapCString (char * val) { 3023 return(xmlXPathWrapString((xmlChar *)(val))); 3024} 3025 3026/** 3027 * xmlXPathWrapExternal: 3028 * @val: the user data 3029 * 3030 * Wraps the @val data into an XPath object. 3031 * 3032 * Returns the newly created object. 3033 */ 3034xmlXPathObjectPtr 3035xmlXPathWrapExternal (void *val) { 3036 xmlXPathObjectPtr ret; 3037 3038 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3039 if (ret == NULL) { 3040 xmlGenericError(xmlGenericErrorContext, 3041 "xmlXPathWrapExternal: out of memory\n"); 3042 return(NULL); 3043 } 3044 memset(ret, 0 , (size_t) sizeof(xmlXPathObject)); 3045 ret->type = XPATH_USERS; 3046 ret->user = val; 3047 return(ret); 3048} 3049 3050/** 3051 * xmlXPathObjectCopy: 3052 * @val: the original object 3053 * 3054 * allocate a new copy of a given object 3055 * 3056 * Returns the newly created object. 3057 */ 3058xmlXPathObjectPtr 3059xmlXPathObjectCopy(xmlXPathObjectPtr val) { 3060 xmlXPathObjectPtr ret; 3061 3062 if (val == NULL) 3063 return(NULL); 3064 3065 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject)); 3066 if (ret == NULL) { 3067 xmlGenericError(xmlGenericErrorContext, 3068 "xmlXPathObjectCopy: out of memory\n"); 3069 return(NULL); 3070 } 3071 memcpy(ret, val , (size_t) sizeof(xmlXPathObject)); 3072 switch (val->type) { 3073 case XPATH_BOOLEAN: 3074 case XPATH_NUMBER: 3075 case XPATH_POINT: 3076 case XPATH_RANGE: 3077 break; 3078 case XPATH_STRING: 3079 ret->stringval = xmlStrdup(val->stringval); 3080 break; 3081 case XPATH_XSLT_TREE: 3082 if ((val->nodesetval != NULL) && 3083 (val->nodesetval->nodeTab != NULL)) { 3084 ret->boolval = 1; 3085 ret->user = xmlDocCopyNode(val->nodesetval->nodeTab[0], 3086 val->nodesetval->nodeTab[0]->doc, 1); 3087 ret->nodesetval = xmlXPathNodeSetCreate( 3088 (xmlNodePtr) ret->user); 3089 } else 3090 ret->nodesetval = xmlXPathNodeSetCreate(NULL); 3091 /* Deallocate the copied tree value */ 3092 break; 3093 case XPATH_NODESET: 3094 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval); 3095 /* Do not deallocate the copied tree value */ 3096 ret->boolval = 0; 3097 break; 3098 case XPATH_LOCATIONSET: 3099#ifdef LIBXML_XPTR_ENABLED 3100 { 3101 xmlLocationSetPtr loc = val->user; 3102 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc); 3103 break; 3104 } 3105#endif 3106 case XPATH_USERS: 3107 ret->user = val->user; 3108 break; 3109 case XPATH_UNDEFINED: 3110 xmlGenericError(xmlGenericErrorContext, 3111 "xmlXPathObjectCopy: unsupported type %d\n", 3112 val->type); 3113 break; 3114 } 3115 return(ret); 3116} 3117 3118/** 3119 * xmlXPathFreeObject: 3120 * @obj: the object to free 3121 * 3122 * Free up an xmlXPathObjectPtr object. 3123 */ 3124void 3125xmlXPathFreeObject(xmlXPathObjectPtr obj) { 3126 if (obj == NULL) return; 3127 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) { 3128 if (obj->boolval) { 3129 if (obj->user != NULL) { 3130 xmlXPathFreeNodeSet(obj->nodesetval); 3131 xmlFreeNodeList((xmlNodePtr) obj->user); 3132 } else if (obj->nodesetval != NULL) 3133 xmlXPathFreeValueTree(obj->nodesetval); 3134 } else { 3135 if (obj->nodesetval != NULL) 3136 xmlXPathFreeNodeSet(obj->nodesetval); 3137 } 3138#ifdef LIBXML_XPTR_ENABLED 3139 } else if (obj->type == XPATH_LOCATIONSET) { 3140 if (obj->user != NULL) 3141 xmlXPtrFreeLocationSet(obj->user); 3142#endif 3143 } else if (obj->type == XPATH_STRING) { 3144 if (obj->stringval != NULL) 3145 xmlFree(obj->stringval); 3146 } 3147 3148 xmlFree(obj); 3149} 3150 3151 3152/************************************************************************ 3153 * * 3154 * Type Casting Routines * 3155 * * 3156 ************************************************************************/ 3157 3158/** 3159 * xmlXPathCastBooleanToString: 3160 * @val: a boolean 3161 * 3162 * Converts a boolean to its string value. 3163 * 3164 * Returns a newly allocated string. 3165 */ 3166xmlChar * 3167xmlXPathCastBooleanToString (int val) { 3168 xmlChar *ret; 3169 if (val) 3170 ret = xmlStrdup((const xmlChar *) "true"); 3171 else 3172 ret = xmlStrdup((const xmlChar *) "false"); 3173 return(ret); 3174} 3175 3176/** 3177 * xmlXPathCastNumberToString: 3178 * @val: a number 3179 * 3180 * Converts a number to its string value. 3181 * 3182 * Returns a newly allocated string. 3183 */ 3184xmlChar * 3185xmlXPathCastNumberToString (double val) { 3186 xmlChar *ret; 3187 switch (xmlXPathIsInf(val)) { 3188 case 1: 3189 ret = xmlStrdup((const xmlChar *) "Infinity"); 3190 break; 3191 case -1: 3192 ret = xmlStrdup((const xmlChar *) "-Infinity"); 3193 break; 3194 default: 3195 if (xmlXPathIsNaN(val)) { 3196 ret = xmlStrdup((const xmlChar *) "NaN"); 3197 } else if (val == 0 && xmlXPathGetSign(val) != 0) { 3198 ret = xmlStrdup((const xmlChar *) "0"); 3199 } else { 3200 /* could be improved */ 3201 char buf[100]; 3202 xmlXPathFormatNumber(val, buf, 100); 3203 ret = xmlStrdup((const xmlChar *) buf); 3204 } 3205 } 3206 return(ret); 3207} 3208 3209/** 3210 * xmlXPathCastNodeToString: 3211 * @node: a node 3212 * 3213 * Converts a node to its string value. 3214 * 3215 * Returns a newly allocated string. 3216 */ 3217xmlChar * 3218xmlXPathCastNodeToString (xmlNodePtr node) { 3219 if ((node != NULL) && (node->type == XML_DOCUMENT_NODE)) 3220 node = xmlDocGetRootElement((xmlDocPtr) node); 3221 return(xmlNodeGetContent(node)); 3222} 3223 3224/** 3225 * xmlXPathCastNodeSetToString: 3226 * @ns: a node-set 3227 * 3228 * Converts a node-set to its string value. 3229 * 3230 * Returns a newly allocated string. 3231 */ 3232xmlChar * 3233xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) { 3234 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL)) 3235 return(xmlStrdup((const xmlChar *) "")); 3236 3237 xmlXPathNodeSetSort(ns); 3238 return(xmlXPathCastNodeToString(ns->nodeTab[0])); 3239} 3240 3241/** 3242 * xmlXPathCastToString: 3243 * @val: an XPath object 3244 * 3245 * Converts an existing object to its string() equivalent 3246 * 3247 * Returns the string value of the object, NULL in case of error. 3248 * A new string is allocated only if needed (@val isn't a 3249 * string object). 3250 */ 3251xmlChar * 3252xmlXPathCastToString(xmlXPathObjectPtr val) { 3253 xmlChar *ret = NULL; 3254 3255 if (val == NULL) 3256 return(xmlStrdup((const xmlChar *) "")); 3257 switch (val->type) { 3258 case XPATH_UNDEFINED: 3259#ifdef DEBUG_EXPR 3260 xmlGenericError(xmlGenericErrorContext, "String: undefined\n"); 3261#endif 3262 ret = xmlStrdup((const xmlChar *) ""); 3263 break; 3264 case XPATH_XSLT_TREE: 3265 case XPATH_NODESET: 3266 ret = xmlXPathCastNodeSetToString(val->nodesetval); 3267 break; 3268 case XPATH_STRING: 3269 return(xmlStrdup(val->stringval)); 3270 case XPATH_BOOLEAN: 3271 ret = xmlXPathCastBooleanToString(val->boolval); 3272 break; 3273 case XPATH_NUMBER: { 3274 ret = xmlXPathCastNumberToString(val->floatval); 3275 break; 3276 } 3277 case XPATH_USERS: 3278 case XPATH_POINT: 3279 case XPATH_RANGE: 3280 case XPATH_LOCATIONSET: 3281 TODO 3282 ret = xmlStrdup((const xmlChar *) ""); 3283 break; 3284 } 3285 return(ret); 3286} 3287 3288/** 3289 * xmlXPathConvertString: 3290 * @val: an XPath object 3291 * 3292 * Converts an existing object to its string() equivalent 3293 * 3294 * Returns the new object, the old one is freed (or the operation 3295 * is done directly on @val) 3296 */ 3297xmlXPathObjectPtr 3298xmlXPathConvertString(xmlXPathObjectPtr val) { 3299 xmlChar *res = NULL; 3300 3301 if (val == NULL) 3302 return(xmlXPathNewCString("")); 3303 3304 switch (val->type) { 3305 case XPATH_UNDEFINED: 3306#ifdef DEBUG_EXPR 3307 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n"); 3308#endif 3309 break; 3310 case XPATH_XSLT_TREE: 3311 case XPATH_NODESET: 3312 res = xmlXPathCastNodeSetToString(val->nodesetval); 3313 break; 3314 case XPATH_STRING: 3315 return(val); 3316 case XPATH_BOOLEAN: 3317 res = xmlXPathCastBooleanToString(val->boolval); 3318 break; 3319 case XPATH_NUMBER: 3320 res = xmlXPathCastNumberToString(val->floatval); 3321 break; 3322 case XPATH_USERS: 3323 case XPATH_POINT: 3324 case XPATH_RANGE: 3325 case XPATH_LOCATIONSET: 3326 TODO; 3327 break; 3328 } 3329 xmlXPathFreeObject(val); 3330 if (res == NULL) 3331 return(xmlXPathNewCString("")); 3332 return(xmlXPathWrapString(res)); 3333} 3334 3335/** 3336 * xmlXPathCastBooleanToNumber: 3337 * @val: a boolean 3338 * 3339 * Converts a boolean to its number value 3340 * 3341 * Returns the number value 3342 */ 3343double 3344xmlXPathCastBooleanToNumber(int val) { 3345 if (val) 3346 return(1.0); 3347 return(0.0); 3348} 3349 3350/** 3351 * xmlXPathCastStringToNumber: 3352 * @val: a string 3353 * 3354 * Converts a string to its number value 3355 * 3356 * Returns the number value 3357 */ 3358double 3359xmlXPathCastStringToNumber(const xmlChar * val) { 3360 return(xmlXPathStringEvalNumber(val)); 3361} 3362 3363/** 3364 * xmlXPathCastNodeToNumber: 3365 * @node: a node 3366 * 3367 * Converts a node to its number value 3368 * 3369 * Returns the number value 3370 */ 3371double 3372xmlXPathCastNodeToNumber (xmlNodePtr node) { 3373 xmlChar *strval; 3374 double ret; 3375 3376 if (node == NULL) 3377 return(xmlXPathNAN); 3378 strval = xmlXPathCastNodeToString(node); 3379 if (strval == NULL) 3380 return(xmlXPathNAN); 3381 ret = xmlXPathCastStringToNumber(strval); 3382 xmlFree(strval); 3383 3384 return(ret); 3385} 3386 3387/** 3388 * xmlXPathCastNodeSetToNumber: 3389 * @ns: a node-set 3390 * 3391 * Converts a node-set to its number value 3392 * 3393 * Returns the number value 3394 */ 3395double 3396xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) { 3397 xmlChar *str; 3398 double ret; 3399 3400 if (ns == NULL) 3401 return(xmlXPathNAN); 3402 str = xmlXPathCastNodeSetToString(ns); 3403 ret = xmlXPathCastStringToNumber(str); 3404 xmlFree(str); 3405 return(ret); 3406} 3407 3408/** 3409 * xmlXPathCastToNumber: 3410 * @val: an XPath object 3411 * 3412 * Converts an XPath object to its number value 3413 * 3414 * Returns the number value 3415 */ 3416double 3417xmlXPathCastToNumber(xmlXPathObjectPtr val) { 3418 double ret = 0.0; 3419 3420 if (val == NULL) 3421 return(xmlXPathNAN); 3422 switch (val->type) { 3423 case XPATH_UNDEFINED: 3424#ifdef DEGUB_EXPR 3425 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n"); 3426#endif 3427 ret = xmlXPathNAN; 3428 break; 3429 case XPATH_XSLT_TREE: 3430 case XPATH_NODESET: 3431 ret = xmlXPathCastNodeSetToNumber(val->nodesetval); 3432 break; 3433 case XPATH_STRING: 3434 ret = xmlXPathCastStringToNumber(val->stringval); 3435 break; 3436 case XPATH_NUMBER: 3437 ret = val->floatval; 3438 break; 3439 case XPATH_BOOLEAN: 3440 ret = xmlXPathCastBooleanToNumber(val->boolval); 3441 break; 3442 case XPATH_USERS: 3443 case XPATH_POINT: 3444 case XPATH_RANGE: 3445 case XPATH_LOCATIONSET: 3446 TODO; 3447 ret = xmlXPathNAN; 3448 break; 3449 } 3450 return(ret); 3451} 3452 3453/** 3454 * xmlXPathConvertNumber: 3455 * @val: an XPath object 3456 * 3457 * Converts an existing object to its number() equivalent 3458 * 3459 * Returns the new object, the old one is freed (or the operation 3460 * is done directly on @val) 3461 */ 3462xmlXPathObjectPtr 3463xmlXPathConvertNumber(xmlXPathObjectPtr val) { 3464 xmlXPathObjectPtr ret; 3465 3466 if (val == NULL) 3467 return(xmlXPathNewFloat(0.0)); 3468 if (val->type == XPATH_NUMBER) 3469 return(val); 3470 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val)); 3471 xmlXPathFreeObject(val); 3472 return(ret); 3473} 3474 3475/** 3476 * xmlXPathCastNumberToBoolean: 3477 * @val: a number 3478 * 3479 * Converts a number to its boolean value 3480 * 3481 * Returns the boolean value 3482 */ 3483int 3484xmlXPathCastNumberToBoolean (double val) { 3485 if (xmlXPathIsNaN(val) || (val == 0.0)) 3486 return(0); 3487 return(1); 3488} 3489 3490/** 3491 * xmlXPathCastStringToBoolean: 3492 * @val: a string 3493 * 3494 * Converts a string to its boolean value 3495 * 3496 * Returns the boolean value 3497 */ 3498int 3499xmlXPathCastStringToBoolean (const xmlChar *val) { 3500 if ((val == NULL) || (xmlStrlen(val) == 0)) 3501 return(0); 3502 return(1); 3503} 3504 3505/** 3506 * xmlXPathCastNodeSetToBoolean: 3507 * @ns: a node-set 3508 * 3509 * Converts a node-set to its boolean value 3510 * 3511 * Returns the boolean value 3512 */ 3513int 3514xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) { 3515 if ((ns == NULL) || (ns->nodeNr == 0)) 3516 return(0); 3517 return(1); 3518} 3519 3520/** 3521 * xmlXPathCastToBoolean: 3522 * @val: an XPath object 3523 * 3524 * Converts an XPath object to its boolean value 3525 * 3526 * Returns the boolean value 3527 */ 3528int 3529xmlXPathCastToBoolean (xmlXPathObjectPtr val) { 3530 int ret = 0; 3531 3532 if (val == NULL) 3533 return(0); 3534 switch (val->type) { 3535 case XPATH_UNDEFINED: 3536#ifdef DEBUG_EXPR 3537 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n"); 3538#endif 3539 ret = 0; 3540 break; 3541 case XPATH_XSLT_TREE: 3542 case XPATH_NODESET: 3543 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval); 3544 break; 3545 case XPATH_STRING: 3546 ret = xmlXPathCastStringToBoolean(val->stringval); 3547 break; 3548 case XPATH_NUMBER: 3549 ret = xmlXPathCastNumberToBoolean(val->floatval); 3550 break; 3551 case XPATH_BOOLEAN: 3552 ret = val->boolval; 3553 break; 3554 case XPATH_USERS: 3555 case XPATH_POINT: 3556 case XPATH_RANGE: 3557 case XPATH_LOCATIONSET: 3558 TODO; 3559 ret = 0; 3560 break; 3561 } 3562 return(ret); 3563} 3564 3565 3566/** 3567 * xmlXPathConvertBoolean: 3568 * @val: an XPath object 3569 * 3570 * Converts an existing object to its boolean() equivalent 3571 * 3572 * Returns the new object, the old one is freed (or the operation 3573 * is done directly on @val) 3574 */ 3575xmlXPathObjectPtr 3576xmlXPathConvertBoolean(xmlXPathObjectPtr val) { 3577 xmlXPathObjectPtr ret; 3578 3579 if (val == NULL) 3580 return(xmlXPathNewBoolean(0)); 3581 if (val->type == XPATH_BOOLEAN) 3582 return(val); 3583 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val)); 3584 xmlXPathFreeObject(val); 3585 return(ret); 3586} 3587 3588/************************************************************************ 3589 * * 3590 * Routines to handle XPath contexts * 3591 * * 3592 ************************************************************************/ 3593 3594/** 3595 * xmlXPathNewContext: 3596 * @doc: the XML document 3597 * 3598 * Create a new xmlXPathContext 3599 * 3600 * Returns the xmlXPathContext just allocated. The caller will need to free it. 3601 */ 3602xmlXPathContextPtr 3603xmlXPathNewContext(xmlDocPtr doc) { 3604 xmlXPathContextPtr ret; 3605 3606 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext)); 3607 if (ret == NULL) { 3608 xmlGenericError(xmlGenericErrorContext, 3609 "xmlXPathNewContext: out of memory\n"); 3610 return(NULL); 3611 } 3612 memset(ret, 0 , (size_t) sizeof(xmlXPathContext)); 3613 ret->doc = doc; 3614 ret->node = NULL; 3615 3616 ret->varHash = NULL; 3617 3618 ret->nb_types = 0; 3619 ret->max_types = 0; 3620 ret->types = NULL; 3621 3622 ret->funcHash = xmlHashCreate(0); 3623 3624 ret->nb_axis = 0; 3625 ret->max_axis = 0; 3626 ret->axis = NULL; 3627 3628 ret->nsHash = NULL; 3629 ret->user = NULL; 3630 3631 ret->contextSize = -1; 3632 ret->proximityPosition = -1; 3633 3634 xmlXPathRegisterAllFunctions(ret); 3635 3636 return(ret); 3637} 3638 3639/** 3640 * xmlXPathFreeContext: 3641 * @ctxt: the context to free 3642 * 3643 * Free up an xmlXPathContext 3644 */ 3645void 3646xmlXPathFreeContext(xmlXPathContextPtr ctxt) { 3647 xmlXPathRegisteredNsCleanup(ctxt); 3648 xmlXPathRegisteredFuncsCleanup(ctxt); 3649 xmlXPathRegisteredVariablesCleanup(ctxt); 3650 xmlFree(ctxt); 3651} 3652 3653/************************************************************************ 3654 * * 3655 * Routines to handle XPath parser contexts * 3656 * * 3657 ************************************************************************/ 3658 3659#define CHECK_CTXT(ctxt) \ 3660 if (ctxt == NULL) { \ 3661 xmlGenericError(xmlGenericErrorContext, \ 3662 "%s:%d Internal error: ctxt == NULL\n", \ 3663 __FILE__, __LINE__); \ 3664 } \ 3665 3666 3667#define CHECK_CONTEXT(ctxt) \ 3668 if (ctxt == NULL) { \ 3669 xmlGenericError(xmlGenericErrorContext, \ 3670 "%s:%d Internal error: no context\n", \ 3671 __FILE__, __LINE__); \ 3672 } \ 3673 else if (ctxt->doc == NULL) { \ 3674 xmlGenericError(xmlGenericErrorContext, \ 3675 "%s:%d Internal error: no document\n", \ 3676 __FILE__, __LINE__); \ 3677 } \ 3678 else if (ctxt->doc->children == NULL) { \ 3679 xmlGenericError(xmlGenericErrorContext, \ 3680 "%s:%d Internal error: document without root\n", \ 3681 __FILE__, __LINE__); \ 3682 } \ 3683 3684 3685/** 3686 * xmlXPathNewParserContext: 3687 * @str: the XPath expression 3688 * @ctxt: the XPath context 3689 * 3690 * Create a new xmlXPathParserContext 3691 * 3692 * Returns the xmlXPathParserContext just allocated. 3693 */ 3694xmlXPathParserContextPtr 3695xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) { 3696 xmlXPathParserContextPtr ret; 3697 3698 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 3699 if (ret == NULL) { 3700 xmlGenericError(xmlGenericErrorContext, 3701 "xmlXPathNewParserContext: out of memory\n"); 3702 return(NULL); 3703 } 3704 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 3705 ret->cur = ret->base = str; 3706 ret->context = ctxt; 3707 3708 ret->comp = xmlXPathNewCompExpr(); 3709 if (ret->comp == NULL) { 3710 xmlFree(ret->valueTab); 3711 xmlFree(ret); 3712 return(NULL); 3713 } 3714 3715 return(ret); 3716} 3717 3718/** 3719 * xmlXPathCompParserContext: 3720 * @comp: the XPath compiled expression 3721 * @ctxt: the XPath context 3722 * 3723 * Create a new xmlXPathParserContext when processing a compiled expression 3724 * 3725 * Returns the xmlXPathParserContext just allocated. 3726 */ 3727static xmlXPathParserContextPtr 3728xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) { 3729 xmlXPathParserContextPtr ret; 3730 3731 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext)); 3732 if (ret == NULL) { 3733 xmlGenericError(xmlGenericErrorContext, 3734 "xmlXPathCompParserContext: out of memory\n"); 3735 return(NULL); 3736 } 3737 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext)); 3738 3739 /* Allocate the value stack */ 3740 ret->valueTab = (xmlXPathObjectPtr *) 3741 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 3742 if (ret->valueTab == NULL) { 3743 xmlFree(ret); 3744 xmlGenericError(xmlGenericErrorContext, 3745 "xmlXPathCompParserContext: out of memory\n"); 3746 return(NULL); 3747 } 3748 ret->valueNr = 0; 3749 ret->valueMax = 10; 3750 ret->value = NULL; 3751 3752 ret->context = ctxt; 3753 ret->comp = comp; 3754 3755 return(ret); 3756} 3757 3758/** 3759 * xmlXPathFreeParserContext: 3760 * @ctxt: the context to free 3761 * 3762 * Free up an xmlXPathParserContext 3763 */ 3764void 3765xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) { 3766 if (ctxt->valueTab != NULL) { 3767 xmlFree(ctxt->valueTab); 3768 } 3769 if (ctxt->comp) 3770 xmlXPathFreeCompExpr(ctxt->comp); 3771 xmlFree(ctxt); 3772} 3773 3774/************************************************************************ 3775 * * 3776 * The implicit core function library * 3777 * * 3778 ************************************************************************/ 3779 3780/** 3781 * xmlXPathNodeStringHash: 3782 * @node: a node pointer 3783 * 3784 * Function computing the beginning of the string value of the node, 3785 * used to speed up comparisons 3786 * 3787 * Returns an int usable as a hash 3788 */ 3789static unsigned int 3790xmlXPathNodeValHash(xmlNodePtr node) { 3791 int len = 2; 3792 const xmlChar * string = NULL; 3793 xmlNodePtr tmp = NULL; 3794 unsigned int ret = 0; 3795 3796 if (node == NULL) 3797 return(0); 3798 3799 3800 switch (node->type) { 3801 case XML_COMMENT_NODE: 3802 case XML_PI_NODE: 3803 case XML_CDATA_SECTION_NODE: 3804 case XML_TEXT_NODE: 3805 string = node->content; 3806 if (string == NULL) 3807 return(0); 3808 if (string[0] == 0) 3809 return(0); 3810 return(((unsigned int) string[0]) + 3811 (((unsigned int) string[1]) << 8)); 3812 case XML_NAMESPACE_DECL: 3813 string = ((xmlNsPtr)node)->href; 3814 if (string == NULL) 3815 return(0); 3816 if (string[0] == 0) 3817 return(0); 3818 return(((unsigned int) string[0]) + 3819 (((unsigned int) string[1]) << 8)); 3820 case XML_ATTRIBUTE_NODE: 3821 tmp = ((xmlAttrPtr) node)->children; 3822 break; 3823 case XML_ELEMENT_NODE: 3824 tmp = node->children; 3825 break; 3826 default: 3827 return(0); 3828 } 3829 while (tmp != NULL) { 3830 switch (tmp->type) { 3831 case XML_COMMENT_NODE: 3832 case XML_PI_NODE: 3833 case XML_CDATA_SECTION_NODE: 3834 case XML_TEXT_NODE: 3835 string = tmp->content; 3836 break; 3837 case XML_NAMESPACE_DECL: 3838 string = ((xmlNsPtr)tmp)->href; 3839 break; 3840 default: 3841 break; 3842 } 3843 if ((string != NULL) && (string[0] != 0)) { 3844 if (string[0] == 0) 3845 return(0); 3846 if (len == 1) { 3847 return(ret + (((unsigned int) string[0]) << 8)); 3848 } 3849 if (string[1] == 0) { 3850 len = 1; 3851 ret = (unsigned int) string[0]; 3852 } else { 3853 return(((unsigned int) string[0]) + 3854 (((unsigned int) string[1]) << 8)); 3855 } 3856 } 3857 /* 3858 * Skip to next node 3859 */ 3860 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) { 3861 if (tmp->children->type != XML_ENTITY_DECL) { 3862 tmp = tmp->children; 3863 continue; 3864 } 3865 } 3866 if (tmp == node) 3867 break; 3868 3869 if (tmp->next != NULL) { 3870 tmp = tmp->next; 3871 continue; 3872 } 3873 3874 do { 3875 tmp = tmp->parent; 3876 if (tmp == NULL) 3877 break; 3878 if (tmp == node) { 3879 tmp = NULL; 3880 break; 3881 } 3882 if (tmp->next != NULL) { 3883 tmp = tmp->next; 3884 break; 3885 } 3886 } while (tmp != NULL); 3887 } 3888 return(ret); 3889} 3890 3891/** 3892 * xmlXPathStringHash: 3893 * @string: a string 3894 * 3895 * Function computing the beginning of the string value of the node, 3896 * used to speed up comparisons 3897 * 3898 * Returns an int usable as a hash 3899 */ 3900static unsigned int 3901xmlXPathStringHash(const xmlChar * string) { 3902 if (string == NULL) 3903 return((unsigned int) 0); 3904 if (string[0] == 0) 3905 return(0); 3906 return(((unsigned int) string[0]) + 3907 (((unsigned int) string[1]) << 8)); 3908} 3909 3910/** 3911 * xmlXPathCompareNodeSetFloat: 3912 * @ctxt: the XPath Parser context 3913 * @inf: less than (1) or greater than (0) 3914 * @strict: is the comparison strict 3915 * @arg: the node set 3916 * @f: the value 3917 * 3918 * Implement the compare operation between a nodeset and a number 3919 * @ns < @val (1, 1, ... 3920 * @ns <= @val (1, 0, ... 3921 * @ns > @val (0, 1, ... 3922 * @ns >= @val (0, 0, ... 3923 * 3924 * If one object to be compared is a node-set and the other is a number, 3925 * then the comparison will be true if and only if there is a node in the 3926 * node-set such that the result of performing the comparison on the number 3927 * to be compared and on the result of converting the string-value of that 3928 * node to a number using the number function is true. 3929 * 3930 * Returns 0 or 1 depending on the results of the test. 3931 */ 3932static int 3933xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict, 3934 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) { 3935 int i, ret = 0; 3936 xmlNodeSetPtr ns; 3937 xmlChar *str2; 3938 3939 if ((f == NULL) || (arg == NULL) || 3940 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 3941 xmlXPathFreeObject(arg); 3942 xmlXPathFreeObject(f); 3943 return(0); 3944 } 3945 ns = arg->nodesetval; 3946 if (ns != NULL) { 3947 for (i = 0;i < ns->nodeNr;i++) { 3948 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 3949 if (str2 != NULL) { 3950 valuePush(ctxt, 3951 xmlXPathNewString(str2)); 3952 xmlFree(str2); 3953 xmlXPathNumberFunction(ctxt, 1); 3954 valuePush(ctxt, xmlXPathObjectCopy(f)); 3955 ret = xmlXPathCompareValues(ctxt, inf, strict); 3956 if (ret) 3957 break; 3958 } 3959 } 3960 } 3961 xmlXPathFreeObject(arg); 3962 xmlXPathFreeObject(f); 3963 return(ret); 3964} 3965 3966/** 3967 * xmlXPathCompareNodeSetString: 3968 * @ctxt: the XPath Parser context 3969 * @inf: less than (1) or greater than (0) 3970 * @strict: is the comparison strict 3971 * @arg: the node set 3972 * @s: the value 3973 * 3974 * Implement the compare operation between a nodeset and a string 3975 * @ns < @val (1, 1, ... 3976 * @ns <= @val (1, 0, ... 3977 * @ns > @val (0, 1, ... 3978 * @ns >= @val (0, 0, ... 3979 * 3980 * If one object to be compared is a node-set and the other is a string, 3981 * then the comparison will be true if and only if there is a node in 3982 * the node-set such that the result of performing the comparison on the 3983 * string-value of the node and the other string is true. 3984 * 3985 * Returns 0 or 1 depending on the results of the test. 3986 */ 3987static int 3988xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict, 3989 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) { 3990 int i, ret = 0; 3991 xmlNodeSetPtr ns; 3992 xmlChar *str2; 3993 3994 if ((s == NULL) || (arg == NULL) || 3995 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) { 3996 xmlXPathFreeObject(arg); 3997 xmlXPathFreeObject(s); 3998 return(0); 3999 } 4000 ns = arg->nodesetval; 4001 if (ns != NULL) { 4002 for (i = 0;i < ns->nodeNr;i++) { 4003 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]); 4004 if (str2 != NULL) { 4005 valuePush(ctxt, 4006 xmlXPathNewString(str2)); 4007 xmlFree(str2); 4008 valuePush(ctxt, xmlXPathObjectCopy(s)); 4009 ret = xmlXPathCompareValues(ctxt, inf, strict); 4010 if (ret) 4011 break; 4012 } 4013 } 4014 } 4015 xmlXPathFreeObject(arg); 4016 xmlXPathFreeObject(s); 4017 return(ret); 4018} 4019 4020/** 4021 * xmlXPathCompareNodeSets: 4022 * @inf: less than (1) or greater than (0) 4023 * @strict: is the comparison strict 4024 * @arg1: the first node set object 4025 * @arg2: the second node set object 4026 * 4027 * Implement the compare operation on nodesets: 4028 * 4029 * If both objects to be compared are node-sets, then the comparison 4030 * will be true if and only if there is a node in the first node-set 4031 * and a node in the second node-set such that the result of performing 4032 * the comparison on the string-values of the two nodes is true. 4033 * .... 4034 * When neither object to be compared is a node-set and the operator 4035 * is <=, <, >= or >, then the objects are compared by converting both 4036 * objects to numbers and comparing the numbers according to IEEE 754. 4037 * .... 4038 * The number function converts its argument to a number as follows: 4039 * - a string that consists of optional whitespace followed by an 4040 * optional minus sign followed by a Number followed by whitespace 4041 * is converted to the IEEE 754 number that is nearest (according 4042 * to the IEEE 754 round-to-nearest rule) to the mathematical value 4043 * represented by the string; any other string is converted to NaN 4044 * 4045 * Conclusion all nodes need to be converted first to their string value 4046 * and then the comparison must be done when possible 4047 */ 4048static int 4049xmlXPathCompareNodeSets(int inf, int strict, 4050 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 4051 int i, j, init = 0; 4052 double val1; 4053 double *values2; 4054 int ret = 0; 4055 xmlNodeSetPtr ns1; 4056 xmlNodeSetPtr ns2; 4057 4058 if ((arg1 == NULL) || 4059 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) { 4060 xmlXPathFreeObject(arg2); 4061 return(0); 4062 } 4063 if ((arg2 == NULL) || 4064 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) { 4065 xmlXPathFreeObject(arg1); 4066 xmlXPathFreeObject(arg2); 4067 return(0); 4068 } 4069 4070 ns1 = arg1->nodesetval; 4071 ns2 = arg2->nodesetval; 4072 4073 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) { 4074 xmlXPathFreeObject(arg1); 4075 xmlXPathFreeObject(arg2); 4076 return(0); 4077 } 4078 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) { 4079 xmlXPathFreeObject(arg1); 4080 xmlXPathFreeObject(arg2); 4081 return(0); 4082 } 4083 4084 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double)); 4085 if (values2 == NULL) { 4086 xmlXPathFreeObject(arg1); 4087 xmlXPathFreeObject(arg2); 4088 return(0); 4089 } 4090 for (i = 0;i < ns1->nodeNr;i++) { 4091 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]); 4092 if (xmlXPathIsNaN(val1)) 4093 continue; 4094 for (j = 0;j < ns2->nodeNr;j++) { 4095 if (init == 0) { 4096 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]); 4097 } 4098 if (xmlXPathIsNaN(values2[j])) 4099 continue; 4100 if (inf && strict) 4101 ret = (val1 < values2[j]); 4102 else if (inf && !strict) 4103 ret = (val1 <= values2[j]); 4104 else if (!inf && strict) 4105 ret = (val1 > values2[j]); 4106 else if (!inf && !strict) 4107 ret = (val1 >= values2[j]); 4108 if (ret) 4109 break; 4110 } 4111 if (ret) 4112 break; 4113 init = 1; 4114 } 4115 xmlFree(values2); 4116 xmlXPathFreeObject(arg1); 4117 xmlXPathFreeObject(arg2); 4118 return(ret); 4119} 4120 4121/** 4122 * xmlXPathCompareNodeSetValue: 4123 * @ctxt: the XPath Parser context 4124 * @inf: less than (1) or greater than (0) 4125 * @strict: is the comparison strict 4126 * @arg: the node set 4127 * @val: the value 4128 * 4129 * Implement the compare operation between a nodeset and a value 4130 * @ns < @val (1, 1, ... 4131 * @ns <= @val (1, 0, ... 4132 * @ns > @val (0, 1, ... 4133 * @ns >= @val (0, 0, ... 4134 * 4135 * If one object to be compared is a node-set and the other is a boolean, 4136 * then the comparison will be true if and only if the result of performing 4137 * the comparison on the boolean and on the result of converting 4138 * the node-set to a boolean using the boolean function is true. 4139 * 4140 * Returns 0 or 1 depending on the results of the test. 4141 */ 4142static int 4143xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict, 4144 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) { 4145 if ((val == NULL) || (arg == NULL) || 4146 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 4147 return(0); 4148 4149 switch(val->type) { 4150 case XPATH_NUMBER: 4151 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val)); 4152 case XPATH_NODESET: 4153 case XPATH_XSLT_TREE: 4154 return(xmlXPathCompareNodeSets(inf, strict, arg, val)); 4155 case XPATH_STRING: 4156 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val)); 4157 case XPATH_BOOLEAN: 4158 valuePush(ctxt, arg); 4159 xmlXPathBooleanFunction(ctxt, 1); 4160 valuePush(ctxt, val); 4161 return(xmlXPathCompareValues(ctxt, inf, strict)); 4162 default: 4163 TODO 4164 } 4165 return(0); 4166} 4167 4168/** 4169 * xmlXPathEqualNodeSetString 4170 * @arg: the nodeset object argument 4171 * @str: the string to compare to. 4172 * 4173 * Implement the equal operation on XPath objects content: @arg1 == @arg2 4174 * If one object to be compared is a node-set and the other is a string, 4175 * then the comparison will be true if and only if there is a node in 4176 * the node-set such that the result of performing the comparison on the 4177 * string-value of the node and the other string is true. 4178 * 4179 * Returns 0 or 1 depending on the results of the test. 4180 */ 4181static int 4182xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str) 4183{ 4184 int i; 4185 xmlNodeSetPtr ns; 4186 xmlChar *str2; 4187 unsigned int hash; 4188 4189 if ((str == NULL) || (arg == NULL) || 4190 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 4191 return (0); 4192 ns = arg->nodesetval; 4193 hash = xmlXPathStringHash(str); 4194 if (ns == NULL) 4195 return (0); 4196 if (ns->nodeNr <= 0) { 4197 if (hash == 0) 4198 return(1); 4199 return(0); 4200 } 4201 for (i = 0; i < ns->nodeNr; i++) { 4202 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) { 4203 str2 = xmlNodeGetContent(ns->nodeTab[i]); 4204 if ((str2 != NULL) && (xmlStrEqual(str, str2))) { 4205 xmlFree(str2); 4206 return (1); 4207 } 4208 if (str2 != NULL) 4209 xmlFree(str2); 4210 } 4211 } 4212 return (0); 4213} 4214 4215/** 4216 * xmlXPathEqualNodeSetFloat 4217 * @arg: the nodeset object argument 4218 * @f: the float to compare to 4219 * 4220 * Implement the equal operation on XPath objects content: @arg1 == @arg2 4221 * If one object to be compared is a node-set and the other is a number, 4222 * then the comparison will be true if and only if there is a node in 4223 * the node-set such that the result of performing the comparison on the 4224 * number to be compared and on the result of converting the string-value 4225 * of that node to a number using the number function is true. 4226 * 4227 * Returns 0 or 1 depending on the results of the test. 4228 */ 4229static int 4230xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) { 4231 char buf[100] = ""; 4232 4233 if ((arg == NULL) || 4234 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) 4235 return(0); 4236 4237 xmlXPathFormatNumber(f, buf, sizeof(buf)); 4238 return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf)); 4239} 4240 4241 4242/** 4243 * xmlXPathEqualNodeSets 4244 * @arg1: first nodeset object argument 4245 * @arg2: second nodeset object argument 4246 * 4247 * Implement the equal operation on XPath nodesets: @arg1 == @arg2 4248 * If both objects to be compared are node-sets, then the comparison 4249 * will be true if and only if there is a node in the first node-set and 4250 * a node in the second node-set such that the result of performing the 4251 * comparison on the string-values of the two nodes is true. 4252 * 4253 * (needless to say, this is a costly operation) 4254 * 4255 * Returns 0 or 1 depending on the results of the test. 4256 */ 4257static int 4258xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) { 4259 int i, j; 4260 unsigned int *hashs1; 4261 unsigned int *hashs2; 4262 xmlChar **values1; 4263 xmlChar **values2; 4264 int ret = 0; 4265 xmlNodeSetPtr ns1; 4266 xmlNodeSetPtr ns2; 4267 4268 if ((arg1 == NULL) || 4269 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) 4270 return(0); 4271 if ((arg2 == NULL) || 4272 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) 4273 return(0); 4274 4275 ns1 = arg1->nodesetval; 4276 ns2 = arg2->nodesetval; 4277 4278 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) 4279 return(0); 4280 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) 4281 return(0); 4282 4283 /* 4284 * check if there is a node pertaining to both sets 4285 */ 4286 for (i = 0;i < ns1->nodeNr;i++) 4287 for (j = 0;j < ns2->nodeNr;j++) 4288 if (ns1->nodeTab[i] == ns2->nodeTab[j]) 4289 return(1); 4290 4291 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *)); 4292 if (values1 == NULL) 4293 return(0); 4294 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int)); 4295 if (hashs1 == NULL) { 4296 xmlFree(values1); 4297 return(0); 4298 } 4299 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *)); 4300 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *)); 4301 if (values2 == NULL) { 4302 xmlFree(hashs1); 4303 xmlFree(values1); 4304 return(0); 4305 } 4306 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int)); 4307 if (hashs2 == NULL) { 4308 xmlFree(hashs1); 4309 xmlFree(values1); 4310 xmlFree(values2); 4311 return(0); 4312 } 4313 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *)); 4314 for (i = 0;i < ns1->nodeNr;i++) { 4315 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]); 4316 for (j = 0;j < ns2->nodeNr;j++) { 4317 if (i == 0) 4318 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]); 4319 if (hashs1[i] == hashs2[j]) { 4320 if (values1[i] == NULL) 4321 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]); 4322 if (values2[j] == NULL) 4323 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]); 4324 ret = xmlStrEqual(values1[i], values2[j]); 4325 if (ret) 4326 break; 4327 } 4328 } 4329 if (ret) 4330 break; 4331 } 4332 for (i = 0;i < ns1->nodeNr;i++) 4333 if (values1[i] != NULL) 4334 xmlFree(values1[i]); 4335 for (j = 0;j < ns2->nodeNr;j++) 4336 if (values2[j] != NULL) 4337 xmlFree(values2[j]); 4338 xmlFree(values1); 4339 xmlFree(values2); 4340 xmlFree(hashs1); 4341 xmlFree(hashs2); 4342 return(ret); 4343} 4344 4345/** 4346 * xmlXPathEqualValues: 4347 * @ctxt: the XPath Parser context 4348 * 4349 * Implement the equal operation on XPath objects content: @arg1 == @arg2 4350 * 4351 * Returns 0 or 1 depending on the results of the test. 4352 */ 4353int 4354xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) { 4355 xmlXPathObjectPtr arg1, arg2; 4356 int ret = 0; 4357 4358 arg1 = valuePop(ctxt); 4359 if (arg1 == NULL) 4360 XP_ERROR0(XPATH_INVALID_OPERAND); 4361 4362 arg2 = valuePop(ctxt); 4363 if (arg2 == NULL) { 4364 xmlXPathFreeObject(arg1); 4365 XP_ERROR0(XPATH_INVALID_OPERAND); 4366 } 4367 4368 if (arg1 == arg2) { 4369#ifdef DEBUG_EXPR 4370 xmlGenericError(xmlGenericErrorContext, 4371 "Equal: by pointer\n"); 4372#endif 4373 return(1); 4374 } 4375 4376 switch (arg1->type) { 4377 case XPATH_UNDEFINED: 4378#ifdef DEBUG_EXPR 4379 xmlGenericError(xmlGenericErrorContext, 4380 "Equal: undefined\n"); 4381#endif 4382 break; 4383 case XPATH_XSLT_TREE: 4384 case XPATH_NODESET: 4385 switch (arg2->type) { 4386 case XPATH_UNDEFINED: 4387#ifdef DEBUG_EXPR 4388 xmlGenericError(xmlGenericErrorContext, 4389 "Equal: undefined\n"); 4390#endif 4391 break; 4392 case XPATH_XSLT_TREE: 4393 case XPATH_NODESET: 4394 ret = xmlXPathEqualNodeSets(arg1, arg2); 4395 break; 4396 case XPATH_BOOLEAN: 4397 if ((arg1->nodesetval == NULL) || 4398 (arg1->nodesetval->nodeNr == 0)) ret = 0; 4399 else 4400 ret = 1; 4401 ret = (ret == arg2->boolval); 4402 break; 4403 case XPATH_NUMBER: 4404 ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval); 4405 break; 4406 case XPATH_STRING: 4407 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval); 4408 break; 4409 case XPATH_USERS: 4410 case XPATH_POINT: 4411 case XPATH_RANGE: 4412 case XPATH_LOCATIONSET: 4413 TODO 4414 break; 4415 } 4416 break; 4417 case XPATH_BOOLEAN: 4418 switch (arg2->type) { 4419 case XPATH_UNDEFINED: 4420#ifdef DEBUG_EXPR 4421 xmlGenericError(xmlGenericErrorContext, 4422 "Equal: undefined\n"); 4423#endif 4424 break; 4425 case XPATH_NODESET: 4426 case XPATH_XSLT_TREE: 4427 if ((arg2->nodesetval == NULL) || 4428 (arg2->nodesetval->nodeNr == 0)) 4429 ret = 0; 4430 else 4431 ret = 1; 4432 ret = (ret == arg1->boolval); 4433 break; 4434 case XPATH_BOOLEAN: 4435#ifdef DEBUG_EXPR 4436 xmlGenericError(xmlGenericErrorContext, 4437 "Equal: %d boolean %d \n", 4438 arg1->boolval, arg2->boolval); 4439#endif 4440 ret = (arg1->boolval == arg2->boolval); 4441 break; 4442 case XPATH_NUMBER: 4443 if (arg2->floatval) ret = 1; 4444 else ret = 0; 4445 ret = (arg1->boolval == ret); 4446 break; 4447 case XPATH_STRING: 4448 if ((arg2->stringval == NULL) || 4449 (arg2->stringval[0] == 0)) ret = 0; 4450 else 4451 ret = 1; 4452 ret = (arg1->boolval == ret); 4453 break; 4454 case XPATH_USERS: 4455 case XPATH_POINT: 4456 case XPATH_RANGE: 4457 case XPATH_LOCATIONSET: 4458 TODO 4459 break; 4460 } 4461 break; 4462 case XPATH_NUMBER: 4463 switch (arg2->type) { 4464 case XPATH_UNDEFINED: 4465#ifdef DEBUG_EXPR 4466 xmlGenericError(xmlGenericErrorContext, 4467 "Equal: undefined\n"); 4468#endif 4469 break; 4470 case XPATH_NODESET: 4471 case XPATH_XSLT_TREE: 4472 ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval); 4473 break; 4474 case XPATH_BOOLEAN: 4475 if (arg1->floatval) ret = 1; 4476 else ret = 0; 4477 ret = (arg2->boolval == ret); 4478 break; 4479 case XPATH_STRING: 4480 valuePush(ctxt, arg2); 4481 xmlXPathNumberFunction(ctxt, 1); 4482 arg2 = valuePop(ctxt); 4483 /* no break on purpose */ 4484 case XPATH_NUMBER: 4485 /* Hand check NaN and Infinity equalities */ 4486 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 4487 ret = 0; 4488 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 4489 if (xmlXPathIsInf(arg2->floatval) == 1) 4490 ret = 1; 4491 else 4492 ret = 0; 4493 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 4494 if (xmlXPathIsInf(arg2->floatval) == -1) 4495 ret = 1; 4496 else 4497 ret = 0; 4498 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 4499 if (xmlXPathIsInf(arg1->floatval) == 1) 4500 ret = 1; 4501 else 4502 ret = 0; 4503 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 4504 if (xmlXPathIsInf(arg1->floatval) == -1) 4505 ret = 1; 4506 else 4507 ret = 0; 4508 } else { 4509 ret = (arg1->floatval == arg2->floatval); 4510 } 4511 break; 4512 case XPATH_USERS: 4513 case XPATH_POINT: 4514 case XPATH_RANGE: 4515 case XPATH_LOCATIONSET: 4516 TODO 4517 break; 4518 } 4519 break; 4520 case XPATH_STRING: 4521 switch (arg2->type) { 4522 case XPATH_UNDEFINED: 4523#ifdef DEBUG_EXPR 4524 xmlGenericError(xmlGenericErrorContext, 4525 "Equal: undefined\n"); 4526#endif 4527 break; 4528 case XPATH_NODESET: 4529 case XPATH_XSLT_TREE: 4530 ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval); 4531 break; 4532 case XPATH_BOOLEAN: 4533 if ((arg1->stringval == NULL) || 4534 (arg1->stringval[0] == 0)) ret = 0; 4535 else 4536 ret = 1; 4537 ret = (arg2->boolval == ret); 4538 break; 4539 case XPATH_STRING: 4540 ret = xmlStrEqual(arg1->stringval, arg2->stringval); 4541 break; 4542 case XPATH_NUMBER: 4543 valuePush(ctxt, arg1); 4544 xmlXPathNumberFunction(ctxt, 1); 4545 arg1 = valuePop(ctxt); 4546 /* Hand check NaN and Infinity equalities */ 4547 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 4548 ret = 0; 4549 } else if (xmlXPathIsInf(arg1->floatval) == 1) { 4550 if (xmlXPathIsInf(arg2->floatval) == 1) 4551 ret = 1; 4552 else 4553 ret = 0; 4554 } else if (xmlXPathIsInf(arg1->floatval) == -1) { 4555 if (xmlXPathIsInf(arg2->floatval) == -1) 4556 ret = 1; 4557 else 4558 ret = 0; 4559 } else if (xmlXPathIsInf(arg2->floatval) == 1) { 4560 if (xmlXPathIsInf(arg1->floatval) == 1) 4561 ret = 1; 4562 else 4563 ret = 0; 4564 } else if (xmlXPathIsInf(arg2->floatval) == -1) { 4565 if (xmlXPathIsInf(arg1->floatval) == -1) 4566 ret = 1; 4567 else 4568 ret = 0; 4569 } else { 4570 ret = (arg1->floatval == arg2->floatval); 4571 } 4572 break; 4573 case XPATH_USERS: 4574 case XPATH_POINT: 4575 case XPATH_RANGE: 4576 case XPATH_LOCATIONSET: 4577 TODO 4578 break; 4579 } 4580 break; 4581 case XPATH_USERS: 4582 case XPATH_POINT: 4583 case XPATH_RANGE: 4584 case XPATH_LOCATIONSET: 4585 TODO 4586 break; 4587 } 4588 xmlXPathFreeObject(arg1); 4589 xmlXPathFreeObject(arg2); 4590 return(ret); 4591} 4592 4593 4594/** 4595 * xmlXPathCompareValues: 4596 * @ctxt: the XPath Parser context 4597 * @inf: less than (1) or greater than (0) 4598 * @strict: is the comparison strict 4599 * 4600 * Implement the compare operation on XPath objects: 4601 * @arg1 < @arg2 (1, 1, ... 4602 * @arg1 <= @arg2 (1, 0, ... 4603 * @arg1 > @arg2 (0, 1, ... 4604 * @arg1 >= @arg2 (0, 0, ... 4605 * 4606 * When neither object to be compared is a node-set and the operator is 4607 * <=, <, >=, >, then the objects are compared by converted both objects 4608 * to numbers and comparing the numbers according to IEEE 754. The < 4609 * comparison will be true if and only if the first number is less than the 4610 * second number. The <= comparison will be true if and only if the first 4611 * number is less than or equal to the second number. The > comparison 4612 * will be true if and only if the first number is greater than the second 4613 * number. The >= comparison will be true if and only if the first number 4614 * is greater than or equal to the second number. 4615 * 4616 * Returns 1 if the comparison succeeded, 0 if it failed 4617 */ 4618int 4619xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) { 4620 int ret = 0, arg1i = 0, arg2i = 0; 4621 xmlXPathObjectPtr arg1, arg2; 4622 4623 arg2 = valuePop(ctxt); 4624 if (arg2 == NULL) { 4625 XP_ERROR0(XPATH_INVALID_OPERAND); 4626 } 4627 4628 arg1 = valuePop(ctxt); 4629 if (arg1 == NULL) { 4630 xmlXPathFreeObject(arg2); 4631 XP_ERROR0(XPATH_INVALID_OPERAND); 4632 } 4633 4634 if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) { 4635 if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) { 4636 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2); 4637 } else { 4638 if (arg1->type == XPATH_NODESET) { 4639 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, 4640 arg1, arg2); 4641 } else { 4642 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict, 4643 arg2, arg1); 4644 } 4645 } 4646 return(ret); 4647 } 4648 4649 if (arg1->type != XPATH_NUMBER) { 4650 valuePush(ctxt, arg1); 4651 xmlXPathNumberFunction(ctxt, 1); 4652 arg1 = valuePop(ctxt); 4653 } 4654 if (arg1->type != XPATH_NUMBER) { 4655 xmlXPathFreeObject(arg1); 4656 xmlXPathFreeObject(arg2); 4657 XP_ERROR0(XPATH_INVALID_OPERAND); 4658 } 4659 if (arg2->type != XPATH_NUMBER) { 4660 valuePush(ctxt, arg2); 4661 xmlXPathNumberFunction(ctxt, 1); 4662 arg2 = valuePop(ctxt); 4663 } 4664 if (arg2->type != XPATH_NUMBER) { 4665 xmlXPathFreeObject(arg1); 4666 xmlXPathFreeObject(arg2); 4667 XP_ERROR0(XPATH_INVALID_OPERAND); 4668 } 4669 /* 4670 * Add tests for infinity and nan 4671 * => feedback on 3.4 for Inf and NaN 4672 */ 4673 /* Hand check NaN and Infinity comparisons */ 4674 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) { 4675 ret=0; 4676 } else { 4677 arg1i=xmlXPathIsInf(arg1->floatval); 4678 arg2i=xmlXPathIsInf(arg2->floatval); 4679 if (inf && strict) { 4680 if ((arg1i == -1 && arg2i != -1) || 4681 (arg2i == 1 && arg1i != 1)) { 4682 ret = 1; 4683 } else if (arg1i == 0 && arg2i == 0) { 4684 ret = (arg1->floatval < arg2->floatval); 4685 } else { 4686 ret = 0; 4687 } 4688 } 4689 else if (inf && !strict) { 4690 if (arg1i == -1 || arg2i == 1) { 4691 ret = 1; 4692 } else if (arg1i == 0 && arg2i == 0) { 4693 ret = (arg1->floatval <= arg2->floatval); 4694 } else { 4695 ret = 0; 4696 } 4697 } 4698 else if (!inf && strict) { 4699 if ((arg1i == 1 && arg2i != 1) || 4700 (arg2i == -1 && arg1i != -1)) { 4701 ret = 1; 4702 } else if (arg1i == 0 && arg2i == 0) { 4703 ret = (arg1->floatval > arg2->floatval); 4704 } else { 4705 ret = 0; 4706 } 4707 } 4708 else if (!inf && !strict) { 4709 if (arg1i == 1 || arg2i == -1) { 4710 ret = 1; 4711 } else if (arg1i == 0 && arg2i == 0) { 4712 ret = (arg1->floatval >= arg2->floatval); 4713 } else { 4714 ret = 0; 4715 } 4716 } 4717 } 4718 xmlXPathFreeObject(arg1); 4719 xmlXPathFreeObject(arg2); 4720 return(ret); 4721} 4722 4723/** 4724 * xmlXPathValueFlipSign: 4725 * @ctxt: the XPath Parser context 4726 * 4727 * Implement the unary - operation on an XPath object 4728 * The numeric operators convert their operands to numbers as if 4729 * by calling the number function. 4730 */ 4731void 4732xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) { 4733 CAST_TO_NUMBER; 4734 CHECK_TYPE(XPATH_NUMBER); 4735 if (xmlXPathIsNaN(ctxt->value->floatval)) 4736 ctxt->value->floatval=xmlXPathNAN; 4737 else if (xmlXPathIsInf(ctxt->value->floatval) == 1) 4738 ctxt->value->floatval=xmlXPathNINF; 4739 else if (xmlXPathIsInf(ctxt->value->floatval) == -1) 4740 ctxt->value->floatval=xmlXPathPINF; 4741 else if (ctxt->value->floatval == 0) { 4742 if (xmlXPathGetSign(ctxt->value->floatval) == 0) 4743 ctxt->value->floatval = xmlXPathNZERO; 4744 else 4745 ctxt->value->floatval = 0; 4746 } 4747 else 4748 ctxt->value->floatval = - ctxt->value->floatval; 4749} 4750 4751/** 4752 * xmlXPathAddValues: 4753 * @ctxt: the XPath Parser context 4754 * 4755 * Implement the add operation on XPath objects: 4756 * The numeric operators convert their operands to numbers as if 4757 * by calling the number function. 4758 */ 4759void 4760xmlXPathAddValues(xmlXPathParserContextPtr ctxt) { 4761 xmlXPathObjectPtr arg; 4762 double val; 4763 4764 arg = valuePop(ctxt); 4765 if (arg == NULL) 4766 XP_ERROR(XPATH_INVALID_OPERAND); 4767 val = xmlXPathCastToNumber(arg); 4768 xmlXPathFreeObject(arg); 4769 4770 CAST_TO_NUMBER; 4771 CHECK_TYPE(XPATH_NUMBER); 4772 ctxt->value->floatval += val; 4773} 4774 4775/** 4776 * xmlXPathSubValues: 4777 * @ctxt: the XPath Parser context 4778 * 4779 * Implement the subtraction operation on XPath objects: 4780 * The numeric operators convert their operands to numbers as if 4781 * by calling the number function. 4782 */ 4783void 4784xmlXPathSubValues(xmlXPathParserContextPtr ctxt) { 4785 xmlXPathObjectPtr arg; 4786 double val; 4787 4788 arg = valuePop(ctxt); 4789 if (arg == NULL) 4790 XP_ERROR(XPATH_INVALID_OPERAND); 4791 val = xmlXPathCastToNumber(arg); 4792 xmlXPathFreeObject(arg); 4793 4794 CAST_TO_NUMBER; 4795 CHECK_TYPE(XPATH_NUMBER); 4796 ctxt->value->floatval -= val; 4797} 4798 4799/** 4800 * xmlXPathMultValues: 4801 * @ctxt: the XPath Parser context 4802 * 4803 * Implement the multiply operation on XPath objects: 4804 * The numeric operators convert their operands to numbers as if 4805 * by calling the number function. 4806 */ 4807void 4808xmlXPathMultValues(xmlXPathParserContextPtr ctxt) { 4809 xmlXPathObjectPtr arg; 4810 double val; 4811 4812 arg = valuePop(ctxt); 4813 if (arg == NULL) 4814 XP_ERROR(XPATH_INVALID_OPERAND); 4815 val = xmlXPathCastToNumber(arg); 4816 xmlXPathFreeObject(arg); 4817 4818 CAST_TO_NUMBER; 4819 CHECK_TYPE(XPATH_NUMBER); 4820 ctxt->value->floatval *= val; 4821} 4822 4823/** 4824 * xmlXPathDivValues: 4825 * @ctxt: the XPath Parser context 4826 * 4827 * Implement the div operation on XPath objects @arg1 / @arg2: 4828 * The numeric operators convert their operands to numbers as if 4829 * by calling the number function. 4830 */ 4831void 4832xmlXPathDivValues(xmlXPathParserContextPtr ctxt) { 4833 xmlXPathObjectPtr arg; 4834 double val; 4835 4836 arg = valuePop(ctxt); 4837 if (arg == NULL) 4838 XP_ERROR(XPATH_INVALID_OPERAND); 4839 val = xmlXPathCastToNumber(arg); 4840 xmlXPathFreeObject(arg); 4841 4842 CAST_TO_NUMBER; 4843 CHECK_TYPE(XPATH_NUMBER); 4844 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval)) 4845 ctxt->value->floatval = xmlXPathNAN; 4846 else if (val == 0 && xmlXPathGetSign(val) != 0) { 4847 if (ctxt->value->floatval == 0) 4848 ctxt->value->floatval = xmlXPathNAN; 4849 else if (ctxt->value->floatval > 0) 4850 ctxt->value->floatval = xmlXPathNINF; 4851 else if (ctxt->value->floatval < 0) 4852 ctxt->value->floatval = xmlXPathPINF; 4853 } 4854 else if (val == 0) { 4855 if (ctxt->value->floatval == 0) 4856 ctxt->value->floatval = xmlXPathNAN; 4857 else if (ctxt->value->floatval > 0) 4858 ctxt->value->floatval = xmlXPathPINF; 4859 else if (ctxt->value->floatval < 0) 4860 ctxt->value->floatval = xmlXPathNINF; 4861 } else 4862 ctxt->value->floatval /= val; 4863} 4864 4865/** 4866 * xmlXPathModValues: 4867 * @ctxt: the XPath Parser context 4868 * 4869 * Implement the mod operation on XPath objects: @arg1 / @arg2 4870 * The numeric operators convert their operands to numbers as if 4871 * by calling the number function. 4872 */ 4873void 4874xmlXPathModValues(xmlXPathParserContextPtr ctxt) { 4875 xmlXPathObjectPtr arg; 4876 double arg1, arg2, tmp; 4877 4878 arg = valuePop(ctxt); 4879 if (arg == NULL) 4880 XP_ERROR(XPATH_INVALID_OPERAND); 4881 arg2 = xmlXPathCastToNumber(arg); 4882 xmlXPathFreeObject(arg); 4883 4884 CAST_TO_NUMBER; 4885 CHECK_TYPE(XPATH_NUMBER); 4886 arg1 = ctxt->value->floatval; 4887 if (arg2 == 0) 4888 ctxt->value->floatval = xmlXPathNAN; 4889 else { 4890 tmp=arg1/arg2; 4891 ctxt->value->floatval = arg2 * (tmp - (double)((int)tmp)); 4892 } 4893} 4894 4895/************************************************************************ 4896 * * 4897 * The traversal functions * 4898 * * 4899 ************************************************************************/ 4900 4901/* 4902 * A traversal function enumerates nodes along an axis. 4903 * Initially it must be called with NULL, and it indicates 4904 * termination on the axis by returning NULL. 4905 */ 4906typedef xmlNodePtr (*xmlXPathTraversalFunction) 4907 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur); 4908 4909/** 4910 * xmlXPathNextSelf: 4911 * @ctxt: the XPath Parser context 4912 * @cur: the current node in the traversal 4913 * 4914 * Traversal function for the "self" direction 4915 * The self axis contains just the context node itself 4916 * 4917 * Returns the next element following that axis 4918 */ 4919xmlNodePtr 4920xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 4921 if (cur == NULL) 4922 return(ctxt->context->node); 4923 return(NULL); 4924} 4925 4926/** 4927 * xmlXPathNextChild: 4928 * @ctxt: the XPath Parser context 4929 * @cur: the current node in the traversal 4930 * 4931 * Traversal function for the "child" direction 4932 * The child axis contains the children of the context node in document order. 4933 * 4934 * Returns the next element following that axis 4935 */ 4936xmlNodePtr 4937xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 4938 if (cur == NULL) { 4939 if (ctxt->context->node == NULL) return(NULL); 4940 switch (ctxt->context->node->type) { 4941 case XML_ELEMENT_NODE: 4942 case XML_TEXT_NODE: 4943 case XML_CDATA_SECTION_NODE: 4944 case XML_ENTITY_REF_NODE: 4945 case XML_ENTITY_NODE: 4946 case XML_PI_NODE: 4947 case XML_COMMENT_NODE: 4948 case XML_NOTATION_NODE: 4949 case XML_DTD_NODE: 4950 return(ctxt->context->node->children); 4951 case XML_DOCUMENT_NODE: 4952 case XML_DOCUMENT_TYPE_NODE: 4953 case XML_DOCUMENT_FRAG_NODE: 4954 case XML_HTML_DOCUMENT_NODE: 4955#ifdef LIBXML_DOCB_ENABLED 4956 case XML_DOCB_DOCUMENT_NODE: 4957#endif 4958 return(((xmlDocPtr) ctxt->context->node)->children); 4959 case XML_ELEMENT_DECL: 4960 case XML_ATTRIBUTE_DECL: 4961 case XML_ENTITY_DECL: 4962 case XML_ATTRIBUTE_NODE: 4963 case XML_NAMESPACE_DECL: 4964 case XML_XINCLUDE_START: 4965 case XML_XINCLUDE_END: 4966 return(NULL); 4967 } 4968 return(NULL); 4969 } 4970 if ((cur->type == XML_DOCUMENT_NODE) || 4971 (cur->type == XML_HTML_DOCUMENT_NODE)) 4972 return(NULL); 4973 return(cur->next); 4974} 4975 4976/** 4977 * xmlXPathNextDescendant: 4978 * @ctxt: the XPath Parser context 4979 * @cur: the current node in the traversal 4980 * 4981 * Traversal function for the "descendant" direction 4982 * the descendant axis contains the descendants of the context node in document 4983 * order; a descendant is a child or a child of a child and so on. 4984 * 4985 * Returns the next element following that axis 4986 */ 4987xmlNodePtr 4988xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 4989 if (cur == NULL) { 4990 if (ctxt->context->node == NULL) 4991 return(NULL); 4992 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 4993 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 4994 return(NULL); 4995 4996 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 4997 return(ctxt->context->doc->children); 4998 return(ctxt->context->node->children); 4999 } 5000 5001 if (cur->children != NULL) { 5002 if (cur->children->type != XML_ENTITY_DECL) 5003 return(cur->children); 5004 } 5005 5006 if (cur == ctxt->context->node) return(NULL); 5007 5008 if (cur->next != NULL) return(cur->next); 5009 5010 do { 5011 cur = cur->parent; 5012 if (cur == NULL) return(NULL); 5013 if (cur == ctxt->context->node) return(NULL); 5014 if (cur->next != NULL) { 5015 cur = cur->next; 5016 return(cur); 5017 } 5018 } while (cur != NULL); 5019 return(cur); 5020} 5021 5022/** 5023 * xmlXPathNextDescendantOrSelf: 5024 * @ctxt: the XPath Parser context 5025 * @cur: the current node in the traversal 5026 * 5027 * Traversal function for the "descendant-or-self" direction 5028 * the descendant-or-self axis contains the context node and the descendants 5029 * of the context node in document order; thus the context node is the first 5030 * node on the axis, and the first child of the context node is the second node 5031 * on the axis 5032 * 5033 * Returns the next element following that axis 5034 */ 5035xmlNodePtr 5036xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5037 if (cur == NULL) { 5038 if (ctxt->context->node == NULL) 5039 return(NULL); 5040 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 5041 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 5042 return(NULL); 5043 return(ctxt->context->node); 5044 } 5045 5046 return(xmlXPathNextDescendant(ctxt, cur)); 5047} 5048 5049/** 5050 * xmlXPathNextParent: 5051 * @ctxt: the XPath Parser context 5052 * @cur: the current node in the traversal 5053 * 5054 * Traversal function for the "parent" direction 5055 * The parent axis contains the parent of the context node, if there is one. 5056 * 5057 * Returns the next element following that axis 5058 */ 5059xmlNodePtr 5060xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5061 /* 5062 * the parent of an attribute or namespace node is the element 5063 * to which the attribute or namespace node is attached 5064 * Namespace handling !!! 5065 */ 5066 if (cur == NULL) { 5067 if (ctxt->context->node == NULL) return(NULL); 5068 switch (ctxt->context->node->type) { 5069 case XML_ELEMENT_NODE: 5070 case XML_TEXT_NODE: 5071 case XML_CDATA_SECTION_NODE: 5072 case XML_ENTITY_REF_NODE: 5073 case XML_ENTITY_NODE: 5074 case XML_PI_NODE: 5075 case XML_COMMENT_NODE: 5076 case XML_NOTATION_NODE: 5077 case XML_DTD_NODE: 5078 case XML_ELEMENT_DECL: 5079 case XML_ATTRIBUTE_DECL: 5080 case XML_XINCLUDE_START: 5081 case XML_XINCLUDE_END: 5082 case XML_ENTITY_DECL: 5083 if (ctxt->context->node->parent == NULL) 5084 return((xmlNodePtr) ctxt->context->doc); 5085 return(ctxt->context->node->parent); 5086 case XML_ATTRIBUTE_NODE: { 5087 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 5088 5089 return(att->parent); 5090 } 5091 case XML_DOCUMENT_NODE: 5092 case XML_DOCUMENT_TYPE_NODE: 5093 case XML_DOCUMENT_FRAG_NODE: 5094 case XML_HTML_DOCUMENT_NODE: 5095#ifdef LIBXML_DOCB_ENABLED 5096 case XML_DOCB_DOCUMENT_NODE: 5097#endif 5098 return(NULL); 5099 case XML_NAMESPACE_DECL: { 5100 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 5101 5102 if ((ns->next != NULL) && 5103 (ns->next->type != XML_NAMESPACE_DECL)) 5104 return((xmlNodePtr) ns->next); 5105 return(NULL); 5106 } 5107 } 5108 } 5109 return(NULL); 5110} 5111 5112/** 5113 * xmlXPathNextAncestor: 5114 * @ctxt: the XPath Parser context 5115 * @cur: the current node in the traversal 5116 * 5117 * Traversal function for the "ancestor" direction 5118 * the ancestor axis contains the ancestors of the context node; the ancestors 5119 * of the context node consist of the parent of context node and the parent's 5120 * parent and so on; the nodes are ordered in reverse document order; thus the 5121 * parent is the first node on the axis, and the parent's parent is the second 5122 * node on the axis 5123 * 5124 * Returns the next element following that axis 5125 */ 5126xmlNodePtr 5127xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5128 /* 5129 * the parent of an attribute or namespace node is the element 5130 * to which the attribute or namespace node is attached 5131 * !!!!!!!!!!!!! 5132 */ 5133 if (cur == NULL) { 5134 if (ctxt->context->node == NULL) return(NULL); 5135 switch (ctxt->context->node->type) { 5136 case XML_ELEMENT_NODE: 5137 case XML_TEXT_NODE: 5138 case XML_CDATA_SECTION_NODE: 5139 case XML_ENTITY_REF_NODE: 5140 case XML_ENTITY_NODE: 5141 case XML_PI_NODE: 5142 case XML_COMMENT_NODE: 5143 case XML_DTD_NODE: 5144 case XML_ELEMENT_DECL: 5145 case XML_ATTRIBUTE_DECL: 5146 case XML_ENTITY_DECL: 5147 case XML_NOTATION_NODE: 5148 case XML_XINCLUDE_START: 5149 case XML_XINCLUDE_END: 5150 if (ctxt->context->node->parent == NULL) 5151 return((xmlNodePtr) ctxt->context->doc); 5152 return(ctxt->context->node->parent); 5153 case XML_ATTRIBUTE_NODE: { 5154 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node; 5155 5156 return(tmp->parent); 5157 } 5158 case XML_DOCUMENT_NODE: 5159 case XML_DOCUMENT_TYPE_NODE: 5160 case XML_DOCUMENT_FRAG_NODE: 5161 case XML_HTML_DOCUMENT_NODE: 5162#ifdef LIBXML_DOCB_ENABLED 5163 case XML_DOCB_DOCUMENT_NODE: 5164#endif 5165 return(NULL); 5166 case XML_NAMESPACE_DECL: { 5167 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node; 5168 5169 if ((ns->next != NULL) && 5170 (ns->next->type != XML_NAMESPACE_DECL)) 5171 return((xmlNodePtr) ns->next); 5172 /* Bad, how did that namespace ended-up there ? */ 5173 return(NULL); 5174 } 5175 } 5176 return(NULL); 5177 } 5178 if (cur == ctxt->context->doc->children) 5179 return((xmlNodePtr) ctxt->context->doc); 5180 if (cur == (xmlNodePtr) ctxt->context->doc) 5181 return(NULL); 5182 switch (cur->type) { 5183 case XML_ELEMENT_NODE: 5184 case XML_TEXT_NODE: 5185 case XML_CDATA_SECTION_NODE: 5186 case XML_ENTITY_REF_NODE: 5187 case XML_ENTITY_NODE: 5188 case XML_PI_NODE: 5189 case XML_COMMENT_NODE: 5190 case XML_NOTATION_NODE: 5191 case XML_DTD_NODE: 5192 case XML_ELEMENT_DECL: 5193 case XML_ATTRIBUTE_DECL: 5194 case XML_ENTITY_DECL: 5195 case XML_XINCLUDE_START: 5196 case XML_XINCLUDE_END: 5197 return(cur->parent); 5198 case XML_ATTRIBUTE_NODE: { 5199 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node; 5200 5201 return(att->parent); 5202 } 5203 case XML_DOCUMENT_NODE: 5204 case XML_DOCUMENT_TYPE_NODE: 5205 case XML_DOCUMENT_FRAG_NODE: 5206 case XML_HTML_DOCUMENT_NODE: 5207#ifdef LIBXML_DOCB_ENABLED 5208 case XML_DOCB_DOCUMENT_NODE: 5209#endif 5210 return(NULL); 5211 case XML_NAMESPACE_DECL: 5212 /* 5213 * this should not hapen a namespace can't be 5214 * the ancestor of another node 5215 */ 5216 return(NULL); 5217 } 5218 return(NULL); 5219} 5220 5221/** 5222 * xmlXPathNextAncestorOrSelf: 5223 * @ctxt: the XPath Parser context 5224 * @cur: the current node in the traversal 5225 * 5226 * Traversal function for the "ancestor-or-self" direction 5227 * he ancestor-or-self axis contains the context node and ancestors of 5228 * the context node in reverse document order; thus the context node is 5229 * the first node on the axis, and the context node's parent the second; 5230 * parent here is defined the same as with the parent axis. 5231 * 5232 * Returns the next element following that axis 5233 */ 5234xmlNodePtr 5235xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5236 if (cur == NULL) 5237 return(ctxt->context->node); 5238 return(xmlXPathNextAncestor(ctxt, cur)); 5239} 5240 5241/** 5242 * xmlXPathNextFollowingSibling: 5243 * @ctxt: the XPath Parser context 5244 * @cur: the current node in the traversal 5245 * 5246 * Traversal function for the "following-sibling" direction 5247 * The following-sibling axis contains the following siblings of the context 5248 * node in document order. 5249 * 5250 * Returns the next element following that axis 5251 */ 5252xmlNodePtr 5253xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5254 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 5255 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 5256 return(NULL); 5257 if (cur == (xmlNodePtr) ctxt->context->doc) 5258 return(NULL); 5259 if (cur == NULL) 5260 return(ctxt->context->node->next); 5261 return(cur->next); 5262} 5263 5264/** 5265 * xmlXPathNextPrecedingSibling: 5266 * @ctxt: the XPath Parser context 5267 * @cur: the current node in the traversal 5268 * 5269 * Traversal function for the "preceding-sibling" direction 5270 * The preceding-sibling axis contains the preceding siblings of the context 5271 * node in reverse document order; the first preceding sibling is first on the 5272 * axis; the sibling preceding that node is the second on the axis and so on. 5273 * 5274 * Returns the next element following that axis 5275 */ 5276xmlNodePtr 5277xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5278 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || 5279 (ctxt->context->node->type == XML_NAMESPACE_DECL)) 5280 return(NULL); 5281 if (cur == (xmlNodePtr) ctxt->context->doc) 5282 return(NULL); 5283 if (cur == NULL) 5284 return(ctxt->context->node->prev); 5285 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) { 5286 cur = cur->prev; 5287 if (cur == NULL) 5288 return(ctxt->context->node->prev); 5289 } 5290 return(cur->prev); 5291} 5292 5293/** 5294 * xmlXPathNextFollowing: 5295 * @ctxt: the XPath Parser context 5296 * @cur: the current node in the traversal 5297 * 5298 * Traversal function for the "following" direction 5299 * The following axis contains all nodes in the same document as the context 5300 * node that are after the context node in document order, excluding any 5301 * descendants and excluding attribute nodes and namespace nodes; the nodes 5302 * are ordered in document order 5303 * 5304 * Returns the next element following that axis 5305 */ 5306xmlNodePtr 5307xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5308 if (cur != NULL && cur->children != NULL) 5309 return cur->children ; 5310 if (cur == NULL) cur = ctxt->context->node; 5311 if (cur == NULL) return(NULL) ; /* ERROR */ 5312 if (cur->next != NULL) return(cur->next) ; 5313 do { 5314 cur = cur->parent; 5315 if (cur == NULL) return(NULL); 5316 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL); 5317 if (cur->next != NULL) return(cur->next); 5318 } while (cur != NULL); 5319 return(cur); 5320} 5321 5322/* 5323 * xmlXPathIsAncestor: 5324 * @ancestor: the ancestor node 5325 * @node: the current node 5326 * 5327 * Check that @ancestor is a @node's ancestor 5328 * 5329 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise. 5330 */ 5331static int 5332xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { 5333 if ((ancestor == NULL) || (node == NULL)) return(0); 5334 /* nodes need to be in the same document */ 5335 if (ancestor->doc != node->doc) return(0); 5336 /* avoid searching if ancestor or node is the root node */ 5337 if (ancestor == (xmlNodePtr) node->doc) return(1); 5338 if (node == (xmlNodePtr) ancestor->doc) return(0); 5339 while (node->parent != NULL) { 5340 if (node->parent == ancestor) 5341 return(1); 5342 node = node->parent; 5343 } 5344 return(0); 5345} 5346 5347/** 5348 * xmlXPathNextPreceding: 5349 * @ctxt: the XPath Parser context 5350 * @cur: the current node in the traversal 5351 * 5352 * Traversal function for the "preceding" direction 5353 * the preceding axis contains all nodes in the same document as the context 5354 * node that are before the context node in document order, excluding any 5355 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 5356 * ordered in reverse document order 5357 * 5358 * Returns the next element following that axis 5359 */ 5360xmlNodePtr 5361xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) 5362{ 5363 if (cur == NULL) 5364 cur = ctxt->context->node; 5365 if (cur == NULL) 5366 return (NULL); 5367 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 5368 cur = cur->prev; 5369 do { 5370 if (cur->prev != NULL) { 5371 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ; 5372 return (cur); 5373 } 5374 5375 cur = cur->parent; 5376 if (cur == NULL) 5377 return (NULL); 5378 if (cur == ctxt->context->doc->children) 5379 return (NULL); 5380 } while (xmlXPathIsAncestor(cur, ctxt->context->node)); 5381 return (cur); 5382} 5383 5384/** 5385 * xmlXPathNextPrecedingInternal: 5386 * @ctxt: the XPath Parser context 5387 * @cur: the current node in the traversal 5388 * 5389 * Traversal function for the "preceding" direction 5390 * the preceding axis contains all nodes in the same document as the context 5391 * node that are before the context node in document order, excluding any 5392 * ancestors and excluding attribute nodes and namespace nodes; the nodes are 5393 * ordered in reverse document order 5394 * This is a faster implementation but internal only since it requires a 5395 * state kept in the parser context: ctxt->ancestor. 5396 * 5397 * Returns the next element following that axis 5398 */ 5399static xmlNodePtr 5400xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, 5401 xmlNodePtr cur) 5402{ 5403 if (cur == NULL) { 5404 cur = ctxt->context->node; 5405 if (cur == NULL) 5406 return (NULL); 5407 ctxt->ancestor = cur->parent; 5408 } 5409 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) 5410 cur = cur->prev; 5411 while (cur->prev == NULL) { 5412 cur = cur->parent; 5413 if (cur == NULL) 5414 return (NULL); 5415 if (cur == ctxt->context->doc->children) 5416 return (NULL); 5417 if (cur != ctxt->ancestor) 5418 return (cur); 5419 ctxt->ancestor = cur->parent; 5420 } 5421 cur = cur->prev; 5422 while (cur->last != NULL) 5423 cur = cur->last; 5424 return (cur); 5425} 5426 5427/** 5428 * xmlXPathNextNamespace: 5429 * @ctxt: the XPath Parser context 5430 * @cur: the current attribute in the traversal 5431 * 5432 * Traversal function for the "namespace" direction 5433 * the namespace axis contains the namespace nodes of the context node; 5434 * the order of nodes on this axis is implementation-defined; the axis will 5435 * be empty unless the context node is an element 5436 * 5437 * We keep the XML namespace node at the end of the list. 5438 * 5439 * Returns the next element following that axis 5440 */ 5441xmlNodePtr 5442xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5443 xmlNodePtr ret; 5444 5445 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); 5446 if (cur == (xmlNodePtr) xmlXPathXMLNamespace) 5447 return(NULL); 5448 if ((cur == NULL) || (ctxt->context->tmpNsList == NULL)) { 5449 if (ctxt->context->tmpNsList != NULL) 5450 xmlFree(ctxt->context->tmpNsList); 5451 ctxt->context->tmpNsList = 5452 xmlGetNsList(ctxt->context->doc, ctxt->context->node); 5453 if (ctxt->context->tmpNsList == NULL) return(NULL); 5454 ctxt->context->tmpNsNr = 0; 5455 } 5456 ret = (xmlNodePtr)ctxt->context->tmpNsList[ctxt->context->tmpNsNr++]; 5457 if (ret == NULL) { 5458 xmlFree(ctxt->context->tmpNsList); 5459 ctxt->context->tmpNsList = NULL; 5460 return((xmlNodePtr) xmlXPathXMLNamespace); 5461 } 5462 return(ret); 5463} 5464 5465/** 5466 * xmlXPathNextAttribute: 5467 * @ctxt: the XPath Parser context 5468 * @cur: the current attribute in the traversal 5469 * 5470 * Traversal function for the "attribute" direction 5471 * TODO: support DTD inherited default attributes 5472 * 5473 * Returns the next element following that axis 5474 */ 5475xmlNodePtr 5476xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { 5477 if (ctxt->context->node == NULL) 5478 return(NULL); 5479 if (ctxt->context->node->type != XML_ELEMENT_NODE) 5480 return(NULL); 5481 if (cur == NULL) { 5482 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc) 5483 return(NULL); 5484 return((xmlNodePtr)ctxt->context->node->properties); 5485 } 5486 return((xmlNodePtr)cur->next); 5487} 5488 5489/************************************************************************ 5490 * * 5491 * NodeTest Functions * 5492 * * 5493 ************************************************************************/ 5494 5495#define IS_FUNCTION 200 5496 5497 5498/************************************************************************ 5499 * * 5500 * Implicit tree core function library * 5501 * * 5502 ************************************************************************/ 5503 5504/** 5505 * xmlXPathRoot: 5506 * @ctxt: the XPath Parser context 5507 * 5508 * Initialize the context to the root of the document 5509 */ 5510void 5511xmlXPathRoot(xmlXPathParserContextPtr ctxt) { 5512 ctxt->context->node = (xmlNodePtr) ctxt->context->doc; 5513 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 5514} 5515 5516/************************************************************************ 5517 * * 5518 * The explicit core function library * 5519 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib * 5520 * * 5521 ************************************************************************/ 5522 5523 5524/** 5525 * xmlXPathLastFunction: 5526 * @ctxt: the XPath Parser context 5527 * @nargs: the number of arguments 5528 * 5529 * Implement the last() XPath function 5530 * number last() 5531 * The last function returns the number of nodes in the context node list. 5532 */ 5533void 5534xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5535 CHECK_ARITY(0); 5536 if (ctxt->context->contextSize >= 0) { 5537 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize)); 5538#ifdef DEBUG_EXPR 5539 xmlGenericError(xmlGenericErrorContext, 5540 "last() : %d\n", ctxt->context->contextSize); 5541#endif 5542 } else { 5543 XP_ERROR(XPATH_INVALID_CTXT_SIZE); 5544 } 5545} 5546 5547/** 5548 * xmlXPathPositionFunction: 5549 * @ctxt: the XPath Parser context 5550 * @nargs: the number of arguments 5551 * 5552 * Implement the position() XPath function 5553 * number position() 5554 * The position function returns the position of the context node in the 5555 * context node list. The first position is 1, and so the last position 5556 * will be equal to last(). 5557 */ 5558void 5559xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5560 CHECK_ARITY(0); 5561 if (ctxt->context->proximityPosition >= 0) { 5562 valuePush(ctxt, 5563 xmlXPathNewFloat((double) ctxt->context->proximityPosition)); 5564#ifdef DEBUG_EXPR 5565 xmlGenericError(xmlGenericErrorContext, "position() : %d\n", 5566 ctxt->context->proximityPosition); 5567#endif 5568 } else { 5569 XP_ERROR(XPATH_INVALID_CTXT_POSITION); 5570 } 5571} 5572 5573/** 5574 * xmlXPathCountFunction: 5575 * @ctxt: the XPath Parser context 5576 * @nargs: the number of arguments 5577 * 5578 * Implement the count() XPath function 5579 * number count(node-set) 5580 */ 5581void 5582xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5583 xmlXPathObjectPtr cur; 5584 5585 CHECK_ARITY(1); 5586 if ((ctxt->value == NULL) || 5587 ((ctxt->value->type != XPATH_NODESET) && 5588 (ctxt->value->type != XPATH_XSLT_TREE))) 5589 XP_ERROR(XPATH_INVALID_TYPE); 5590 cur = valuePop(ctxt); 5591 5592 if ((cur == NULL) || (cur->nodesetval == NULL)) 5593 valuePush(ctxt, xmlXPathNewFloat((double) 0)); 5594 else if (cur->type == XPATH_NODESET) { 5595 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr)); 5596 } else { 5597 if ((cur->nodesetval->nodeNr != 1) || 5598 (cur->nodesetval->nodeTab == NULL)) { 5599 valuePush(ctxt, xmlXPathNewFloat((double) 0)); 5600 } else { 5601 xmlNodePtr tmp; 5602 int i = 0; 5603 5604 tmp = cur->nodesetval->nodeTab[0]; 5605 if (tmp != NULL) { 5606 tmp = tmp->children; 5607 while (tmp != NULL) { 5608 tmp = tmp->next; 5609 i++; 5610 } 5611 } 5612 valuePush(ctxt, xmlXPathNewFloat((double) i)); 5613 } 5614 } 5615 xmlXPathFreeObject(cur); 5616} 5617 5618/** 5619 * xmlXPathGetElementsByIds: 5620 * @doc: the document 5621 * @ids: a whitespace separated list of IDs 5622 * 5623 * Selects elements by their unique ID. 5624 * 5625 * Returns a node-set of selected elements. 5626 */ 5627static xmlNodeSetPtr 5628xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) { 5629 xmlNodeSetPtr ret; 5630 const xmlChar *cur = ids; 5631 xmlChar *ID; 5632 xmlAttrPtr attr; 5633 xmlNodePtr elem = NULL; 5634 5635 ret = xmlXPathNodeSetCreate(NULL); 5636 5637 while (IS_BLANK(*cur)) cur++; 5638 while (*cur != 0) { 5639 while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) || 5640 (*cur == '.') || (*cur == '-') || 5641 (*cur == '_') || (*cur == ':') || 5642 (IS_COMBINING(*cur)) || 5643 (IS_EXTENDER(*cur))) 5644 cur++; 5645 5646 if ((!IS_BLANK(*cur)) && (*cur != 0)) break; 5647 5648 ID = xmlStrndup(ids, cur - ids); 5649 attr = xmlGetID(doc, ID); 5650 if (attr != NULL) { 5651 elem = attr->parent; 5652 xmlXPathNodeSetAdd(ret, elem); 5653 } 5654 if (ID != NULL) 5655 xmlFree(ID); 5656 5657 while (IS_BLANK(*cur)) cur++; 5658 ids = cur; 5659 } 5660 return(ret); 5661} 5662 5663/** 5664 * xmlXPathIdFunction: 5665 * @ctxt: the XPath Parser context 5666 * @nargs: the number of arguments 5667 * 5668 * Implement the id() XPath function 5669 * node-set id(object) 5670 * The id function selects elements by their unique ID 5671 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, 5672 * then the result is the union of the result of applying id to the 5673 * string value of each of the nodes in the argument node-set. When the 5674 * argument to id is of any other type, the argument is converted to a 5675 * string as if by a call to the string function; the string is split 5676 * into a whitespace-separated list of tokens (whitespace is any sequence 5677 * of characters matching the production S); the result is a node-set 5678 * containing the elements in the same document as the context node that 5679 * have a unique ID equal to any of the tokens in the list. 5680 */ 5681void 5682xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5683 xmlChar *tokens; 5684 xmlNodeSetPtr ret; 5685 xmlXPathObjectPtr obj; 5686 5687 CHECK_ARITY(1); 5688 obj = valuePop(ctxt); 5689 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 5690 if (obj->type == XPATH_NODESET) { 5691 xmlNodeSetPtr ns; 5692 int i; 5693 5694 ret = xmlXPathNodeSetCreate(NULL); 5695 5696 if (obj->nodesetval != NULL) { 5697 for (i = 0; i < obj->nodesetval->nodeNr; i++) { 5698 tokens = 5699 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]); 5700 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens); 5701 ret = xmlXPathNodeSetMerge(ret, ns); 5702 xmlXPathFreeNodeSet(ns); 5703 if (tokens != NULL) 5704 xmlFree(tokens); 5705 } 5706 } 5707 5708 xmlXPathFreeObject(obj); 5709 valuePush(ctxt, xmlXPathWrapNodeSet(ret)); 5710 return; 5711 } 5712 obj = xmlXPathConvertString(obj); 5713 5714 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval); 5715 valuePush(ctxt, xmlXPathWrapNodeSet(ret)); 5716 5717 xmlXPathFreeObject(obj); 5718 return; 5719} 5720 5721/** 5722 * xmlXPathLocalNameFunction: 5723 * @ctxt: the XPath Parser context 5724 * @nargs: the number of arguments 5725 * 5726 * Implement the local-name() XPath function 5727 * string local-name(node-set?) 5728 * The local-name function returns a string containing the local part 5729 * of the name of the node in the argument node-set that is first in 5730 * document order. If the node-set is empty or the first node has no 5731 * name, an empty string is returned. If the argument is omitted it 5732 * defaults to the context node. 5733 */ 5734void 5735xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5736 xmlXPathObjectPtr cur; 5737 5738 if (nargs == 0) { 5739 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 5740 nargs = 1; 5741 } 5742 5743 CHECK_ARITY(1); 5744 if ((ctxt->value == NULL) || 5745 ((ctxt->value->type != XPATH_NODESET) && 5746 (ctxt->value->type != XPATH_XSLT_TREE))) 5747 XP_ERROR(XPATH_INVALID_TYPE); 5748 cur = valuePop(ctxt); 5749 5750 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 5751 valuePush(ctxt, xmlXPathNewCString("")); 5752 } else { 5753 int i = 0; /* Should be first in document order !!!!! */ 5754 switch (cur->nodesetval->nodeTab[i]->type) { 5755 case XML_ELEMENT_NODE: 5756 case XML_ATTRIBUTE_NODE: 5757 case XML_PI_NODE: 5758 valuePush(ctxt, 5759 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name)); 5760 break; 5761 case XML_NAMESPACE_DECL: 5762 valuePush(ctxt, xmlXPathNewString( 5763 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix)); 5764 break; 5765 default: 5766 valuePush(ctxt, xmlXPathNewCString("")); 5767 } 5768 } 5769 xmlXPathFreeObject(cur); 5770} 5771 5772/** 5773 * xmlXPathNamespaceURIFunction: 5774 * @ctxt: the XPath Parser context 5775 * @nargs: the number of arguments 5776 * 5777 * Implement the namespace-uri() XPath function 5778 * string namespace-uri(node-set?) 5779 * The namespace-uri function returns a string containing the 5780 * namespace URI of the expanded name of the node in the argument 5781 * node-set that is first in document order. If the node-set is empty, 5782 * the first node has no name, or the expanded name has no namespace 5783 * URI, an empty string is returned. If the argument is omitted it 5784 * defaults to the context node. 5785 */ 5786void 5787xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5788 xmlXPathObjectPtr cur; 5789 5790 if (nargs == 0) { 5791 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 5792 nargs = 1; 5793 } 5794 CHECK_ARITY(1); 5795 if ((ctxt->value == NULL) || 5796 ((ctxt->value->type != XPATH_NODESET) && 5797 (ctxt->value->type != XPATH_XSLT_TREE))) 5798 XP_ERROR(XPATH_INVALID_TYPE); 5799 cur = valuePop(ctxt); 5800 5801 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 5802 valuePush(ctxt, xmlXPathNewCString("")); 5803 } else { 5804 int i = 0; /* Should be first in document order !!!!! */ 5805 switch (cur->nodesetval->nodeTab[i]->type) { 5806 case XML_ELEMENT_NODE: 5807 case XML_ATTRIBUTE_NODE: 5808 if (cur->nodesetval->nodeTab[i]->ns == NULL) 5809 valuePush(ctxt, xmlXPathNewCString("")); 5810 else 5811 valuePush(ctxt, xmlXPathNewString( 5812 cur->nodesetval->nodeTab[i]->ns->href)); 5813 break; 5814 default: 5815 valuePush(ctxt, xmlXPathNewCString("")); 5816 } 5817 } 5818 xmlXPathFreeObject(cur); 5819} 5820 5821/** 5822 * xmlXPathNameFunction: 5823 * @ctxt: the XPath Parser context 5824 * @nargs: the number of arguments 5825 * 5826 * Implement the name() XPath function 5827 * string name(node-set?) 5828 * The name function returns a string containing a QName representing 5829 * the name of the node in the argument node-set that is first in document 5830 * order. The QName must represent the name with respect to the namespace 5831 * declarations in effect on the node whose name is being represented. 5832 * Typically, this will be the form in which the name occurred in the XML 5833 * source. This need not be the case if there are namespace declarations 5834 * in effect on the node that associate multiple prefixes with the same 5835 * namespace. However, an implementation may include information about 5836 * the original prefix in its representation of nodes; in this case, an 5837 * implementation can ensure that the returned string is always the same 5838 * as the QName used in the XML source. If the argument it omitted it 5839 * defaults to the context node. 5840 * Libxml keep the original prefix so the "real qualified name" used is 5841 * returned. 5842 */ 5843static void 5844xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) 5845{ 5846 xmlXPathObjectPtr cur; 5847 5848 if (nargs == 0) { 5849 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 5850 nargs = 1; 5851 } 5852 5853 CHECK_ARITY(1); 5854 if ((ctxt->value == NULL) || 5855 ((ctxt->value->type != XPATH_NODESET) && 5856 (ctxt->value->type != XPATH_XSLT_TREE))) 5857 XP_ERROR(XPATH_INVALID_TYPE); 5858 cur = valuePop(ctxt); 5859 5860 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 5861 valuePush(ctxt, xmlXPathNewCString("")); 5862 } else { 5863 int i = 0; /* Should be first in document order !!!!! */ 5864 5865 switch (cur->nodesetval->nodeTab[i]->type) { 5866 case XML_ELEMENT_NODE: 5867 case XML_ATTRIBUTE_NODE: 5868 if ((cur->nodesetval->nodeTab[i]->ns == NULL) || 5869 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) 5870 valuePush(ctxt, 5871 xmlXPathNewString(cur->nodesetval-> 5872 nodeTab[i]->name)); 5873 5874 else { 5875 char name[2000]; 5876 5877 snprintf(name, sizeof(name), "%s:%s", 5878 (char *) cur->nodesetval->nodeTab[i]->ns-> 5879 prefix, 5880 (char *) cur->nodesetval->nodeTab[i]->name); 5881 name[sizeof(name) - 1] = 0; 5882 valuePush(ctxt, xmlXPathNewCString(name)); 5883 } 5884 break; 5885 default: 5886 valuePush(ctxt, 5887 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i])); 5888 xmlXPathLocalNameFunction(ctxt, 1); 5889 } 5890 } 5891 xmlXPathFreeObject(cur); 5892} 5893 5894 5895/** 5896 * xmlXPathStringFunction: 5897 * @ctxt: the XPath Parser context 5898 * @nargs: the number of arguments 5899 * 5900 * Implement the string() XPath function 5901 * string string(object?) 5902 * he string function converts an object to a string as follows: 5903 * - A node-set is converted to a string by returning the value of 5904 * the node in the node-set that is first in document order. 5905 * If the node-set is empty, an empty string is returned. 5906 * - A number is converted to a string as follows 5907 * + NaN is converted to the string NaN 5908 * + positive zero is converted to the string 0 5909 * + negative zero is converted to the string 0 5910 * + positive infinity is converted to the string Infinity 5911 * + negative infinity is converted to the string -Infinity 5912 * + if the number is an integer, the number is represented in 5913 * decimal form as a Number with no decimal point and no leading 5914 * zeros, preceded by a minus sign (-) if the number is negative 5915 * + otherwise, the number is represented in decimal form as a 5916 * Number including a decimal point with at least one digit 5917 * before the decimal point and at least one digit after the 5918 * decimal point, preceded by a minus sign (-) if the number 5919 * is negative; there must be no leading zeros before the decimal 5920 * point apart possibly from the one required digit immediately 5921 * before the decimal point; beyond the one required digit 5922 * after the decimal point there must be as many, but only as 5923 * many, more digits as are needed to uniquely distinguish the 5924 * number from all other IEEE 754 numeric values. 5925 * - The boolean false value is converted to the string false. 5926 * The boolean true value is converted to the string true. 5927 * 5928 * If the argument is omitted, it defaults to a node-set with the 5929 * context node as its only member. 5930 */ 5931void 5932xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5933 xmlXPathObjectPtr cur; 5934 5935 if (nargs == 0) { 5936 valuePush(ctxt, 5937 xmlXPathWrapString( 5938 xmlXPathCastNodeToString(ctxt->context->node))); 5939 return; 5940 } 5941 5942 CHECK_ARITY(1); 5943 cur = valuePop(ctxt); 5944 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 5945 cur = xmlXPathConvertString(cur); 5946 valuePush(ctxt, cur); 5947} 5948 5949/** 5950 * xmlXPathStringLengthFunction: 5951 * @ctxt: the XPath Parser context 5952 * @nargs: the number of arguments 5953 * 5954 * Implement the string-length() XPath function 5955 * number string-length(string?) 5956 * The string-length returns the number of characters in the string 5957 * (see [3.6 Strings]). If the argument is omitted, it defaults to 5958 * the context node converted to a string, in other words the value 5959 * of the context node. 5960 */ 5961void 5962xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5963 xmlXPathObjectPtr cur; 5964 5965 if (nargs == 0) { 5966 if (ctxt->context->node == NULL) { 5967 valuePush(ctxt, xmlXPathNewFloat(0)); 5968 } else { 5969 xmlChar *content; 5970 5971 content = xmlXPathCastNodeToString(ctxt->context->node); 5972 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content))); 5973 xmlFree(content); 5974 } 5975 return; 5976 } 5977 CHECK_ARITY(1); 5978 CAST_TO_STRING; 5979 CHECK_TYPE(XPATH_STRING); 5980 cur = valuePop(ctxt); 5981 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval))); 5982 xmlXPathFreeObject(cur); 5983} 5984 5985/** 5986 * xmlXPathConcatFunction: 5987 * @ctxt: the XPath Parser context 5988 * @nargs: the number of arguments 5989 * 5990 * Implement the concat() XPath function 5991 * string concat(string, string, string*) 5992 * The concat function returns the concatenation of its arguments. 5993 */ 5994void 5995xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) { 5996 xmlXPathObjectPtr cur, newobj; 5997 xmlChar *tmp; 5998 5999 if (nargs < 2) { 6000 CHECK_ARITY(2); 6001 } 6002 6003 CAST_TO_STRING; 6004 cur = valuePop(ctxt); 6005 if ((cur == NULL) || (cur->type != XPATH_STRING)) { 6006 xmlXPathFreeObject(cur); 6007 return; 6008 } 6009 nargs--; 6010 6011 while (nargs > 0) { 6012 CAST_TO_STRING; 6013 newobj = valuePop(ctxt); 6014 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) { 6015 xmlXPathFreeObject(newobj); 6016 xmlXPathFreeObject(cur); 6017 XP_ERROR(XPATH_INVALID_TYPE); 6018 } 6019 tmp = xmlStrcat(newobj->stringval, cur->stringval); 6020 newobj->stringval = cur->stringval; 6021 cur->stringval = tmp; 6022 6023 xmlXPathFreeObject(newobj); 6024 nargs--; 6025 } 6026 valuePush(ctxt, cur); 6027} 6028 6029/** 6030 * xmlXPathContainsFunction: 6031 * @ctxt: the XPath Parser context 6032 * @nargs: the number of arguments 6033 * 6034 * Implement the contains() XPath function 6035 * boolean contains(string, string) 6036 * The contains function returns true if the first argument string 6037 * contains the second argument string, and otherwise returns false. 6038 */ 6039void 6040xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6041 xmlXPathObjectPtr hay, needle; 6042 6043 CHECK_ARITY(2); 6044 CAST_TO_STRING; 6045 CHECK_TYPE(XPATH_STRING); 6046 needle = valuePop(ctxt); 6047 CAST_TO_STRING; 6048 hay = valuePop(ctxt); 6049 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 6050 xmlXPathFreeObject(hay); 6051 xmlXPathFreeObject(needle); 6052 XP_ERROR(XPATH_INVALID_TYPE); 6053 } 6054 if (xmlStrstr(hay->stringval, needle->stringval)) 6055 valuePush(ctxt, xmlXPathNewBoolean(1)); 6056 else 6057 valuePush(ctxt, xmlXPathNewBoolean(0)); 6058 xmlXPathFreeObject(hay); 6059 xmlXPathFreeObject(needle); 6060} 6061 6062/** 6063 * xmlXPathStartsWithFunction: 6064 * @ctxt: the XPath Parser context 6065 * @nargs: the number of arguments 6066 * 6067 * Implement the starts-with() XPath function 6068 * boolean starts-with(string, string) 6069 * The starts-with function returns true if the first argument string 6070 * starts with the second argument string, and otherwise returns false. 6071 */ 6072void 6073xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6074 xmlXPathObjectPtr hay, needle; 6075 int n; 6076 6077 CHECK_ARITY(2); 6078 CAST_TO_STRING; 6079 CHECK_TYPE(XPATH_STRING); 6080 needle = valuePop(ctxt); 6081 CAST_TO_STRING; 6082 hay = valuePop(ctxt); 6083 if ((hay == NULL) || (hay->type != XPATH_STRING)) { 6084 xmlXPathFreeObject(hay); 6085 xmlXPathFreeObject(needle); 6086 XP_ERROR(XPATH_INVALID_TYPE); 6087 } 6088 n = xmlStrlen(needle->stringval); 6089 if (xmlStrncmp(hay->stringval, needle->stringval, n)) 6090 valuePush(ctxt, xmlXPathNewBoolean(0)); 6091 else 6092 valuePush(ctxt, xmlXPathNewBoolean(1)); 6093 xmlXPathFreeObject(hay); 6094 xmlXPathFreeObject(needle); 6095} 6096 6097/** 6098 * xmlXPathSubstringFunction: 6099 * @ctxt: the XPath Parser context 6100 * @nargs: the number of arguments 6101 * 6102 * Implement the substring() XPath function 6103 * string substring(string, number, number?) 6104 * The substring function returns the substring of the first argument 6105 * starting at the position specified in the second argument with 6106 * length specified in the third argument. For example, 6107 * substring("12345",2,3) returns "234". If the third argument is not 6108 * specified, it returns the substring starting at the position specified 6109 * in the second argument and continuing to the end of the string. For 6110 * example, substring("12345",2) returns "2345". More precisely, each 6111 * character in the string (see [3.6 Strings]) is considered to have a 6112 * numeric position: the position of the first character is 1, the position 6113 * of the second character is 2 and so on. The returned substring contains 6114 * those characters for which the position of the character is greater than 6115 * or equal to the second argument and, if the third argument is specified, 6116 * less than the sum of the second and third arguments; the comparisons 6117 * and addition used for the above follow the standard IEEE 754 rules. Thus: 6118 * - substring("12345", 1.5, 2.6) returns "234" 6119 * - substring("12345", 0, 3) returns "12" 6120 * - substring("12345", 0 div 0, 3) returns "" 6121 * - substring("12345", 1, 0 div 0) returns "" 6122 * - substring("12345", -42, 1 div 0) returns "12345" 6123 * - substring("12345", -1 div 0, 1 div 0) returns "" 6124 */ 6125void 6126xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6127 xmlXPathObjectPtr str, start, len; 6128 double le=0, in; 6129 int i, l, m; 6130 xmlChar *ret; 6131 6132 if (nargs < 2) { 6133 CHECK_ARITY(2); 6134 } 6135 if (nargs > 3) { 6136 CHECK_ARITY(3); 6137 } 6138 /* 6139 * take care of possible last (position) argument 6140 */ 6141 if (nargs == 3) { 6142 CAST_TO_NUMBER; 6143 CHECK_TYPE(XPATH_NUMBER); 6144 len = valuePop(ctxt); 6145 le = len->floatval; 6146 xmlXPathFreeObject(len); 6147 } 6148 6149 CAST_TO_NUMBER; 6150 CHECK_TYPE(XPATH_NUMBER); 6151 start = valuePop(ctxt); 6152 in = start->floatval; 6153 xmlXPathFreeObject(start); 6154 CAST_TO_STRING; 6155 CHECK_TYPE(XPATH_STRING); 6156 str = valuePop(ctxt); 6157 m = xmlUTF8Strlen((const unsigned char *)str->stringval); 6158 6159 /* 6160 * If last pos not present, calculate last position 6161 */ 6162 if (nargs != 3) 6163 le = m; 6164 6165 /* Need to check for the special cases where either 6166 * the index is NaN, the length is NaN, or both 6167 * arguments are infinity (relying on Inf + -Inf = NaN) 6168 */ 6169 if (!xmlXPathIsNaN(in + le)) { 6170 /* 6171 * To meet our requirements, initial index calculations 6172 * must be done before we convert to integer format 6173 * 6174 * First we normalize indices 6175 */ 6176 in -= 1.0; 6177 le += in; 6178 if (in < 0.0) 6179 in = 0.0; 6180 if (le > (double)m) 6181 le = (double)m; 6182 6183 /* 6184 * Now we go to integer form, rounding up 6185 */ 6186 i = (int) in; 6187 if (((double)i) != in) i++; 6188 6189 l = (int) le; 6190 if (((double)l) != le) l++; 6191 6192 if (l > m) l=m; 6193 6194 /* number of chars to copy */ 6195 l -= i; 6196 6197 ret = xmlUTF8Strsub(str->stringval, i, l); 6198 } 6199 else { 6200 ret = NULL; 6201 } 6202 6203 if (ret == NULL) 6204 valuePush(ctxt, xmlXPathNewCString("")); 6205 else { 6206 valuePush(ctxt, xmlXPathNewString(ret)); 6207 xmlFree(ret); 6208 } 6209 6210 xmlXPathFreeObject(str); 6211} 6212 6213/** 6214 * xmlXPathSubstringBeforeFunction: 6215 * @ctxt: the XPath Parser context 6216 * @nargs: the number of arguments 6217 * 6218 * Implement the substring-before() XPath function 6219 * string substring-before(string, string) 6220 * The substring-before function returns the substring of the first 6221 * argument string that precedes the first occurrence of the second 6222 * argument string in the first argument string, or the empty string 6223 * if the first argument string does not contain the second argument 6224 * string. For example, substring-before("1999/04/01","/") returns 1999. 6225 */ 6226void 6227xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6228 xmlXPathObjectPtr str; 6229 xmlXPathObjectPtr find; 6230 xmlBufferPtr target; 6231 const xmlChar *point; 6232 int offset; 6233 6234 CHECK_ARITY(2); 6235 CAST_TO_STRING; 6236 find = valuePop(ctxt); 6237 CAST_TO_STRING; 6238 str = valuePop(ctxt); 6239 6240 target = xmlBufferCreate(); 6241 if (target) { 6242 point = xmlStrstr(str->stringval, find->stringval); 6243 if (point) { 6244 offset = (int)(point - str->stringval); 6245 xmlBufferAdd(target, str->stringval, offset); 6246 } 6247 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6248 xmlBufferFree(target); 6249 } 6250 6251 xmlXPathFreeObject(str); 6252 xmlXPathFreeObject(find); 6253} 6254 6255/** 6256 * xmlXPathSubstringAfterFunction: 6257 * @ctxt: the XPath Parser context 6258 * @nargs: the number of arguments 6259 * 6260 * Implement the substring-after() XPath function 6261 * string substring-after(string, string) 6262 * The substring-after function returns the substring of the first 6263 * argument string that follows the first occurrence of the second 6264 * argument string in the first argument string, or the empty stringi 6265 * if the first argument string does not contain the second argument 6266 * string. For example, substring-after("1999/04/01","/") returns 04/01, 6267 * and substring-after("1999/04/01","19") returns 99/04/01. 6268 */ 6269void 6270xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6271 xmlXPathObjectPtr str; 6272 xmlXPathObjectPtr find; 6273 xmlBufferPtr target; 6274 const xmlChar *point; 6275 int offset; 6276 6277 CHECK_ARITY(2); 6278 CAST_TO_STRING; 6279 find = valuePop(ctxt); 6280 CAST_TO_STRING; 6281 str = valuePop(ctxt); 6282 6283 target = xmlBufferCreate(); 6284 if (target) { 6285 point = xmlStrstr(str->stringval, find->stringval); 6286 if (point) { 6287 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval); 6288 xmlBufferAdd(target, &str->stringval[offset], 6289 xmlStrlen(str->stringval) - offset); 6290 } 6291 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6292 xmlBufferFree(target); 6293 } 6294 6295 xmlXPathFreeObject(str); 6296 xmlXPathFreeObject(find); 6297} 6298 6299/** 6300 * xmlXPathNormalizeFunction: 6301 * @ctxt: the XPath Parser context 6302 * @nargs: the number of arguments 6303 * 6304 * Implement the normalize-space() XPath function 6305 * string normalize-space(string?) 6306 * The normalize-space function returns the argument string with white 6307 * space normalized by stripping leading and trailing whitespace 6308 * and replacing sequences of whitespace characters by a single 6309 * space. Whitespace characters are the same allowed by the S production 6310 * in XML. If the argument is omitted, it defaults to the context 6311 * node converted to a string, in other words the value of the context node. 6312 */ 6313void 6314xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6315 xmlXPathObjectPtr obj = NULL; 6316 xmlChar *source = NULL; 6317 xmlBufferPtr target; 6318 xmlChar blank; 6319 6320 if (nargs == 0) { 6321 /* Use current context node */ 6322 valuePush(ctxt, 6323 xmlXPathWrapString( 6324 xmlXPathCastNodeToString(ctxt->context->node))); 6325 nargs = 1; 6326 } 6327 6328 CHECK_ARITY(1); 6329 CAST_TO_STRING; 6330 CHECK_TYPE(XPATH_STRING); 6331 obj = valuePop(ctxt); 6332 source = obj->stringval; 6333 6334 target = xmlBufferCreate(); 6335 if (target && source) { 6336 6337 /* Skip leading whitespaces */ 6338 while (IS_BLANK(*source)) 6339 source++; 6340 6341 /* Collapse intermediate whitespaces, and skip trailing whitespaces */ 6342 blank = 0; 6343 while (*source) { 6344 if (IS_BLANK(*source)) { 6345 blank = 0x20; 6346 } else { 6347 if (blank) { 6348 xmlBufferAdd(target, &blank, 1); 6349 blank = 0; 6350 } 6351 xmlBufferAdd(target, source, 1); 6352 } 6353 source++; 6354 } 6355 6356 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6357 xmlBufferFree(target); 6358 } 6359 xmlXPathFreeObject(obj); 6360} 6361 6362/** 6363 * xmlXPathTranslateFunction: 6364 * @ctxt: the XPath Parser context 6365 * @nargs: the number of arguments 6366 * 6367 * Implement the translate() XPath function 6368 * string translate(string, string, string) 6369 * The translate function returns the first argument string with 6370 * occurrences of characters in the second argument string replaced 6371 * by the character at the corresponding position in the third argument 6372 * string. For example, translate("bar","abc","ABC") returns the string 6373 * BAr. If there is a character in the second argument string with no 6374 * character at a corresponding position in the third argument string 6375 * (because the second argument string is longer than the third argument 6376 * string), then occurrences of that character in the first argument 6377 * string are removed. For example, translate("--aaa--","abc-","ABC") 6378 * returns "AAA". If a character occurs more than once in second 6379 * argument string, then the first occurrence determines the replacement 6380 * character. If the third argument string is longer than the second 6381 * argument string, then excess characters are ignored. 6382 */ 6383void 6384xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6385 xmlXPathObjectPtr str; 6386 xmlXPathObjectPtr from; 6387 xmlXPathObjectPtr to; 6388 xmlBufferPtr target; 6389 int offset, max; 6390 xmlChar ch; 6391 xmlChar *point; 6392 xmlChar *cptr; 6393 6394 CHECK_ARITY(3); 6395 6396 CAST_TO_STRING; 6397 to = valuePop(ctxt); 6398 CAST_TO_STRING; 6399 from = valuePop(ctxt); 6400 CAST_TO_STRING; 6401 str = valuePop(ctxt); 6402 6403 target = xmlBufferCreate(); 6404 if (target) { 6405 max = xmlUTF8Strlen(to->stringval); 6406 for (cptr = str->stringval; (ch=*cptr); ) { 6407 offset = xmlUTF8Strloc(from->stringval, cptr); 6408 if (offset >= 0) { 6409 if (offset < max) { 6410 point = xmlUTF8Strpos(to->stringval, offset); 6411 if (point) 6412 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1)); 6413 } 6414 } else 6415 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1)); 6416 6417 /* Step to next character in input */ 6418 cptr++; 6419 if ( ch & 0x80 ) { 6420 /* if not simple ascii, verify proper format */ 6421 if ( (ch & 0xc0) != 0xc0 ) { 6422 xmlGenericError(xmlGenericErrorContext, 6423 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 6424 break; 6425 } 6426 /* then skip over remaining bytes for this char */ 6427 while ( (ch <<= 1) & 0x80 ) 6428 if ( (*cptr++ & 0xc0) != 0x80 ) { 6429 xmlGenericError(xmlGenericErrorContext, 6430 "xmlXPathTranslateFunction: Invalid UTF8 string\n"); 6431 break; 6432 } 6433 if (ch & 0x80) /* must have had error encountered */ 6434 break; 6435 } 6436 } 6437 } 6438 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target))); 6439 xmlBufferFree(target); 6440 xmlXPathFreeObject(str); 6441 xmlXPathFreeObject(from); 6442 xmlXPathFreeObject(to); 6443} 6444 6445/** 6446 * xmlXPathBooleanFunction: 6447 * @ctxt: the XPath Parser context 6448 * @nargs: the number of arguments 6449 * 6450 * Implement the boolean() XPath function 6451 * boolean boolean(object) 6452 * he boolean function converts its argument to a boolean as follows: 6453 * - a number is true if and only if it is neither positive or 6454 * negative zero nor NaN 6455 * - a node-set is true if and only if it is non-empty 6456 * - a string is true if and only if its length is non-zero 6457 */ 6458void 6459xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6460 xmlXPathObjectPtr cur; 6461 6462 CHECK_ARITY(1); 6463 cur = valuePop(ctxt); 6464 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND); 6465 cur = xmlXPathConvertBoolean(cur); 6466 valuePush(ctxt, cur); 6467} 6468 6469/** 6470 * xmlXPathNotFunction: 6471 * @ctxt: the XPath Parser context 6472 * @nargs: the number of arguments 6473 * 6474 * Implement the not() XPath function 6475 * boolean not(boolean) 6476 * The not function returns true if its argument is false, 6477 * and false otherwise. 6478 */ 6479void 6480xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6481 CHECK_ARITY(1); 6482 CAST_TO_BOOLEAN; 6483 CHECK_TYPE(XPATH_BOOLEAN); 6484 ctxt->value->boolval = ! ctxt->value->boolval; 6485} 6486 6487/** 6488 * xmlXPathTrueFunction: 6489 * @ctxt: the XPath Parser context 6490 * @nargs: the number of arguments 6491 * 6492 * Implement the true() XPath function 6493 * boolean true() 6494 */ 6495void 6496xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6497 CHECK_ARITY(0); 6498 valuePush(ctxt, xmlXPathNewBoolean(1)); 6499} 6500 6501/** 6502 * xmlXPathFalseFunction: 6503 * @ctxt: the XPath Parser context 6504 * @nargs: the number of arguments 6505 * 6506 * Implement the false() XPath function 6507 * boolean false() 6508 */ 6509void 6510xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6511 CHECK_ARITY(0); 6512 valuePush(ctxt, xmlXPathNewBoolean(0)); 6513} 6514 6515/** 6516 * xmlXPathLangFunction: 6517 * @ctxt: the XPath Parser context 6518 * @nargs: the number of arguments 6519 * 6520 * Implement the lang() XPath function 6521 * boolean lang(string) 6522 * The lang function returns true or false depending on whether the 6523 * language of the context node as specified by xml:lang attributes 6524 * is the same as or is a sublanguage of the language specified by 6525 * the argument string. The language of the context node is determined 6526 * by the value of the xml:lang attribute on the context node, or, if 6527 * the context node has no xml:lang attribute, by the value of the 6528 * xml:lang attribute on the nearest ancestor of the context node that 6529 * has an xml:lang attribute. If there is no such attribute, then lang 6530 * returns false. If there is such an attribute, then lang returns 6531 * true if the attribute value is equal to the argument ignoring case, 6532 * or if there is some suffix starting with - such that the attribute 6533 * value is equal to the argument ignoring that suffix of the attribute 6534 * value and ignoring case. 6535 */ 6536void 6537xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6538 xmlXPathObjectPtr val; 6539 const xmlChar *theLang; 6540 const xmlChar *lang; 6541 int ret = 0; 6542 int i; 6543 6544 CHECK_ARITY(1); 6545 CAST_TO_STRING; 6546 CHECK_TYPE(XPATH_STRING); 6547 val = valuePop(ctxt); 6548 lang = val->stringval; 6549 theLang = xmlNodeGetLang(ctxt->context->node); 6550 if ((theLang != NULL) && (lang != NULL)) { 6551 for (i = 0;lang[i] != 0;i++) 6552 if (toupper(lang[i]) != toupper(theLang[i])) 6553 goto not_equal; 6554 ret = 1; 6555 } 6556not_equal: 6557 xmlXPathFreeObject(val); 6558 valuePush(ctxt, xmlXPathNewBoolean(ret)); 6559} 6560 6561/** 6562 * xmlXPathNumberFunction: 6563 * @ctxt: the XPath Parser context 6564 * @nargs: the number of arguments 6565 * 6566 * Implement the number() XPath function 6567 * number number(object?) 6568 */ 6569void 6570xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6571 xmlXPathObjectPtr cur; 6572 double res; 6573 6574 if (nargs == 0) { 6575 if (ctxt->context->node == NULL) { 6576 valuePush(ctxt, xmlXPathNewFloat(0.0)); 6577 } else { 6578 xmlChar* content = xmlNodeGetContent(ctxt->context->node); 6579 6580 res = xmlXPathStringEvalNumber(content); 6581 valuePush(ctxt, xmlXPathNewFloat(res)); 6582 xmlFree(content); 6583 } 6584 return; 6585 } 6586 6587 CHECK_ARITY(1); 6588 cur = valuePop(ctxt); 6589 cur = xmlXPathConvertNumber(cur); 6590 valuePush(ctxt, cur); 6591} 6592 6593/** 6594 * xmlXPathSumFunction: 6595 * @ctxt: the XPath Parser context 6596 * @nargs: the number of arguments 6597 * 6598 * Implement the sum() XPath function 6599 * number sum(node-set) 6600 * The sum function returns the sum of the values of the nodes in 6601 * the argument node-set. 6602 */ 6603void 6604xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6605 xmlXPathObjectPtr cur; 6606 int i; 6607 double res = 0.0; 6608 6609 CHECK_ARITY(1); 6610 if ((ctxt->value == NULL) || 6611 ((ctxt->value->type != XPATH_NODESET) && 6612 (ctxt->value->type != XPATH_XSLT_TREE))) 6613 XP_ERROR(XPATH_INVALID_TYPE); 6614 cur = valuePop(ctxt); 6615 6616 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) { 6617 valuePush(ctxt, xmlXPathNewFloat(0.0)); 6618 } else { 6619 for (i = 0; i < cur->nodesetval->nodeNr; i++) { 6620 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]); 6621 } 6622 valuePush(ctxt, xmlXPathNewFloat(res)); 6623 } 6624 xmlXPathFreeObject(cur); 6625} 6626 6627/** 6628 * xmlXPathFloorFunction: 6629 * @ctxt: the XPath Parser context 6630 * @nargs: the number of arguments 6631 * 6632 * Implement the floor() XPath function 6633 * number floor(number) 6634 * The floor function returns the largest (closest to positive infinity) 6635 * number that is not greater than the argument and that is an integer. 6636 */ 6637void 6638xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6639 double f; 6640 6641 CHECK_ARITY(1); 6642 CAST_TO_NUMBER; 6643 CHECK_TYPE(XPATH_NUMBER); 6644 6645 f = (double)((int) ctxt->value->floatval); 6646 if (f != ctxt->value->floatval) { 6647 if (ctxt->value->floatval > 0) 6648 ctxt->value->floatval = f; 6649 else 6650 ctxt->value->floatval = f - 1; 6651 } 6652} 6653 6654/** 6655 * xmlXPathCeilingFunction: 6656 * @ctxt: the XPath Parser context 6657 * @nargs: the number of arguments 6658 * 6659 * Implement the ceiling() XPath function 6660 * number ceiling(number) 6661 * The ceiling function returns the smallest (closest to negative infinity) 6662 * number that is not less than the argument and that is an integer. 6663 */ 6664void 6665xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6666 double f; 6667 6668 CHECK_ARITY(1); 6669 CAST_TO_NUMBER; 6670 CHECK_TYPE(XPATH_NUMBER); 6671 6672#if 0 6673 ctxt->value->floatval = ceil(ctxt->value->floatval); 6674#else 6675 f = (double)((int) ctxt->value->floatval); 6676 if (f != ctxt->value->floatval) { 6677 if (ctxt->value->floatval > 0) 6678 ctxt->value->floatval = f + 1; 6679 else { 6680 if (ctxt->value->floatval < 0 && f == 0) 6681 ctxt->value->floatval = xmlXPathNZERO; 6682 else 6683 ctxt->value->floatval = f; 6684 } 6685 6686 } 6687#endif 6688} 6689 6690/** 6691 * xmlXPathRoundFunction: 6692 * @ctxt: the XPath Parser context 6693 * @nargs: the number of arguments 6694 * 6695 * Implement the round() XPath function 6696 * number round(number) 6697 * The round function returns the number that is closest to the 6698 * argument and that is an integer. If there are two such numbers, 6699 * then the one that is even is returned. 6700 */ 6701void 6702xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) { 6703 double f; 6704 6705 CHECK_ARITY(1); 6706 CAST_TO_NUMBER; 6707 CHECK_TYPE(XPATH_NUMBER); 6708 6709 if ((xmlXPathIsNaN(ctxt->value->floatval)) || 6710 (xmlXPathIsInf(ctxt->value->floatval) == 1) || 6711 (xmlXPathIsInf(ctxt->value->floatval) == -1) || 6712 (ctxt->value->floatval == 0.0)) 6713 return; 6714 6715 f = (double)((int) ctxt->value->floatval); 6716 if (ctxt->value->floatval < 0) { 6717 if (ctxt->value->floatval < f - 0.5) 6718 ctxt->value->floatval = f - 1; 6719 else 6720 ctxt->value->floatval = f; 6721 if (ctxt->value->floatval == 0) 6722 ctxt->value->floatval = xmlXPathNZERO; 6723 } else { 6724 if (ctxt->value->floatval < f + 0.5) 6725 ctxt->value->floatval = f; 6726 else 6727 ctxt->value->floatval = f + 1; 6728 } 6729} 6730 6731/************************************************************************ 6732 * * 6733 * The Parser * 6734 * * 6735 ************************************************************************/ 6736 6737/* 6738 * a couple of forward declarations since we use a recursive call based 6739 * implementation. 6740 */ 6741static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt); 6742static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter); 6743static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt); 6744#ifdef VMS 6745static void xmlXPathCompRelLocationPath(xmlXPathParserContextPtr ctxt); 6746#define xmlXPathCompRelativeLocationPath xmlXPathCompRelLocationPath 6747#else 6748static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt); 6749#endif 6750static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, 6751 int qualified); 6752 6753/** 6754 * xmlXPathCurrentChar: 6755 * @ctxt: the XPath parser context 6756 * @cur: pointer to the beginning of the char 6757 * @len: pointer to the length of the char read 6758 * 6759 * The current char value, if using UTF-8 this may actually span multiple 6760 * bytes in the input buffer. 6761 * 6762 * Returns the current char value and its length 6763 */ 6764 6765static int 6766xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) { 6767 unsigned char c; 6768 unsigned int val; 6769 const xmlChar *cur; 6770 6771 if (ctxt == NULL) 6772 return(0); 6773 cur = ctxt->cur; 6774 6775 /* 6776 * We are supposed to handle UTF8, check it's valid 6777 * From rfc2044: encoding of the Unicode values on UTF-8: 6778 * 6779 * UCS-4 range (hex.) UTF-8 octet sequence (binary) 6780 * 0000 0000-0000 007F 0xxxxxxx 6781 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx 6782 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx 6783 * 6784 * Check for the 0x110000 limit too 6785 */ 6786 c = *cur; 6787 if (c & 0x80) { 6788 if ((cur[1] & 0xc0) != 0x80) 6789 goto encoding_error; 6790 if ((c & 0xe0) == 0xe0) { 6791 6792 if ((cur[2] & 0xc0) != 0x80) 6793 goto encoding_error; 6794 if ((c & 0xf0) == 0xf0) { 6795 if (((c & 0xf8) != 0xf0) || 6796 ((cur[3] & 0xc0) != 0x80)) 6797 goto encoding_error; 6798 /* 4-byte code */ 6799 *len = 4; 6800 val = (cur[0] & 0x7) << 18; 6801 val |= (cur[1] & 0x3f) << 12; 6802 val |= (cur[2] & 0x3f) << 6; 6803 val |= cur[3] & 0x3f; 6804 } else { 6805 /* 3-byte code */ 6806 *len = 3; 6807 val = (cur[0] & 0xf) << 12; 6808 val |= (cur[1] & 0x3f) << 6; 6809 val |= cur[2] & 0x3f; 6810 } 6811 } else { 6812 /* 2-byte code */ 6813 *len = 2; 6814 val = (cur[0] & 0x1f) << 6; 6815 val |= cur[1] & 0x3f; 6816 } 6817 if (!IS_CHAR(val)) { 6818 XP_ERROR0(XPATH_INVALID_CHAR_ERROR); 6819 } 6820 return(val); 6821 } else { 6822 /* 1-byte code */ 6823 *len = 1; 6824 return((int) *cur); 6825 } 6826encoding_error: 6827 /* 6828 * If we detect an UTF8 error that probably mean that the 6829 * input encoding didn't get properly advertized in the 6830 * declaration header. Report the error and switch the encoding 6831 * to ISO-Latin-1 (if you don't like this policy, just declare the 6832 * encoding !) 6833 */ 6834 *len = 0; 6835 XP_ERROR0(XPATH_ENCODING_ERROR); 6836} 6837 6838/** 6839 * xmlXPathParseNCName: 6840 * @ctxt: the XPath Parser context 6841 * 6842 * parse an XML namespace non qualified name. 6843 * 6844 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)* 6845 * 6846 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' | 6847 * CombiningChar | Extender 6848 * 6849 * Returns the namespace name or NULL 6850 */ 6851 6852xmlChar * 6853xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { 6854 const xmlChar *in; 6855 xmlChar *ret; 6856 int count = 0; 6857 6858 /* 6859 * Accelerator for simple ASCII names 6860 */ 6861 in = ctxt->cur; 6862 if (((*in >= 0x61) && (*in <= 0x7A)) || 6863 ((*in >= 0x41) && (*in <= 0x5A)) || 6864 (*in == '_')) { 6865 in++; 6866 while (((*in >= 0x61) && (*in <= 0x7A)) || 6867 ((*in >= 0x41) && (*in <= 0x5A)) || 6868 ((*in >= 0x30) && (*in <= 0x39)) || 6869 (*in == '_') || (*in == '.') || 6870 (*in == '-')) 6871 in++; 6872 if ((*in == ' ') || (*in == '>') || (*in == '/') || 6873 (*in == '[') || (*in == ']') || (*in == ':') || 6874 (*in == '@') || (*in == '*')) { 6875 count = in - ctxt->cur; 6876 if (count == 0) 6877 return(NULL); 6878 ret = xmlStrndup(ctxt->cur, count); 6879 ctxt->cur = in; 6880 return(ret); 6881 } 6882 } 6883 return(xmlXPathParseNameComplex(ctxt, 0)); 6884} 6885 6886 6887/** 6888 * xmlXPathParseQName: 6889 * @ctxt: the XPath Parser context 6890 * @prefix: a xmlChar ** 6891 * 6892 * parse an XML qualified name 6893 * 6894 * [NS 5] QName ::= (Prefix ':')? LocalPart 6895 * 6896 * [NS 6] Prefix ::= NCName 6897 * 6898 * [NS 7] LocalPart ::= NCName 6899 * 6900 * Returns the function returns the local part, and prefix is updated 6901 * to get the Prefix if any. 6902 */ 6903 6904static xmlChar * 6905xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) { 6906 xmlChar *ret = NULL; 6907 6908 *prefix = NULL; 6909 ret = xmlXPathParseNCName(ctxt); 6910 if (CUR == ':') { 6911 *prefix = ret; 6912 NEXT; 6913 ret = xmlXPathParseNCName(ctxt); 6914 } 6915 return(ret); 6916} 6917 6918/** 6919 * xmlXPathParseName: 6920 * @ctxt: the XPath Parser context 6921 * 6922 * parse an XML name 6923 * 6924 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 6925 * CombiningChar | Extender 6926 * 6927 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 6928 * 6929 * Returns the namespace name or NULL 6930 */ 6931 6932xmlChar * 6933xmlXPathParseName(xmlXPathParserContextPtr ctxt) { 6934 const xmlChar *in; 6935 xmlChar *ret; 6936 int count = 0; 6937 6938 /* 6939 * Accelerator for simple ASCII names 6940 */ 6941 in = ctxt->cur; 6942 if (((*in >= 0x61) && (*in <= 0x7A)) || 6943 ((*in >= 0x41) && (*in <= 0x5A)) || 6944 (*in == '_') || (*in == ':')) { 6945 in++; 6946 while (((*in >= 0x61) && (*in <= 0x7A)) || 6947 ((*in >= 0x41) && (*in <= 0x5A)) || 6948 ((*in >= 0x30) && (*in <= 0x39)) || 6949 (*in == '_') || (*in == '-') || 6950 (*in == ':') || (*in == '.')) 6951 in++; 6952 if ((*in > 0) && (*in < 0x80)) { 6953 count = in - ctxt->cur; 6954 ret = xmlStrndup(ctxt->cur, count); 6955 ctxt->cur = in; 6956 return(ret); 6957 } 6958 } 6959 return(xmlXPathParseNameComplex(ctxt, 1)); 6960} 6961 6962static xmlChar * 6963xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) { 6964 xmlChar buf[XML_MAX_NAMELEN + 5]; 6965 int len = 0, l; 6966 int c; 6967 6968 /* 6969 * Handler for more complex cases 6970 */ 6971 c = CUR_CHAR(l); 6972 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */ 6973 (c == '[') || (c == ']') || (c == '@') || /* accelerators */ 6974 (c == '*') || /* accelerators */ 6975 (!IS_LETTER(c) && (c != '_') && 6976 ((qualified) && (c != ':')))) { 6977 return(NULL); 6978 } 6979 6980 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */ 6981 ((IS_LETTER(c)) || (IS_DIGIT(c)) || 6982 (c == '.') || (c == '-') || 6983 (c == '_') || ((qualified) && (c == ':')) || 6984 (IS_COMBINING(c)) || 6985 (IS_EXTENDER(c)))) { 6986 COPY_BUF(l,buf,len,c); 6987 NEXTL(l); 6988 c = CUR_CHAR(l); 6989 if (len >= XML_MAX_NAMELEN) { 6990 /* 6991 * Okay someone managed to make a huge name, so he's ready to pay 6992 * for the processing speed. 6993 */ 6994 xmlChar *buffer; 6995 int max = len * 2; 6996 6997 buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar)); 6998 if (buffer == NULL) { 6999 XP_ERROR0(XPATH_MEMORY_ERROR); 7000 } 7001 memcpy(buffer, buf, len); 7002 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */ 7003 (c == '.') || (c == '-') || 7004 (c == '_') || ((qualified) && (c == ':')) || 7005 (IS_COMBINING(c)) || 7006 (IS_EXTENDER(c))) { 7007 if (len + 10 > max) { 7008 max *= 2; 7009 buffer = (xmlChar *) xmlRealloc(buffer, 7010 max * sizeof(xmlChar)); 7011 if (buffer == NULL) { 7012 XP_ERROR0(XPATH_MEMORY_ERROR); 7013 } 7014 } 7015 COPY_BUF(l,buffer,len,c); 7016 NEXTL(l); 7017 c = CUR_CHAR(l); 7018 } 7019 buffer[len] = 0; 7020 return(buffer); 7021 } 7022 } 7023 if (len == 0) 7024 return(NULL); 7025 return(xmlStrndup(buf, len)); 7026} 7027 7028#define MAX_FRAC 20 7029 7030static double my_pow10[MAX_FRAC] = { 7031 1.0, 10.0, 100.0, 1000.0, 10000.0, 7032 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 7033 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0, 7034 100000000000000.0, 7035 1000000000000000.0, 10000000000000000.0, 100000000000000000.0, 7036 1000000000000000000.0, 10000000000000000000.0 7037}; 7038 7039/** 7040 * xmlXPathStringEvalNumber: 7041 * @str: A string to scan 7042 * 7043 * [30a] Float ::= Number ('e' Digits?)? 7044 * 7045 * [30] Number ::= Digits ('.' Digits?)? 7046 * | '.' Digits 7047 * [31] Digits ::= [0-9]+ 7048 * 7049 * Compile a Number in the string 7050 * In complement of the Number expression, this function also handles 7051 * negative values : '-' Number. 7052 * 7053 * Returns the double value. 7054 */ 7055double 7056xmlXPathStringEvalNumber(const xmlChar *str) { 7057 const xmlChar *cur = str; 7058 double ret; 7059 int ok = 0; 7060 int isneg = 0; 7061 int exponent = 0; 7062 int is_exponent_negative = 0; 7063#ifdef __GNUC__ 7064 unsigned long tmp = 0; 7065 double temp; 7066#endif 7067 if (cur == NULL) return(0); 7068 while (IS_BLANK(*cur)) cur++; 7069 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) { 7070 return(xmlXPathNAN); 7071 } 7072 if (*cur == '-') { 7073 isneg = 1; 7074 cur++; 7075 } 7076 7077#ifdef __GNUC__ 7078 /* 7079 * tmp/temp is a workaround against a gcc compiler bug 7080 * http://veillard.com/gcc.bug 7081 */ 7082 ret = 0; 7083 while ((*cur >= '0') && (*cur <= '9')) { 7084 ret = ret * 10; 7085 tmp = (*cur - '0'); 7086 ok = 1; 7087 cur++; 7088 temp = (double) tmp; 7089 ret = ret + temp; 7090 } 7091#else 7092 ret = 0; 7093 while ((*cur >= '0') && (*cur <= '9')) { 7094 ret = ret * 10 + (*cur - '0'); 7095 ok = 1; 7096 cur++; 7097 } 7098#endif 7099 7100 if (*cur == '.') { 7101 int v, frac = 0; 7102 double fraction = 0; 7103 7104 cur++; 7105 if (((*cur < '0') || (*cur > '9')) && (!ok)) { 7106 return(xmlXPathNAN); 7107 } 7108 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) { 7109 v = (*cur - '0'); 7110 fraction = fraction * 10 + v; 7111 frac = frac + 1; 7112 cur++; 7113 } 7114 fraction /= my_pow10[frac]; 7115 ret = ret + fraction; 7116 while ((*cur >= '0') && (*cur <= '9')) 7117 cur++; 7118 } 7119 if ((*cur == 'e') || (*cur == 'E')) { 7120 cur++; 7121 if (*cur == '-') { 7122 is_exponent_negative = 1; 7123 cur++; 7124 } 7125 while ((*cur >= '0') && (*cur <= '9')) { 7126 exponent = exponent * 10 + (*cur - '0'); 7127 cur++; 7128 } 7129 } 7130 while (IS_BLANK(*cur)) cur++; 7131 if (*cur != 0) return(xmlXPathNAN); 7132 if (isneg) ret = -ret; 7133 if (is_exponent_negative) exponent = -exponent; 7134 ret *= pow(10.0, (double)exponent); 7135 return(ret); 7136} 7137 7138/** 7139 * xmlXPathCompNumber: 7140 * @ctxt: the XPath Parser context 7141 * 7142 * [30] Number ::= Digits ('.' Digits?)? 7143 * | '.' Digits 7144 * [31] Digits ::= [0-9]+ 7145 * 7146 * Compile a Number, then push it on the stack 7147 * 7148 */ 7149static void 7150xmlXPathCompNumber(xmlXPathParserContextPtr ctxt) 7151{ 7152 double ret = 0.0; 7153 double mult = 1; 7154 int ok = 0; 7155 int exponent = 0; 7156 int is_exponent_negative = 0; 7157#ifdef __GNUC__ 7158 unsigned long tmp = 0; 7159 double temp; 7160#endif 7161 7162 CHECK_ERROR; 7163 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) { 7164 XP_ERROR(XPATH_NUMBER_ERROR); 7165 } 7166#ifdef __GNUC__ 7167 /* 7168 * tmp/temp is a workaround against a gcc compiler bug 7169 * http://veillard.com/gcc.bug 7170 */ 7171 ret = 0; 7172 while ((CUR >= '0') && (CUR <= '9')) { 7173 ret = ret * 10; 7174 tmp = (CUR - '0'); 7175 ok = 1; 7176 NEXT; 7177 temp = (double) tmp; 7178 ret = ret + temp; 7179 } 7180#else 7181 ret = 0; 7182 while ((CUR >= '0') && (CUR <= '9')) { 7183 ret = ret * 10 + (CUR - '0'); 7184 ok = 1; 7185 NEXT; 7186 } 7187#endif 7188 if (CUR == '.') { 7189 NEXT; 7190 if (((CUR < '0') || (CUR > '9')) && (!ok)) { 7191 XP_ERROR(XPATH_NUMBER_ERROR); 7192 } 7193 while ((CUR >= '0') && (CUR <= '9')) { 7194 mult /= 10; 7195 ret = ret + (CUR - '0') * mult; 7196 NEXT; 7197 } 7198 } 7199 if ((CUR == 'e') || (CUR == 'E')) { 7200 NEXT; 7201 if (CUR == '-') { 7202 is_exponent_negative = 1; 7203 NEXT; 7204 } 7205 while ((CUR >= '0') && (CUR <= '9')) { 7206 exponent = exponent * 10 + (CUR - '0'); 7207 NEXT; 7208 } 7209 if (is_exponent_negative) 7210 exponent = -exponent; 7211 ret *= pow(10.0, (double) exponent); 7212 } 7213 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, 7214 xmlXPathNewFloat(ret), NULL); 7215} 7216 7217/** 7218 * xmlXPathParseLiteral: 7219 * @ctxt: the XPath Parser context 7220 * 7221 * Parse a Literal 7222 * 7223 * [29] Literal ::= '"' [^"]* '"' 7224 * | "'" [^']* "'" 7225 * 7226 * Returns the value found or NULL in case of error 7227 */ 7228static xmlChar * 7229xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) { 7230 const xmlChar *q; 7231 xmlChar *ret = NULL; 7232 7233 if (CUR == '"') { 7234 NEXT; 7235 q = CUR_PTR; 7236 while ((IS_CHAR(CUR)) && (CUR != '"')) 7237 NEXT; 7238 if (!IS_CHAR(CUR)) { 7239 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR); 7240 } else { 7241 ret = xmlStrndup(q, CUR_PTR - q); 7242 NEXT; 7243 } 7244 } else if (CUR == '\'') { 7245 NEXT; 7246 q = CUR_PTR; 7247 while ((IS_CHAR(CUR)) && (CUR != '\'')) 7248 NEXT; 7249 if (!IS_CHAR(CUR)) { 7250 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR); 7251 } else { 7252 ret = xmlStrndup(q, CUR_PTR - q); 7253 NEXT; 7254 } 7255 } else { 7256 XP_ERROR0(XPATH_START_LITERAL_ERROR); 7257 } 7258 return(ret); 7259} 7260 7261/** 7262 * xmlXPathCompLiteral: 7263 * @ctxt: the XPath Parser context 7264 * 7265 * Parse a Literal and push it on the stack. 7266 * 7267 * [29] Literal ::= '"' [^"]* '"' 7268 * | "'" [^']* "'" 7269 * 7270 * TODO: xmlXPathCompLiteral memory allocation could be improved. 7271 */ 7272static void 7273xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) { 7274 const xmlChar *q; 7275 xmlChar *ret = NULL; 7276 7277 if (CUR == '"') { 7278 NEXT; 7279 q = CUR_PTR; 7280 while ((IS_CHAR(CUR)) && (CUR != '"')) 7281 NEXT; 7282 if (!IS_CHAR(CUR)) { 7283 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 7284 } else { 7285 ret = xmlStrndup(q, CUR_PTR - q); 7286 NEXT; 7287 } 7288 } else if (CUR == '\'') { 7289 NEXT; 7290 q = CUR_PTR; 7291 while ((IS_CHAR(CUR)) && (CUR != '\'')) 7292 NEXT; 7293 if (!IS_CHAR(CUR)) { 7294 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR); 7295 } else { 7296 ret = xmlStrndup(q, CUR_PTR - q); 7297 NEXT; 7298 } 7299 } else { 7300 XP_ERROR(XPATH_START_LITERAL_ERROR); 7301 } 7302 if (ret == NULL) return; 7303 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, 7304 xmlXPathNewString(ret), NULL); 7305 xmlFree(ret); 7306} 7307 7308/** 7309 * xmlXPathCompVariableReference: 7310 * @ctxt: the XPath Parser context 7311 * 7312 * Parse a VariableReference, evaluate it and push it on the stack. 7313 * 7314 * The variable bindings consist of a mapping from variable names 7315 * to variable values. The value of a variable is an object, which 7316 * of any of the types that are possible for the value of an expression, 7317 * and may also be of additional types not specified here. 7318 * 7319 * Early evaluation is possible since: 7320 * The variable bindings [...] used to evaluate a subexpression are 7321 * always the same as those used to evaluate the containing expression. 7322 * 7323 * [36] VariableReference ::= '$' QName 7324 */ 7325static void 7326xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) { 7327 xmlChar *name; 7328 xmlChar *prefix; 7329 7330 SKIP_BLANKS; 7331 if (CUR != '$') { 7332 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 7333 } 7334 NEXT; 7335 name = xmlXPathParseQName(ctxt, &prefix); 7336 if (name == NULL) { 7337 XP_ERROR(XPATH_VARIABLE_REF_ERROR); 7338 } 7339 ctxt->comp->last = -1; 7340 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, 7341 name, prefix); 7342 SKIP_BLANKS; 7343} 7344 7345/** 7346 * xmlXPathIsNodeType: 7347 * @ctxt: the XPath Parser context 7348 * @name: a name string 7349 * 7350 * Is the name given a NodeType one. 7351 * 7352 * [38] NodeType ::= 'comment' 7353 * | 'text' 7354 * | 'processing-instruction' 7355 * | 'node' 7356 * 7357 * Returns 1 if true 0 otherwise 7358 */ 7359int 7360xmlXPathIsNodeType(const xmlChar *name) { 7361 if (name == NULL) 7362 return(0); 7363 7364 if (xmlStrEqual(name, BAD_CAST "node")) 7365 return(1); 7366 if (xmlStrEqual(name, BAD_CAST "text")) 7367 return(1); 7368 if (xmlStrEqual(name, BAD_CAST "comment")) 7369 return(1); 7370 if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 7371 return(1); 7372 return(0); 7373} 7374 7375/** 7376 * xmlXPathCompFunctionCall: 7377 * @ctxt: the XPath Parser context 7378 * 7379 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')' 7380 * [17] Argument ::= Expr 7381 * 7382 * Compile a function call, the evaluation of all arguments are 7383 * pushed on the stack 7384 */ 7385static void 7386xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) { 7387 xmlChar *name; 7388 xmlChar *prefix; 7389 int nbargs = 0; 7390 7391 name = xmlXPathParseQName(ctxt, &prefix); 7392 if (name == NULL) { 7393 XP_ERROR(XPATH_EXPR_ERROR); 7394 } 7395 SKIP_BLANKS; 7396#ifdef DEBUG_EXPR 7397 if (prefix == NULL) 7398 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n", 7399 name); 7400 else 7401 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n", 7402 prefix, name); 7403#endif 7404 7405 if (CUR != '(') { 7406 XP_ERROR(XPATH_EXPR_ERROR); 7407 } 7408 NEXT; 7409 SKIP_BLANKS; 7410 7411 ctxt->comp->last = -1; 7412 while (CUR != ')') { 7413 int op1 = ctxt->comp->last; 7414 ctxt->comp->last = -1; 7415 xmlXPathCompileExpr(ctxt); 7416 CHECK_ERROR; 7417 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0); 7418 nbargs++; 7419 if (CUR == ')') break; 7420 if (CUR != ',') { 7421 XP_ERROR(XPATH_EXPR_ERROR); 7422 } 7423 NEXT; 7424 SKIP_BLANKS; 7425 } 7426 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, 7427 name, prefix); 7428 NEXT; 7429 SKIP_BLANKS; 7430} 7431 7432/** 7433 * xmlXPathCompPrimaryExpr: 7434 * @ctxt: the XPath Parser context 7435 * 7436 * [15] PrimaryExpr ::= VariableReference 7437 * | '(' Expr ')' 7438 * | Literal 7439 * | Number 7440 * | FunctionCall 7441 * 7442 * Compile a primary expression. 7443 */ 7444static void 7445xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) { 7446 SKIP_BLANKS; 7447 if (CUR == '$') xmlXPathCompVariableReference(ctxt); 7448 else if (CUR == '(') { 7449 NEXT; 7450 SKIP_BLANKS; 7451 xmlXPathCompileExpr(ctxt); 7452 CHECK_ERROR; 7453 if (CUR != ')') { 7454 XP_ERROR(XPATH_EXPR_ERROR); 7455 } 7456 NEXT; 7457 SKIP_BLANKS; 7458 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) { 7459 xmlXPathCompNumber(ctxt); 7460 } else if ((CUR == '\'') || (CUR == '"')) { 7461 xmlXPathCompLiteral(ctxt); 7462 } else { 7463 xmlXPathCompFunctionCall(ctxt); 7464 } 7465 SKIP_BLANKS; 7466} 7467 7468/** 7469 * xmlXPathCompFilterExpr: 7470 * @ctxt: the XPath Parser context 7471 * 7472 * [20] FilterExpr ::= PrimaryExpr 7473 * | FilterExpr Predicate 7474 * 7475 * Compile a filter expression. 7476 * Square brackets are used to filter expressions in the same way that 7477 * they are used in location paths. It is an error if the expression to 7478 * be filtered does not evaluate to a node-set. The context node list 7479 * used for evaluating the expression in square brackets is the node-set 7480 * to be filtered listed in document order. 7481 */ 7482 7483static void 7484xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) { 7485 xmlXPathCompPrimaryExpr(ctxt); 7486 CHECK_ERROR; 7487 SKIP_BLANKS; 7488 7489 while (CUR == '[') { 7490 xmlXPathCompPredicate(ctxt, 1); 7491 SKIP_BLANKS; 7492 } 7493 7494 7495} 7496 7497/** 7498 * xmlXPathScanName: 7499 * @ctxt: the XPath Parser context 7500 * 7501 * Trickery: parse an XML name but without consuming the input flow 7502 * Needed to avoid insanity in the parser state. 7503 * 7504 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | 7505 * CombiningChar | Extender 7506 * 7507 * [5] Name ::= (Letter | '_' | ':') (NameChar)* 7508 * 7509 * [6] Names ::= Name (S Name)* 7510 * 7511 * Returns the Name parsed or NULL 7512 */ 7513 7514static xmlChar * 7515xmlXPathScanName(xmlXPathParserContextPtr ctxt) { 7516 xmlChar buf[XML_MAX_NAMELEN]; 7517 int len = 0; 7518 7519 SKIP_BLANKS; 7520 if (!IS_LETTER(CUR) && (CUR != '_') && 7521 (CUR != ':')) { 7522 return(NULL); 7523 } 7524 7525 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) || 7526 (NXT(len) == '.') || (NXT(len) == '-') || 7527 (NXT(len) == '_') || (NXT(len) == ':') || 7528 (IS_COMBINING(NXT(len))) || 7529 (IS_EXTENDER(NXT(len)))) { 7530 buf[len] = NXT(len); 7531 len++; 7532 if (len >= XML_MAX_NAMELEN) { 7533 xmlGenericError(xmlGenericErrorContext, 7534 "xmlScanName: reached XML_MAX_NAMELEN limit\n"); 7535 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) || 7536 (NXT(len) == '.') || (NXT(len) == '-') || 7537 (NXT(len) == '_') || (NXT(len) == ':') || 7538 (IS_COMBINING(NXT(len))) || 7539 (IS_EXTENDER(NXT(len)))) 7540 len++; 7541 break; 7542 } 7543 } 7544 return(xmlStrndup(buf, len)); 7545} 7546 7547/** 7548 * xmlXPathCompPathExpr: 7549 * @ctxt: the XPath Parser context 7550 * 7551 * [19] PathExpr ::= LocationPath 7552 * | FilterExpr 7553 * | FilterExpr '/' RelativeLocationPath 7554 * | FilterExpr '//' RelativeLocationPath 7555 * 7556 * Compile a path expression. 7557 * The / operator and // operators combine an arbitrary expression 7558 * and a relative location path. It is an error if the expression 7559 * does not evaluate to a node-set. 7560 * The / operator does composition in the same way as when / is 7561 * used in a location path. As in location paths, // is short for 7562 * /descendant-or-self::node()/. 7563 */ 7564 7565static void 7566xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) { 7567 int lc = 1; /* Should we branch to LocationPath ? */ 7568 xmlChar *name = NULL; /* we may have to preparse a name to find out */ 7569 7570 SKIP_BLANKS; 7571 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) || 7572 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) { 7573 lc = 0; 7574 } else if (CUR == '*') { 7575 /* relative or absolute location path */ 7576 lc = 1; 7577 } else if (CUR == '/') { 7578 /* relative or absolute location path */ 7579 lc = 1; 7580 } else if (CUR == '@') { 7581 /* relative abbreviated attribute location path */ 7582 lc = 1; 7583 } else if (CUR == '.') { 7584 /* relative abbreviated attribute location path */ 7585 lc = 1; 7586 } else { 7587 /* 7588 * Problem is finding if we have a name here whether it's: 7589 * - a nodetype 7590 * - a function call in which case it's followed by '(' 7591 * - an axis in which case it's followed by ':' 7592 * - a element name 7593 * We do an a priori analysis here rather than having to 7594 * maintain parsed token content through the recursive function 7595 * calls. This looks uglier but makes the code quite easier to 7596 * read/write/debug. 7597 */ 7598 SKIP_BLANKS; 7599 name = xmlXPathScanName(ctxt); 7600 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) { 7601#ifdef DEBUG_STEP 7602 xmlGenericError(xmlGenericErrorContext, 7603 "PathExpr: Axis\n"); 7604#endif 7605 lc = 1; 7606 xmlFree(name); 7607 } else if (name != NULL) { 7608 int len =xmlStrlen(name); 7609 int blank = 0; 7610 7611 7612 while (NXT(len) != 0) { 7613 if (NXT(len) == '/') { 7614 /* element name */ 7615#ifdef DEBUG_STEP 7616 xmlGenericError(xmlGenericErrorContext, 7617 "PathExpr: AbbrRelLocation\n"); 7618#endif 7619 lc = 1; 7620 break; 7621 } else if (IS_BLANK(NXT(len))) { 7622 /* skip to next */ 7623 blank = 1; 7624 } else if (NXT(len) == ':') { 7625#ifdef DEBUG_STEP 7626 xmlGenericError(xmlGenericErrorContext, 7627 "PathExpr: AbbrRelLocation\n"); 7628#endif 7629 lc = 1; 7630 break; 7631 } else if ((NXT(len) == '(')) { 7632 /* Note Type or Function */ 7633 if (xmlXPathIsNodeType(name)) { 7634#ifdef DEBUG_STEP 7635 xmlGenericError(xmlGenericErrorContext, 7636 "PathExpr: Type search\n"); 7637#endif 7638 lc = 1; 7639 } else { 7640#ifdef DEBUG_STEP 7641 xmlGenericError(xmlGenericErrorContext, 7642 "PathExpr: function call\n"); 7643#endif 7644 lc = 0; 7645 } 7646 break; 7647 } else if ((NXT(len) == '[')) { 7648 /* element name */ 7649#ifdef DEBUG_STEP 7650 xmlGenericError(xmlGenericErrorContext, 7651 "PathExpr: AbbrRelLocation\n"); 7652#endif 7653 lc = 1; 7654 break; 7655 } else if ((NXT(len) == '<') || (NXT(len) == '>') || 7656 (NXT(len) == '=')) { 7657 lc = 1; 7658 break; 7659 } else { 7660 lc = 1; 7661 break; 7662 } 7663 len++; 7664 } 7665 if (NXT(len) == 0) { 7666#ifdef DEBUG_STEP 7667 xmlGenericError(xmlGenericErrorContext, 7668 "PathExpr: AbbrRelLocation\n"); 7669#endif 7670 /* element name */ 7671 lc = 1; 7672 } 7673 xmlFree(name); 7674 } else { 7675 /* make sure all cases are covered explicitely */ 7676 XP_ERROR(XPATH_EXPR_ERROR); 7677 } 7678 } 7679 7680 if (lc) { 7681 if (CUR == '/') { 7682 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0); 7683 } else { 7684 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 7685 } 7686 xmlXPathCompLocationPath(ctxt); 7687 } else { 7688 xmlXPathCompFilterExpr(ctxt); 7689 CHECK_ERROR; 7690 if ((CUR == '/') && (NXT(1) == '/')) { 7691 SKIP(2); 7692 SKIP_BLANKS; 7693 7694 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 7695 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 7696 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0); 7697 7698 xmlXPathCompRelativeLocationPath(ctxt); 7699 } else if (CUR == '/') { 7700 xmlXPathCompRelativeLocationPath(ctxt); 7701 } 7702 } 7703 SKIP_BLANKS; 7704} 7705 7706/** 7707 * xmlXPathCompUnionExpr: 7708 * @ctxt: the XPath Parser context 7709 * 7710 * [18] UnionExpr ::= PathExpr 7711 * | UnionExpr '|' PathExpr 7712 * 7713 * Compile an union expression. 7714 */ 7715 7716static void 7717xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) { 7718 xmlXPathCompPathExpr(ctxt); 7719 CHECK_ERROR; 7720 SKIP_BLANKS; 7721 while (CUR == '|') { 7722 int op1 = ctxt->comp->last; 7723 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0); 7724 7725 NEXT; 7726 SKIP_BLANKS; 7727 xmlXPathCompPathExpr(ctxt); 7728 7729 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0); 7730 7731 SKIP_BLANKS; 7732 } 7733} 7734 7735/** 7736 * xmlXPathCompUnaryExpr: 7737 * @ctxt: the XPath Parser context 7738 * 7739 * [27] UnaryExpr ::= UnionExpr 7740 * | '-' UnaryExpr 7741 * 7742 * Compile an unary expression. 7743 */ 7744 7745static void 7746xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) { 7747 int minus = 0; 7748 int found = 0; 7749 7750 SKIP_BLANKS; 7751 while (CUR == '-') { 7752 minus = 1 - minus; 7753 found = 1; 7754 NEXT; 7755 SKIP_BLANKS; 7756 } 7757 7758 xmlXPathCompUnionExpr(ctxt); 7759 CHECK_ERROR; 7760 if (found) { 7761 if (minus) 7762 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0); 7763 else 7764 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0); 7765 } 7766} 7767 7768/** 7769 * xmlXPathCompMultiplicativeExpr: 7770 * @ctxt: the XPath Parser context 7771 * 7772 * [26] MultiplicativeExpr ::= UnaryExpr 7773 * | MultiplicativeExpr MultiplyOperator UnaryExpr 7774 * | MultiplicativeExpr 'div' UnaryExpr 7775 * | MultiplicativeExpr 'mod' UnaryExpr 7776 * [34] MultiplyOperator ::= '*' 7777 * 7778 * Compile an Additive expression. 7779 */ 7780 7781static void 7782xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) { 7783 xmlXPathCompUnaryExpr(ctxt); 7784 CHECK_ERROR; 7785 SKIP_BLANKS; 7786 while ((CUR == '*') || 7787 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) || 7788 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) { 7789 int op = -1; 7790 int op1 = ctxt->comp->last; 7791 7792 if (CUR == '*') { 7793 op = 0; 7794 NEXT; 7795 } else if (CUR == 'd') { 7796 op = 1; 7797 SKIP(3); 7798 } else if (CUR == 'm') { 7799 op = 2; 7800 SKIP(3); 7801 } 7802 SKIP_BLANKS; 7803 xmlXPathCompUnaryExpr(ctxt); 7804 CHECK_ERROR; 7805 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0); 7806 SKIP_BLANKS; 7807 } 7808} 7809 7810/** 7811 * xmlXPathCompAdditiveExpr: 7812 * @ctxt: the XPath Parser context 7813 * 7814 * [25] AdditiveExpr ::= MultiplicativeExpr 7815 * | AdditiveExpr '+' MultiplicativeExpr 7816 * | AdditiveExpr '-' MultiplicativeExpr 7817 * 7818 * Compile an Additive expression. 7819 */ 7820 7821static void 7822xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) { 7823 7824 xmlXPathCompMultiplicativeExpr(ctxt); 7825 CHECK_ERROR; 7826 SKIP_BLANKS; 7827 while ((CUR == '+') || (CUR == '-')) { 7828 int plus; 7829 int op1 = ctxt->comp->last; 7830 7831 if (CUR == '+') plus = 1; 7832 else plus = 0; 7833 NEXT; 7834 SKIP_BLANKS; 7835 xmlXPathCompMultiplicativeExpr(ctxt); 7836 CHECK_ERROR; 7837 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0); 7838 SKIP_BLANKS; 7839 } 7840} 7841 7842/** 7843 * xmlXPathCompRelationalExpr: 7844 * @ctxt: the XPath Parser context 7845 * 7846 * [24] RelationalExpr ::= AdditiveExpr 7847 * | RelationalExpr '<' AdditiveExpr 7848 * | RelationalExpr '>' AdditiveExpr 7849 * | RelationalExpr '<=' AdditiveExpr 7850 * | RelationalExpr '>=' AdditiveExpr 7851 * 7852 * A <= B > C is allowed ? Answer from James, yes with 7853 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr 7854 * which is basically what got implemented. 7855 * 7856 * Compile a Relational expression, then push the result 7857 * on the stack 7858 */ 7859 7860static void 7861xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) { 7862 xmlXPathCompAdditiveExpr(ctxt); 7863 CHECK_ERROR; 7864 SKIP_BLANKS; 7865 while ((CUR == '<') || 7866 (CUR == '>') || 7867 ((CUR == '<') && (NXT(1) == '=')) || 7868 ((CUR == '>') && (NXT(1) == '='))) { 7869 int inf, strict; 7870 int op1 = ctxt->comp->last; 7871 7872 if (CUR == '<') inf = 1; 7873 else inf = 0; 7874 if (NXT(1) == '=') strict = 0; 7875 else strict = 1; 7876 NEXT; 7877 if (!strict) NEXT; 7878 SKIP_BLANKS; 7879 xmlXPathCompAdditiveExpr(ctxt); 7880 CHECK_ERROR; 7881 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict); 7882 SKIP_BLANKS; 7883 } 7884} 7885 7886/** 7887 * xmlXPathCompEqualityExpr: 7888 * @ctxt: the XPath Parser context 7889 * 7890 * [23] EqualityExpr ::= RelationalExpr 7891 * | EqualityExpr '=' RelationalExpr 7892 * | EqualityExpr '!=' RelationalExpr 7893 * 7894 * A != B != C is allowed ? Answer from James, yes with 7895 * (RelationalExpr = RelationalExpr) = RelationalExpr 7896 * (RelationalExpr != RelationalExpr) != RelationalExpr 7897 * which is basically what got implemented. 7898 * 7899 * Compile an Equality expression. 7900 * 7901 */ 7902static void 7903xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) { 7904 xmlXPathCompRelationalExpr(ctxt); 7905 CHECK_ERROR; 7906 SKIP_BLANKS; 7907 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) { 7908 int eq; 7909 int op1 = ctxt->comp->last; 7910 7911 if (CUR == '=') eq = 1; 7912 else eq = 0; 7913 NEXT; 7914 if (!eq) NEXT; 7915 SKIP_BLANKS; 7916 xmlXPathCompRelationalExpr(ctxt); 7917 CHECK_ERROR; 7918 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0); 7919 SKIP_BLANKS; 7920 } 7921} 7922 7923/** 7924 * xmlXPathCompAndExpr: 7925 * @ctxt: the XPath Parser context 7926 * 7927 * [22] AndExpr ::= EqualityExpr 7928 * | AndExpr 'and' EqualityExpr 7929 * 7930 * Compile an AND expression. 7931 * 7932 */ 7933static void 7934xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) { 7935 xmlXPathCompEqualityExpr(ctxt); 7936 CHECK_ERROR; 7937 SKIP_BLANKS; 7938 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) { 7939 int op1 = ctxt->comp->last; 7940 SKIP(3); 7941 SKIP_BLANKS; 7942 xmlXPathCompEqualityExpr(ctxt); 7943 CHECK_ERROR; 7944 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0); 7945 SKIP_BLANKS; 7946 } 7947} 7948 7949/** 7950 * xmlXPathCompExpr: 7951 * @ctxt: the XPath Parser context 7952 * 7953 * [14] Expr ::= OrExpr 7954 * [21] OrExpr ::= AndExpr 7955 * | OrExpr 'or' AndExpr 7956 * 7957 * Parse and compile an expression 7958 */ 7959static void 7960xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) { 7961 xmlXPathCompAndExpr(ctxt); 7962 CHECK_ERROR; 7963 SKIP_BLANKS; 7964 while ((CUR == 'o') && (NXT(1) == 'r')) { 7965 int op1 = ctxt->comp->last; 7966 SKIP(2); 7967 SKIP_BLANKS; 7968 xmlXPathCompAndExpr(ctxt); 7969 CHECK_ERROR; 7970 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0); 7971 op1 = ctxt->comp->nbStep; 7972 SKIP_BLANKS; 7973 } 7974 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) { 7975 /* more ops could be optimized too */ 7976 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0); 7977 } 7978} 7979 7980/** 7981 * xmlXPathCompPredicate: 7982 * @ctxt: the XPath Parser context 7983 * @filter: act as a filter 7984 * 7985 * [8] Predicate ::= '[' PredicateExpr ']' 7986 * [9] PredicateExpr ::= Expr 7987 * 7988 * Compile a predicate expression 7989 */ 7990static void 7991xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) { 7992 int op1 = ctxt->comp->last; 7993 7994 SKIP_BLANKS; 7995 if (CUR != '[') { 7996 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 7997 } 7998 NEXT; 7999 SKIP_BLANKS; 8000 8001 ctxt->comp->last = -1; 8002 xmlXPathCompileExpr(ctxt); 8003 CHECK_ERROR; 8004 8005 if (CUR != ']') { 8006 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR); 8007 } 8008 8009 if (filter) 8010 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0); 8011 else 8012 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0); 8013 8014 NEXT; 8015 SKIP_BLANKS; 8016} 8017 8018/** 8019 * xmlXPathCompNodeTest: 8020 * @ctxt: the XPath Parser context 8021 * @test: pointer to a xmlXPathTestVal 8022 * @type: pointer to a xmlXPathTypeVal 8023 * @prefix: placeholder for a possible name prefix 8024 * 8025 * [7] NodeTest ::= NameTest 8026 * | NodeType '(' ')' 8027 * | 'processing-instruction' '(' Literal ')' 8028 * 8029 * [37] NameTest ::= '*' 8030 * | NCName ':' '*' 8031 * | QName 8032 * [38] NodeType ::= 'comment' 8033 * | 'text' 8034 * | 'processing-instruction' 8035 * | 'node' 8036 * 8037 * Returns the name found and update @test, @type and @prefix appropriately 8038 */ 8039static xmlChar * 8040xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test, 8041 xmlXPathTypeVal *type, const xmlChar **prefix, 8042 xmlChar *name) { 8043 int blanks; 8044 8045 if ((test == NULL) || (type == NULL) || (prefix == NULL)) { 8046 STRANGE; 8047 return(NULL); 8048 } 8049 *type = 0; 8050 *test = 0; 8051 *prefix = NULL; 8052 SKIP_BLANKS; 8053 8054 if ((name == NULL) && (CUR == '*')) { 8055 /* 8056 * All elements 8057 */ 8058 NEXT; 8059 *test = NODE_TEST_ALL; 8060 return(NULL); 8061 } 8062 8063 if (name == NULL) 8064 name = xmlXPathParseNCName(ctxt); 8065 if (name == NULL) { 8066 XP_ERROR0(XPATH_EXPR_ERROR); 8067 } 8068 8069 blanks = IS_BLANK(CUR); 8070 SKIP_BLANKS; 8071 if (CUR == '(') { 8072 NEXT; 8073 /* 8074 * NodeType or PI search 8075 */ 8076 if (xmlStrEqual(name, BAD_CAST "comment")) 8077 *type = NODE_TYPE_COMMENT; 8078 else if (xmlStrEqual(name, BAD_CAST "node")) 8079 *type = NODE_TYPE_NODE; 8080 else if (xmlStrEqual(name, BAD_CAST "processing-instruction")) 8081 *type = NODE_TYPE_PI; 8082 else if (xmlStrEqual(name, BAD_CAST "text")) 8083 *type = NODE_TYPE_TEXT; 8084 else { 8085 if (name != NULL) 8086 xmlFree(name); 8087 XP_ERROR0(XPATH_EXPR_ERROR); 8088 } 8089 8090 *test = NODE_TEST_TYPE; 8091 8092 SKIP_BLANKS; 8093 if (*type == NODE_TYPE_PI) { 8094 /* 8095 * Specific case: search a PI by name. 8096 */ 8097 if (name != NULL) 8098 xmlFree(name); 8099 name = NULL; 8100 if (CUR != ')') { 8101 name = xmlXPathParseLiteral(ctxt); 8102 CHECK_ERROR 0; 8103 SKIP_BLANKS; 8104 } 8105 } 8106 if (CUR != ')') { 8107 if (name != NULL) 8108 xmlFree(name); 8109 XP_ERROR0(XPATH_UNCLOSED_ERROR); 8110 } 8111 NEXT; 8112 return(name); 8113 } 8114 *test = NODE_TEST_NAME; 8115 if ((!blanks) && (CUR == ':')) { 8116 NEXT; 8117 8118 /* 8119 * Since currently the parser context don't have a 8120 * namespace list associated: 8121 * The namespace name for this prefix can be computed 8122 * only at evaluation time. The compilation is done 8123 * outside of any context. 8124 */ 8125#if 0 8126 *prefix = xmlXPathNsLookup(ctxt->context, name); 8127 if (name != NULL) 8128 xmlFree(name); 8129 if (*prefix == NULL) { 8130 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 8131 } 8132#else 8133 *prefix = name; 8134#endif 8135 8136 if (CUR == '*') { 8137 /* 8138 * All elements 8139 */ 8140 NEXT; 8141 *test = NODE_TEST_ALL; 8142 return(NULL); 8143 } 8144 8145 name = xmlXPathParseNCName(ctxt); 8146 if (name == NULL) { 8147 XP_ERROR0(XPATH_EXPR_ERROR); 8148 } 8149 } 8150 return(name); 8151} 8152 8153/** 8154 * xmlXPathIsAxisName: 8155 * @name: a preparsed name token 8156 * 8157 * [6] AxisName ::= 'ancestor' 8158 * | 'ancestor-or-self' 8159 * | 'attribute' 8160 * | 'child' 8161 * | 'descendant' 8162 * | 'descendant-or-self' 8163 * | 'following' 8164 * | 'following-sibling' 8165 * | 'namespace' 8166 * | 'parent' 8167 * | 'preceding' 8168 * | 'preceding-sibling' 8169 * | 'self' 8170 * 8171 * Returns the axis or 0 8172 */ 8173static xmlXPathAxisVal 8174xmlXPathIsAxisName(const xmlChar *name) { 8175 xmlXPathAxisVal ret = 0; 8176 switch (name[0]) { 8177 case 'a': 8178 if (xmlStrEqual(name, BAD_CAST "ancestor")) 8179 ret = AXIS_ANCESTOR; 8180 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self")) 8181 ret = AXIS_ANCESTOR_OR_SELF; 8182 if (xmlStrEqual(name, BAD_CAST "attribute")) 8183 ret = AXIS_ATTRIBUTE; 8184 break; 8185 case 'c': 8186 if (xmlStrEqual(name, BAD_CAST "child")) 8187 ret = AXIS_CHILD; 8188 break; 8189 case 'd': 8190 if (xmlStrEqual(name, BAD_CAST "descendant")) 8191 ret = AXIS_DESCENDANT; 8192 if (xmlStrEqual(name, BAD_CAST "descendant-or-self")) 8193 ret = AXIS_DESCENDANT_OR_SELF; 8194 break; 8195 case 'f': 8196 if (xmlStrEqual(name, BAD_CAST "following")) 8197 ret = AXIS_FOLLOWING; 8198 if (xmlStrEqual(name, BAD_CAST "following-sibling")) 8199 ret = AXIS_FOLLOWING_SIBLING; 8200 break; 8201 case 'n': 8202 if (xmlStrEqual(name, BAD_CAST "namespace")) 8203 ret = AXIS_NAMESPACE; 8204 break; 8205 case 'p': 8206 if (xmlStrEqual(name, BAD_CAST "parent")) 8207 ret = AXIS_PARENT; 8208 if (xmlStrEqual(name, BAD_CAST "preceding")) 8209 ret = AXIS_PRECEDING; 8210 if (xmlStrEqual(name, BAD_CAST "preceding-sibling")) 8211 ret = AXIS_PRECEDING_SIBLING; 8212 break; 8213 case 's': 8214 if (xmlStrEqual(name, BAD_CAST "self")) 8215 ret = AXIS_SELF; 8216 break; 8217 } 8218 return(ret); 8219} 8220 8221/** 8222 * xmlXPathCompStep: 8223 * @ctxt: the XPath Parser context 8224 * 8225 * [4] Step ::= AxisSpecifier NodeTest Predicate* 8226 * | AbbreviatedStep 8227 * 8228 * [12] AbbreviatedStep ::= '.' | '..' 8229 * 8230 * [5] AxisSpecifier ::= AxisName '::' 8231 * | AbbreviatedAxisSpecifier 8232 * 8233 * [13] AbbreviatedAxisSpecifier ::= '@'? 8234 * 8235 * Modified for XPtr range support as: 8236 * 8237 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate* 8238 * | AbbreviatedStep 8239 * | 'range-to' '(' Expr ')' Predicate* 8240 * 8241 * Compile one step in a Location Path 8242 * A location step of . is short for self::node(). This is 8243 * particularly useful in conjunction with //. For example, the 8244 * location path .//para is short for 8245 * self::node()/descendant-or-self::node()/child::para 8246 * and so will select all para descendant elements of the context 8247 * node. 8248 * Similarly, a location step of .. is short for parent::node(). 8249 * For example, ../title is short for parent::node()/child::title 8250 * and so will select the title children of the parent of the context 8251 * node. 8252 */ 8253static void 8254xmlXPathCompStep(xmlXPathParserContextPtr ctxt) { 8255#ifdef LIBXML_XPTR_ENABLED 8256 int rangeto = 0; 8257 int op2 = -1; 8258#endif 8259 8260 SKIP_BLANKS; 8261 if ((CUR == '.') && (NXT(1) == '.')) { 8262 SKIP(2); 8263 SKIP_BLANKS; 8264 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT, 8265 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8266 } else if (CUR == '.') { 8267 NEXT; 8268 SKIP_BLANKS; 8269 } else { 8270 xmlChar *name = NULL; 8271 const xmlChar *prefix = NULL; 8272 xmlXPathTestVal test; 8273 xmlXPathAxisVal axis = 0; 8274 xmlXPathTypeVal type; 8275 int op1; 8276 8277 /* 8278 * The modification needed for XPointer change to the production 8279 */ 8280#ifdef LIBXML_XPTR_ENABLED 8281 if (ctxt->xptr) { 8282 name = xmlXPathParseNCName(ctxt); 8283 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) { 8284 op2 = ctxt->comp->last; 8285 xmlFree(name); 8286 SKIP_BLANKS; 8287 if (CUR != '(') { 8288 XP_ERROR(XPATH_EXPR_ERROR); 8289 } 8290 NEXT; 8291 SKIP_BLANKS; 8292 8293 xmlXPathCompileExpr(ctxt); 8294 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */ 8295 CHECK_ERROR; 8296 8297 SKIP_BLANKS; 8298 if (CUR != ')') { 8299 XP_ERROR(XPATH_EXPR_ERROR); 8300 } 8301 NEXT; 8302 rangeto = 1; 8303 goto eval_predicates; 8304 } 8305 } 8306#endif 8307 if (CUR == '*') { 8308 axis = AXIS_CHILD; 8309 } else { 8310 if (name == NULL) 8311 name = xmlXPathParseNCName(ctxt); 8312 if (name != NULL) { 8313 axis = xmlXPathIsAxisName(name); 8314 if (axis != 0) { 8315 SKIP_BLANKS; 8316 if ((CUR == ':') && (NXT(1) == ':')) { 8317 SKIP(2); 8318 xmlFree(name); 8319 name = NULL; 8320 } else { 8321 /* an element name can conflict with an axis one :-\ */ 8322 axis = AXIS_CHILD; 8323 } 8324 } else { 8325 axis = AXIS_CHILD; 8326 } 8327 } else if (CUR == '@') { 8328 NEXT; 8329 axis = AXIS_ATTRIBUTE; 8330 } else { 8331 axis = AXIS_CHILD; 8332 } 8333 } 8334 8335 CHECK_ERROR; 8336 8337 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name); 8338 if (test == 0) 8339 return; 8340 8341#ifdef DEBUG_STEP 8342 xmlGenericError(xmlGenericErrorContext, 8343 "Basis : computing new set\n"); 8344#endif 8345 8346#ifdef DEBUG_STEP 8347 xmlGenericError(xmlGenericErrorContext, "Basis : "); 8348 if (ctxt->value == NULL) 8349 xmlGenericError(xmlGenericErrorContext, "no value\n"); 8350 else if (ctxt->value->nodesetval == NULL) 8351 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 8352 else 8353 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval); 8354#endif 8355 8356eval_predicates: 8357 op1 = ctxt->comp->last; 8358 ctxt->comp->last = -1; 8359 8360 SKIP_BLANKS; 8361 while (CUR == '[') { 8362 xmlXPathCompPredicate(ctxt, 0); 8363 } 8364 8365#ifdef LIBXML_XPTR_ENABLED 8366 if (rangeto) { 8367 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0); 8368 } else 8369#endif 8370 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, 8371 test, type, (void *)prefix, (void *)name); 8372 8373 } 8374#ifdef DEBUG_STEP 8375 xmlGenericError(xmlGenericErrorContext, "Step : "); 8376 if (ctxt->value == NULL) 8377 xmlGenericError(xmlGenericErrorContext, "no value\n"); 8378 else if (ctxt->value->nodesetval == NULL) 8379 xmlGenericError(xmlGenericErrorContext, "Empty\n"); 8380 else 8381 xmlGenericErrorContextNodeSet(xmlGenericErrorContext, 8382 ctxt->value->nodesetval); 8383#endif 8384} 8385 8386/** 8387 * xmlXPathCompRelativeLocationPath: 8388 * @ctxt: the XPath Parser context 8389 * 8390 * [3] RelativeLocationPath ::= Step 8391 * | RelativeLocationPath '/' Step 8392 * | AbbreviatedRelativeLocationPath 8393 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step 8394 * 8395 * Compile a relative location path. 8396 */ 8397static void 8398#ifdef VMS 8399xmlXPathCompRelLocationPath 8400#else 8401xmlXPathCompRelativeLocationPath 8402#endif 8403(xmlXPathParserContextPtr ctxt) { 8404 SKIP_BLANKS; 8405 if ((CUR == '/') && (NXT(1) == '/')) { 8406 SKIP(2); 8407 SKIP_BLANKS; 8408 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 8409 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8410 } else if (CUR == '/') { 8411 NEXT; 8412 SKIP_BLANKS; 8413 } 8414 xmlXPathCompStep(ctxt); 8415 SKIP_BLANKS; 8416 while (CUR == '/') { 8417 if ((CUR == '/') && (NXT(1) == '/')) { 8418 SKIP(2); 8419 SKIP_BLANKS; 8420 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 8421 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8422 xmlXPathCompStep(ctxt); 8423 } else if (CUR == '/') { 8424 NEXT; 8425 SKIP_BLANKS; 8426 xmlXPathCompStep(ctxt); 8427 } 8428 SKIP_BLANKS; 8429 } 8430} 8431 8432/** 8433 * xmlXPathCompLocationPath: 8434 * @ctxt: the XPath Parser context 8435 * 8436 * [1] LocationPath ::= RelativeLocationPath 8437 * | AbsoluteLocationPath 8438 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath? 8439 * | AbbreviatedAbsoluteLocationPath 8440 * [10] AbbreviatedAbsoluteLocationPath ::= 8441 * '//' RelativeLocationPath 8442 * 8443 * Compile a location path 8444 * 8445 * // is short for /descendant-or-self::node()/. For example, 8446 * //para is short for /descendant-or-self::node()/child::para and 8447 * so will select any para element in the document (even a para element 8448 * that is a document element will be selected by //para since the 8449 * document element node is a child of the root node); div//para is 8450 * short for div/descendant-or-self::node()/child::para and so will 8451 * select all para descendants of div children. 8452 */ 8453static void 8454xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) { 8455 SKIP_BLANKS; 8456 if (CUR != '/') { 8457 xmlXPathCompRelativeLocationPath(ctxt); 8458 } else { 8459 while (CUR == '/') { 8460 if ((CUR == '/') && (NXT(1) == '/')) { 8461 SKIP(2); 8462 SKIP_BLANKS; 8463 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, 8464 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL); 8465 xmlXPathCompRelativeLocationPath(ctxt); 8466 } else if (CUR == '/') { 8467 NEXT; 8468 SKIP_BLANKS; 8469 if ((CUR != 0 ) && 8470 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') || 8471 (CUR == '@') || (CUR == '*'))) 8472 xmlXPathCompRelativeLocationPath(ctxt); 8473 } 8474 } 8475 } 8476} 8477 8478/************************************************************************ 8479 * * 8480 * XPath precompiled expression evaluation * 8481 * * 8482 ************************************************************************/ 8483 8484static int 8485xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op); 8486 8487/** 8488 * xmlXPathNodeCollectAndTest: 8489 * @ctxt: the XPath Parser context 8490 * @op: the XPath precompiled step operation 8491 * @first: pointer to the first element in document order 8492 * @last: pointer to the last element in document order 8493 * 8494 * This is the function implementing a step: based on the current list 8495 * of nodes, it builds up a new list, looking at all nodes under that 8496 * axis and selecting them it also do the predicate filtering 8497 * 8498 * Pushes the new NodeSet resulting from the search. 8499 * 8500 * Returns the number of node traversed 8501 */ 8502static int 8503xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, 8504 xmlXPathStepOpPtr op, 8505 xmlNodePtr * first, xmlNodePtr * last) 8506{ 8507 xmlXPathAxisVal axis = op->value; 8508 xmlXPathTestVal test = op->value2; 8509 xmlXPathTypeVal type = op->value3; 8510 const xmlChar *prefix = op->value4; 8511 const xmlChar *name = op->value5; 8512 const xmlChar *URI = NULL; 8513 8514#ifdef DEBUG_STEP 8515 int n = 0; 8516#endif 8517 int i, t = 0; 8518 xmlNodeSetPtr ret, list; 8519 xmlXPathTraversalFunction next = NULL; 8520 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 8521 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr); 8522 xmlNodePtr cur = NULL; 8523 xmlXPathObjectPtr obj; 8524 xmlNodeSetPtr nodelist; 8525 xmlNodePtr tmp; 8526 8527 CHECK_TYPE0(XPATH_NODESET); 8528 obj = valuePop(ctxt); 8529 addNode = xmlXPathNodeSetAdd; 8530 mergeNodeSet = xmlXPathNodeSetMerge; 8531 if (prefix != NULL) { 8532 URI = xmlXPathNsLookup(ctxt->context, prefix); 8533 if (URI == NULL) 8534 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 8535 } 8536#ifdef DEBUG_STEP 8537 xmlGenericError(xmlGenericErrorContext, "new step : "); 8538#endif 8539 switch (axis) { 8540 case AXIS_ANCESTOR: 8541#ifdef DEBUG_STEP 8542 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 8543#endif 8544 first = NULL; 8545 next = xmlXPathNextAncestor; 8546 break; 8547 case AXIS_ANCESTOR_OR_SELF: 8548#ifdef DEBUG_STEP 8549 xmlGenericError(xmlGenericErrorContext, 8550 "axis 'ancestors-or-self' "); 8551#endif 8552 first = NULL; 8553 next = xmlXPathNextAncestorOrSelf; 8554 break; 8555 case AXIS_ATTRIBUTE: 8556#ifdef DEBUG_STEP 8557 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 8558#endif 8559 first = NULL; 8560 last = NULL; 8561 next = xmlXPathNextAttribute; 8562 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8563 break; 8564 case AXIS_CHILD: 8565#ifdef DEBUG_STEP 8566 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 8567#endif 8568 last = NULL; 8569 next = xmlXPathNextChild; 8570 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8571 break; 8572 case AXIS_DESCENDANT: 8573#ifdef DEBUG_STEP 8574 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 8575#endif 8576 last = NULL; 8577 next = xmlXPathNextDescendant; 8578 break; 8579 case AXIS_DESCENDANT_OR_SELF: 8580#ifdef DEBUG_STEP 8581 xmlGenericError(xmlGenericErrorContext, 8582 "axis 'descendant-or-self' "); 8583#endif 8584 last = NULL; 8585 next = xmlXPathNextDescendantOrSelf; 8586 break; 8587 case AXIS_FOLLOWING: 8588#ifdef DEBUG_STEP 8589 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 8590#endif 8591 last = NULL; 8592 next = xmlXPathNextFollowing; 8593 break; 8594 case AXIS_FOLLOWING_SIBLING: 8595#ifdef DEBUG_STEP 8596 xmlGenericError(xmlGenericErrorContext, 8597 "axis 'following-siblings' "); 8598#endif 8599 last = NULL; 8600 next = xmlXPathNextFollowingSibling; 8601 break; 8602 case AXIS_NAMESPACE: 8603#ifdef DEBUG_STEP 8604 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 8605#endif 8606 first = NULL; 8607 last = NULL; 8608 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 8609 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8610 break; 8611 case AXIS_PARENT: 8612#ifdef DEBUG_STEP 8613 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 8614#endif 8615 first = NULL; 8616 next = xmlXPathNextParent; 8617 break; 8618 case AXIS_PRECEDING: 8619#ifdef DEBUG_STEP 8620 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 8621#endif 8622 first = NULL; 8623 next = xmlXPathNextPrecedingInternal; 8624 break; 8625 case AXIS_PRECEDING_SIBLING: 8626#ifdef DEBUG_STEP 8627 xmlGenericError(xmlGenericErrorContext, 8628 "axis 'preceding-sibling' "); 8629#endif 8630 first = NULL; 8631 next = xmlXPathNextPrecedingSibling; 8632 break; 8633 case AXIS_SELF: 8634#ifdef DEBUG_STEP 8635 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 8636#endif 8637 first = NULL; 8638 last = NULL; 8639 next = xmlXPathNextSelf; 8640 mergeNodeSet = xmlXPathNodeSetMergeUnique; 8641 break; 8642 } 8643 if (next == NULL) 8644 return(0); 8645 8646 nodelist = obj->nodesetval; 8647 if (nodelist == NULL) { 8648 xmlXPathFreeObject(obj); 8649 valuePush(ctxt, xmlXPathWrapNodeSet(NULL)); 8650 return(0); 8651 } 8652 addNode = xmlXPathNodeSetAddUnique; 8653 ret = NULL; 8654#ifdef DEBUG_STEP 8655 xmlGenericError(xmlGenericErrorContext, 8656 " context contains %d nodes\n", nodelist->nodeNr); 8657 switch (test) { 8658 case NODE_TEST_NONE: 8659 xmlGenericError(xmlGenericErrorContext, 8660 " searching for none !!!\n"); 8661 break; 8662 case NODE_TEST_TYPE: 8663 xmlGenericError(xmlGenericErrorContext, 8664 " searching for type %d\n", type); 8665 break; 8666 case NODE_TEST_PI: 8667 xmlGenericError(xmlGenericErrorContext, 8668 " searching for PI !!!\n"); 8669 break; 8670 case NODE_TEST_ALL: 8671 xmlGenericError(xmlGenericErrorContext, 8672 " searching for *\n"); 8673 break; 8674 case NODE_TEST_NS: 8675 xmlGenericError(xmlGenericErrorContext, 8676 " searching for namespace %s\n", 8677 prefix); 8678 break; 8679 case NODE_TEST_NAME: 8680 xmlGenericError(xmlGenericErrorContext, 8681 " searching for name %s\n", name); 8682 if (prefix != NULL) 8683 xmlGenericError(xmlGenericErrorContext, 8684 " with namespace %s\n", prefix); 8685 break; 8686 } 8687 xmlGenericError(xmlGenericErrorContext, "Testing : "); 8688#endif 8689 /* 8690 * 2.3 Node Tests 8691 * - For the attribute axis, the principal node type is attribute. 8692 * - For the namespace axis, the principal node type is namespace. 8693 * - For other axes, the principal node type is element. 8694 * 8695 * A node test * is true for any node of the 8696 * principal node type. For example, child::* will 8697 * select all element children of the context node 8698 */ 8699 tmp = ctxt->context->node; 8700 for (i = 0; i < nodelist->nodeNr; i++) { 8701 ctxt->context->node = nodelist->nodeTab[i]; 8702 8703 cur = NULL; 8704 list = xmlXPathNodeSetCreate(NULL); 8705 do { 8706 cur = next(ctxt, cur); 8707 if (cur == NULL) 8708 break; 8709 if ((first != NULL) && (*first == cur)) 8710 break; 8711 if (((t % 256) == 0) && 8712 (first != NULL) && (*first != NULL) && 8713 (xmlXPathCmpNodes(*first, cur) >= 0)) 8714 break; 8715 if ((last != NULL) && (*last == cur)) 8716 break; 8717 if (((t % 256) == 0) && 8718 (last != NULL) && (*last != NULL) && 8719 (xmlXPathCmpNodes(cur, *last) >= 0)) 8720 break; 8721 t++; 8722#ifdef DEBUG_STEP 8723 xmlGenericError(xmlGenericErrorContext, " %s", cur->name); 8724#endif 8725 switch (test) { 8726 case NODE_TEST_NONE: 8727 ctxt->context->node = tmp; 8728 STRANGE return(t); 8729 case NODE_TEST_TYPE: 8730 if ((cur->type == type) || 8731 ((type == NODE_TYPE_NODE) && 8732 ((cur->type == XML_DOCUMENT_NODE) || 8733 (cur->type == XML_HTML_DOCUMENT_NODE) || 8734 (cur->type == XML_ELEMENT_NODE) || 8735 (cur->type == XML_PI_NODE) || 8736 (cur->type == XML_COMMENT_NODE) || 8737 (cur->type == XML_CDATA_SECTION_NODE) || 8738 (cur->type == XML_TEXT_NODE))) || 8739 ((type == NODE_TYPE_TEXT) && 8740 (cur->type == XML_CDATA_SECTION_NODE))) { 8741#ifdef DEBUG_STEP 8742 n++; 8743#endif 8744 addNode(list, cur); 8745 } 8746 break; 8747 case NODE_TEST_PI: 8748 if (cur->type == XML_PI_NODE) { 8749 if ((name != NULL) && 8750 (!xmlStrEqual(name, cur->name))) 8751 break; 8752#ifdef DEBUG_STEP 8753 n++; 8754#endif 8755 addNode(list, cur); 8756 } 8757 break; 8758 case NODE_TEST_ALL: 8759 if (axis == AXIS_ATTRIBUTE) { 8760 if (cur->type == XML_ATTRIBUTE_NODE) { 8761#ifdef DEBUG_STEP 8762 n++; 8763#endif 8764 addNode(list, cur); 8765 } 8766 } else if (axis == AXIS_NAMESPACE) { 8767 if (cur->type == XML_NAMESPACE_DECL) { 8768#ifdef DEBUG_STEP 8769 n++; 8770#endif 8771 xmlXPathNodeSetAddNs(list, ctxt->context->node, 8772 (xmlNsPtr) cur); 8773 } 8774 } else { 8775 if (cur->type == XML_ELEMENT_NODE) { 8776 if (prefix == NULL) { 8777#ifdef DEBUG_STEP 8778 n++; 8779#endif 8780 addNode(list, cur); 8781 } else if ((cur->ns != NULL) && 8782 (xmlStrEqual(URI, cur->ns->href))) { 8783#ifdef DEBUG_STEP 8784 n++; 8785#endif 8786 addNode(list, cur); 8787 } 8788 } 8789 } 8790 break; 8791 case NODE_TEST_NS:{ 8792 TODO; 8793 break; 8794 } 8795 case NODE_TEST_NAME: 8796 switch (cur->type) { 8797 case XML_ELEMENT_NODE: 8798 if (xmlStrEqual(name, cur->name)) { 8799 if (prefix == NULL) { 8800 if (cur->ns == NULL) { 8801#ifdef DEBUG_STEP 8802 n++; 8803#endif 8804 addNode(list, cur); 8805 } 8806 } else { 8807 if ((cur->ns != NULL) && 8808 (xmlStrEqual(URI, 8809 cur->ns->href))) { 8810#ifdef DEBUG_STEP 8811 n++; 8812#endif 8813 addNode(list, cur); 8814 } 8815 } 8816 } 8817 break; 8818 case XML_ATTRIBUTE_NODE:{ 8819 xmlAttrPtr attr = (xmlAttrPtr) cur; 8820 8821 if (xmlStrEqual(name, attr->name)) { 8822 if (prefix == NULL) { 8823 if ((attr->ns == NULL) || 8824 (attr->ns->prefix == NULL)) { 8825#ifdef DEBUG_STEP 8826 n++; 8827#endif 8828 addNode(list, 8829 (xmlNodePtr) attr); 8830 } 8831 } else { 8832 if ((attr->ns != NULL) && 8833 (xmlStrEqual(URI, 8834 attr->ns-> 8835 href))) { 8836#ifdef DEBUG_STEP 8837 n++; 8838#endif 8839 addNode(list, 8840 (xmlNodePtr) attr); 8841 } 8842 } 8843 } 8844 break; 8845 } 8846 case XML_NAMESPACE_DECL: 8847 if (cur->type == XML_NAMESPACE_DECL) { 8848 xmlNsPtr ns = (xmlNsPtr) cur; 8849 8850 if ((ns->prefix != NULL) && (name != NULL) 8851 && (xmlStrEqual(ns->prefix, name))) { 8852#ifdef DEBUG_STEP 8853 n++; 8854#endif 8855 xmlXPathNodeSetAddNs(list, 8856 ctxt->context->node, (xmlNsPtr) cur); 8857 } 8858 } 8859 break; 8860 default: 8861 break; 8862 } 8863 break; 8864 break; 8865 } 8866 } while (cur != NULL); 8867 8868 /* 8869 * If there is some predicate filtering do it now 8870 */ 8871 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) { 8872 xmlXPathObjectPtr obj2; 8873 8874 valuePush(ctxt, xmlXPathWrapNodeSet(list)); 8875 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]); 8876 CHECK_TYPE0(XPATH_NODESET); 8877 obj2 = valuePop(ctxt); 8878 list = obj2->nodesetval; 8879 obj2->nodesetval = NULL; 8880 xmlXPathFreeObject(obj2); 8881 } 8882 if (ret == NULL) { 8883 ret = list; 8884 } else { 8885 ret = mergeNodeSet(ret, list); 8886 xmlXPathFreeNodeSet(list); 8887 } 8888 } 8889 ctxt->context->node = tmp; 8890#ifdef DEBUG_STEP 8891 xmlGenericError(xmlGenericErrorContext, 8892 "\nExamined %d nodes, found %d nodes at that step\n", 8893 t, n); 8894#endif 8895 valuePush(ctxt, xmlXPathWrapNodeSet(ret)); 8896 if ((obj->boolval) && (obj->user != NULL)) { 8897 ctxt->value->boolval = 1; 8898 ctxt->value->user = obj->user; 8899 obj->user = NULL; 8900 obj->boolval = 0; 8901 } 8902 xmlXPathFreeObject(obj); 8903 return(t); 8904} 8905 8906/** 8907 * xmlXPathNodeCollectAndTestNth: 8908 * @ctxt: the XPath Parser context 8909 * @op: the XPath precompiled step operation 8910 * @indx: the index to collect 8911 * @first: pointer to the first element in document order 8912 * @last: pointer to the last element in document order 8913 * 8914 * This is the function implementing a step: based on the current list 8915 * of nodes, it builds up a new list, looking at all nodes under that 8916 * axis and selecting them it also do the predicate filtering 8917 * 8918 * Pushes the new NodeSet resulting from the search. 8919 * Returns the number of node traversed 8920 */ 8921static int 8922xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt, 8923 xmlXPathStepOpPtr op, int indx, 8924 xmlNodePtr * first, xmlNodePtr * last) 8925{ 8926 xmlXPathAxisVal axis = op->value; 8927 xmlXPathTestVal test = op->value2; 8928 xmlXPathTypeVal type = op->value3; 8929 const xmlChar *prefix = op->value4; 8930 const xmlChar *name = op->value5; 8931 const xmlChar *URI = NULL; 8932 int n = 0, t = 0; 8933 8934 int i; 8935 xmlNodeSetPtr list; 8936 xmlXPathTraversalFunction next = NULL; 8937 void (*addNode) (xmlNodeSetPtr, xmlNodePtr); 8938 xmlNodePtr cur = NULL; 8939 xmlXPathObjectPtr obj; 8940 xmlNodeSetPtr nodelist; 8941 xmlNodePtr tmp; 8942 8943 CHECK_TYPE0(XPATH_NODESET); 8944 obj = valuePop(ctxt); 8945 addNode = xmlXPathNodeSetAdd; 8946 if (prefix != NULL) { 8947 URI = xmlXPathNsLookup(ctxt->context, prefix); 8948 if (URI == NULL) 8949 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR); 8950 } 8951#ifdef DEBUG_STEP_NTH 8952 xmlGenericError(xmlGenericErrorContext, "new step : "); 8953 if (first != NULL) { 8954 if (*first != NULL) 8955 xmlGenericError(xmlGenericErrorContext, "first = %s ", 8956 (*first)->name); 8957 else 8958 xmlGenericError(xmlGenericErrorContext, "first = NULL "); 8959 } 8960 if (last != NULL) { 8961 if (*last != NULL) 8962 xmlGenericError(xmlGenericErrorContext, "last = %s ", 8963 (*last)->name); 8964 else 8965 xmlGenericError(xmlGenericErrorContext, "last = NULL "); 8966 } 8967#endif 8968 switch (axis) { 8969 case AXIS_ANCESTOR: 8970#ifdef DEBUG_STEP_NTH 8971 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' "); 8972#endif 8973 first = NULL; 8974 next = xmlXPathNextAncestor; 8975 break; 8976 case AXIS_ANCESTOR_OR_SELF: 8977#ifdef DEBUG_STEP_NTH 8978 xmlGenericError(xmlGenericErrorContext, 8979 "axis 'ancestors-or-self' "); 8980#endif 8981 first = NULL; 8982 next = xmlXPathNextAncestorOrSelf; 8983 break; 8984 case AXIS_ATTRIBUTE: 8985#ifdef DEBUG_STEP_NTH 8986 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' "); 8987#endif 8988 first = NULL; 8989 last = NULL; 8990 next = xmlXPathNextAttribute; 8991 break; 8992 case AXIS_CHILD: 8993#ifdef DEBUG_STEP_NTH 8994 xmlGenericError(xmlGenericErrorContext, "axis 'child' "); 8995#endif 8996 last = NULL; 8997 next = xmlXPathNextChild; 8998 break; 8999 case AXIS_DESCENDANT: 9000#ifdef DEBUG_STEP_NTH 9001 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' "); 9002#endif 9003 last = NULL; 9004 next = xmlXPathNextDescendant; 9005 break; 9006 case AXIS_DESCENDANT_OR_SELF: 9007#ifdef DEBUG_STEP_NTH 9008 xmlGenericError(xmlGenericErrorContext, 9009 "axis 'descendant-or-self' "); 9010#endif 9011 last = NULL; 9012 next = xmlXPathNextDescendantOrSelf; 9013 break; 9014 case AXIS_FOLLOWING: 9015#ifdef DEBUG_STEP_NTH 9016 xmlGenericError(xmlGenericErrorContext, "axis 'following' "); 9017#endif 9018 last = NULL; 9019 next = xmlXPathNextFollowing; 9020 break; 9021 case AXIS_FOLLOWING_SIBLING: 9022#ifdef DEBUG_STEP_NTH 9023 xmlGenericError(xmlGenericErrorContext, 9024 "axis 'following-siblings' "); 9025#endif 9026 last = NULL; 9027 next = xmlXPathNextFollowingSibling; 9028 break; 9029 case AXIS_NAMESPACE: 9030#ifdef DEBUG_STEP_NTH 9031 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' "); 9032#endif 9033 last = NULL; 9034 first = NULL; 9035 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; 9036 break; 9037 case AXIS_PARENT: 9038#ifdef DEBUG_STEP_NTH 9039 xmlGenericError(xmlGenericErrorContext, "axis 'parent' "); 9040#endif 9041 first = NULL; 9042 next = xmlXPathNextParent; 9043 break; 9044 case AXIS_PRECEDING: 9045#ifdef DEBUG_STEP_NTH 9046 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' "); 9047#endif 9048 first = NULL; 9049 next = xmlXPathNextPrecedingInternal; 9050 break; 9051 case AXIS_PRECEDING_SIBLING: 9052#ifdef DEBUG_STEP_NTH 9053 xmlGenericError(xmlGenericErrorContext, 9054 "axis 'preceding-sibling' "); 9055#endif 9056 first = NULL; 9057 next = xmlXPathNextPrecedingSibling; 9058 break; 9059 case AXIS_SELF: 9060#ifdef DEBUG_STEP_NTH 9061 xmlGenericError(xmlGenericErrorContext, "axis 'self' "); 9062#endif 9063 first = NULL; 9064 last = NULL; 9065 next = xmlXPathNextSelf; 9066 break; 9067 } 9068 if (next == NULL) 9069 return(0); 9070 9071 nodelist = obj->nodesetval; 9072 if (nodelist == NULL) { 9073 xmlXPathFreeObject(obj); 9074 valuePush(ctxt, xmlXPathWrapNodeSet(NULL)); 9075 return(0); 9076 } 9077 addNode = xmlXPathNodeSetAddUnique; 9078#ifdef DEBUG_STEP_NTH 9079 xmlGenericError(xmlGenericErrorContext, 9080 " context contains %d nodes\n", nodelist->nodeNr); 9081 switch (test) { 9082 case NODE_TEST_NONE: 9083 xmlGenericError(xmlGenericErrorContext, 9084 " searching for none !!!\n"); 9085 break; 9086 case NODE_TEST_TYPE: 9087 xmlGenericError(xmlGenericErrorContext, 9088 " searching for type %d\n", type); 9089 break; 9090 case NODE_TEST_PI: 9091 xmlGenericError(xmlGenericErrorContext, 9092 " searching for PI !!!\n"); 9093 break; 9094 case NODE_TEST_ALL: 9095 xmlGenericError(xmlGenericErrorContext, 9096 " searching for *\n"); 9097 break; 9098 case NODE_TEST_NS: 9099 xmlGenericError(xmlGenericErrorContext, 9100 " searching for namespace %s\n", 9101 prefix); 9102 break; 9103 case NODE_TEST_NAME: 9104 xmlGenericError(xmlGenericErrorContext, 9105 " searching for name %s\n", name); 9106 if (prefix != NULL) 9107 xmlGenericError(xmlGenericErrorContext, 9108 " with namespace %s\n", prefix); 9109 break; 9110 } 9111 xmlGenericError(xmlGenericErrorContext, "Testing : "); 9112#endif 9113 /* 9114 * 2.3 Node Tests 9115 * - For the attribute axis, the principal node type is attribute. 9116 * - For the namespace axis, the principal node type is namespace. 9117 * - For other axes, the principal node type is element. 9118 * 9119 * A node test * is true for any node of the 9120 * principal node type. For example, child::* will 9121 * select all element children of the context node 9122 */ 9123 tmp = ctxt->context->node; 9124 list = xmlXPathNodeSetCreate(NULL); 9125 for (i = 0; i < nodelist->nodeNr; i++) { 9126 ctxt->context->node = nodelist->nodeTab[i]; 9127 9128 cur = NULL; 9129 n = 0; 9130 do { 9131 cur = next(ctxt, cur); 9132 if (cur == NULL) 9133 break; 9134 if ((first != NULL) && (*first == cur)) 9135 break; 9136 if (((t % 256) == 0) && 9137 (first != NULL) && (*first != NULL) && 9138 (xmlXPathCmpNodes(*first, cur) >= 0)) 9139 break; 9140 if ((last != NULL) && (*last == cur)) 9141 break; 9142 if (((t % 256) == 0) && 9143 (last != NULL) && (*last != NULL) && 9144 (xmlXPathCmpNodes(cur, *last) >= 0)) 9145 break; 9146 t++; 9147 switch (test) { 9148 case NODE_TEST_NONE: 9149 ctxt->context->node = tmp; 9150 STRANGE return(0); 9151 case NODE_TEST_TYPE: 9152 if ((cur->type == type) || 9153 ((type == NODE_TYPE_NODE) && 9154 ((cur->type == XML_DOCUMENT_NODE) || 9155 (cur->type == XML_HTML_DOCUMENT_NODE) || 9156 (cur->type == XML_ELEMENT_NODE) || 9157 (cur->type == XML_PI_NODE) || 9158 (cur->type == XML_COMMENT_NODE) || 9159 (cur->type == XML_CDATA_SECTION_NODE) || 9160 (cur->type == XML_TEXT_NODE)))) { 9161 n++; 9162 if (n == indx) 9163 addNode(list, cur); 9164 } 9165 break; 9166 case NODE_TEST_PI: 9167 if (cur->type == XML_PI_NODE) { 9168 if ((name != NULL) && 9169 (!xmlStrEqual(name, cur->name))) 9170 break; 9171 n++; 9172 if (n == indx) 9173 addNode(list, cur); 9174 } 9175 break; 9176 case NODE_TEST_ALL: 9177 if (axis == AXIS_ATTRIBUTE) { 9178 if (cur->type == XML_ATTRIBUTE_NODE) { 9179 n++; 9180 if (n == indx) 9181 addNode(list, cur); 9182 } 9183 } else if (axis == AXIS_NAMESPACE) { 9184 if (cur->type == XML_NAMESPACE_DECL) { 9185 n++; 9186 if (n == indx) 9187 xmlXPathNodeSetAddNs(list, ctxt->context->node, 9188 (xmlNsPtr) cur); 9189 } 9190 } else { 9191 if (cur->type == XML_ELEMENT_NODE) { 9192 if (prefix == NULL) { 9193 n++; 9194 if (n == indx) 9195 addNode(list, cur); 9196 } else if ((cur->ns != NULL) && 9197 (xmlStrEqual(URI, cur->ns->href))) { 9198 n++; 9199 if (n == indx) 9200 addNode(list, cur); 9201 } 9202 } 9203 } 9204 break; 9205 case NODE_TEST_NS:{ 9206 TODO; 9207 break; 9208 } 9209 case NODE_TEST_NAME: 9210 switch (cur->type) { 9211 case XML_ELEMENT_NODE: 9212 if (xmlStrEqual(name, cur->name)) { 9213 if (prefix == NULL) { 9214 if (cur->ns == NULL) { 9215 n++; 9216 if (n == indx) 9217 addNode(list, cur); 9218 } 9219 } else { 9220 if ((cur->ns != NULL) && 9221 (xmlStrEqual(URI, 9222 cur->ns->href))) { 9223 n++; 9224 if (n == indx) 9225 addNode(list, cur); 9226 } 9227 } 9228 } 9229 break; 9230 case XML_ATTRIBUTE_NODE:{ 9231 xmlAttrPtr attr = (xmlAttrPtr) cur; 9232 9233 if (xmlStrEqual(name, attr->name)) { 9234 if (prefix == NULL) { 9235 if ((attr->ns == NULL) || 9236 (attr->ns->prefix == NULL)) { 9237 n++; 9238 if (n == indx) 9239 addNode(list, cur); 9240 } 9241 } else { 9242 if ((attr->ns != NULL) && 9243 (xmlStrEqual(URI, 9244 attr->ns-> 9245 href))) { 9246 n++; 9247 if (n == indx) 9248 addNode(list, cur); 9249 } 9250 } 9251 } 9252 break; 9253 } 9254 case XML_NAMESPACE_DECL: 9255 if (cur->type == XML_NAMESPACE_DECL) { 9256 xmlNsPtr ns = (xmlNsPtr) cur; 9257 9258 if ((ns->prefix != NULL) && (name != NULL) 9259 && (xmlStrEqual(ns->prefix, name))) { 9260 n++; 9261 if (n == indx) 9262 xmlXPathNodeSetAddNs(list, 9263 ctxt->context->node, (xmlNsPtr) cur); 9264 } 9265 } 9266 break; 9267 default: 9268 break; 9269 } 9270 break; 9271 break; 9272 } 9273 } while (n < indx); 9274 } 9275 ctxt->context->node = tmp; 9276#ifdef DEBUG_STEP_NTH 9277 xmlGenericError(xmlGenericErrorContext, 9278 "\nExamined %d nodes, found %d nodes at that step\n", 9279 t, list->nodeNr); 9280#endif 9281 valuePush(ctxt, xmlXPathWrapNodeSet(list)); 9282 if ((obj->boolval) && (obj->user != NULL)) { 9283 ctxt->value->boolval = 1; 9284 ctxt->value->user = obj->user; 9285 obj->user = NULL; 9286 obj->boolval = 0; 9287 } 9288 xmlXPathFreeObject(obj); 9289 return(t); 9290} 9291 9292/** 9293 * xmlXPathCompOpEvalFirst: 9294 * @ctxt: the XPath parser context with the compiled expression 9295 * @op: an XPath compiled operation 9296 * @first: the first elem found so far 9297 * 9298 * Evaluate the Precompiled XPath operation searching only the first 9299 * element in document order 9300 * 9301 * Returns the number of examined objects. 9302 */ 9303static int 9304xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt, 9305 xmlXPathStepOpPtr op, xmlNodePtr * first) 9306{ 9307 int total = 0, cur; 9308 xmlXPathCompExprPtr comp; 9309 xmlXPathObjectPtr arg1, arg2; 9310 9311 CHECK_ERROR0; 9312 comp = ctxt->comp; 9313 switch (op->op) { 9314 case XPATH_OP_END: 9315 return (0); 9316 case XPATH_OP_UNION: 9317 total = 9318 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 9319 first); 9320 CHECK_ERROR0; 9321 if ((ctxt->value != NULL) 9322 && (ctxt->value->type == XPATH_NODESET) 9323 && (ctxt->value->nodesetval != NULL) 9324 && (ctxt->value->nodesetval->nodeNr >= 1)) { 9325 /* 9326 * limit tree traversing to first node in the result 9327 */ 9328 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9329 *first = ctxt->value->nodesetval->nodeTab[0]; 9330 } 9331 cur = 9332 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2], 9333 first); 9334 CHECK_ERROR0; 9335 CHECK_TYPE0(XPATH_NODESET); 9336 arg2 = valuePop(ctxt); 9337 9338 CHECK_TYPE0(XPATH_NODESET); 9339 arg1 = valuePop(ctxt); 9340 9341 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 9342 arg2->nodesetval); 9343 valuePush(ctxt, arg1); 9344 xmlXPathFreeObject(arg2); 9345 /* optimizer */ 9346 if (total > cur) 9347 xmlXPathCompSwap(op); 9348 return (total + cur); 9349 case XPATH_OP_ROOT: 9350 xmlXPathRoot(ctxt); 9351 return (0); 9352 case XPATH_OP_NODE: 9353 if (op->ch1 != -1) 9354 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9355 CHECK_ERROR0; 9356 if (op->ch2 != -1) 9357 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9358 CHECK_ERROR0; 9359 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 9360 return (total); 9361 case XPATH_OP_RESET: 9362 if (op->ch1 != -1) 9363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9364 CHECK_ERROR0; 9365 if (op->ch2 != -1) 9366 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9367 CHECK_ERROR0; 9368 ctxt->context->node = NULL; 9369 return (total); 9370 case XPATH_OP_COLLECT:{ 9371 if (op->ch1 == -1) 9372 return (total); 9373 9374 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9375 CHECK_ERROR0; 9376 9377 /* 9378 * Optimization for [n] selection where n is a number 9379 */ 9380 if ((op->ch2 != -1) && 9381 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 9382 (comp->steps[op->ch2].ch1 == -1) && 9383 (comp->steps[op->ch2].ch2 != -1) && 9384 (comp->steps[comp->steps[op->ch2].ch2].op == 9385 XPATH_OP_VALUE)) { 9386 xmlXPathObjectPtr val; 9387 9388 val = comp->steps[comp->steps[op->ch2].ch2].value4; 9389 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 9390 int indx = (int) val->floatval; 9391 9392 if (val->floatval == (float) indx) { 9393 xmlXPathNodeCollectAndTestNth(ctxt, op, indx, 9394 first, NULL); 9395 return (total); 9396 } 9397 } 9398 } 9399 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL); 9400 return (total); 9401 } 9402 case XPATH_OP_VALUE: 9403 valuePush(ctxt, 9404 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); 9405 return (0); 9406 case XPATH_OP_SORT: 9407 if (op->ch1 != -1) 9408 total += 9409 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1], 9410 first); 9411 CHECK_ERROR0; 9412 if ((ctxt->value != NULL) 9413 && (ctxt->value->type == XPATH_NODESET) 9414 && (ctxt->value->nodesetval != NULL)) 9415 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9416 return (total); 9417 default: 9418 return (xmlXPathCompOpEval(ctxt, op)); 9419 } 9420} 9421 9422/** 9423 * xmlXPathCompOpEvalLast: 9424 * @ctxt: the XPath parser context with the compiled expression 9425 * @op: an XPath compiled operation 9426 * @last: the last elem found so far 9427 * 9428 * Evaluate the Precompiled XPath operation searching only the last 9429 * element in document order 9430 * 9431 * Returns the number of node traversed 9432 */ 9433static int 9434xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op, 9435 xmlNodePtr * last) 9436{ 9437 int total = 0, cur; 9438 xmlXPathCompExprPtr comp; 9439 xmlXPathObjectPtr arg1, arg2; 9440 9441 CHECK_ERROR0; 9442 comp = ctxt->comp; 9443 switch (op->op) { 9444 case XPATH_OP_END: 9445 return (0); 9446 case XPATH_OP_UNION: 9447 total = 9448 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last); 9449 CHECK_ERROR0; 9450 if ((ctxt->value != NULL) 9451 && (ctxt->value->type == XPATH_NODESET) 9452 && (ctxt->value->nodesetval != NULL) 9453 && (ctxt->value->nodesetval->nodeNr >= 1)) { 9454 /* 9455 * limit tree traversing to first node in the result 9456 */ 9457 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9458 *last = 9459 ctxt->value->nodesetval->nodeTab[ctxt->value-> 9460 nodesetval->nodeNr - 9461 1]; 9462 } 9463 cur = 9464 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last); 9465 CHECK_ERROR0; 9466 if ((ctxt->value != NULL) 9467 && (ctxt->value->type == XPATH_NODESET) 9468 && (ctxt->value->nodesetval != NULL) 9469 && (ctxt->value->nodesetval->nodeNr >= 1)) { 9470 } 9471 CHECK_TYPE0(XPATH_NODESET); 9472 arg2 = valuePop(ctxt); 9473 9474 CHECK_TYPE0(XPATH_NODESET); 9475 arg1 = valuePop(ctxt); 9476 9477 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 9478 arg2->nodesetval); 9479 valuePush(ctxt, arg1); 9480 xmlXPathFreeObject(arg2); 9481 /* optimizer */ 9482 if (total > cur) 9483 xmlXPathCompSwap(op); 9484 return (total + cur); 9485 case XPATH_OP_ROOT: 9486 xmlXPathRoot(ctxt); 9487 return (0); 9488 case XPATH_OP_NODE: 9489 if (op->ch1 != -1) 9490 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9491 CHECK_ERROR0; 9492 if (op->ch2 != -1) 9493 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9494 CHECK_ERROR0; 9495 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 9496 return (total); 9497 case XPATH_OP_RESET: 9498 if (op->ch1 != -1) 9499 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9500 CHECK_ERROR0; 9501 if (op->ch2 != -1) 9502 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9503 CHECK_ERROR0; 9504 ctxt->context->node = NULL; 9505 return (total); 9506 case XPATH_OP_COLLECT:{ 9507 if (op->ch1 == -1) 9508 return (0); 9509 9510 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9511 CHECK_ERROR0; 9512 9513 /* 9514 * Optimization for [n] selection where n is a number 9515 */ 9516 if ((op->ch2 != -1) && 9517 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 9518 (comp->steps[op->ch2].ch1 == -1) && 9519 (comp->steps[op->ch2].ch2 != -1) && 9520 (comp->steps[comp->steps[op->ch2].ch2].op == 9521 XPATH_OP_VALUE)) { 9522 xmlXPathObjectPtr val; 9523 9524 val = comp->steps[comp->steps[op->ch2].ch2].value4; 9525 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 9526 int indx = (int) val->floatval; 9527 9528 if (val->floatval == (float) indx) { 9529 total += 9530 xmlXPathNodeCollectAndTestNth(ctxt, op, 9531 indx, NULL, 9532 last); 9533 return (total); 9534 } 9535 } 9536 } 9537 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last); 9538 return (total); 9539 } 9540 case XPATH_OP_VALUE: 9541 valuePush(ctxt, 9542 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); 9543 return (0); 9544 case XPATH_OP_SORT: 9545 if (op->ch1 != -1) 9546 total += 9547 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], 9548 last); 9549 CHECK_ERROR0; 9550 if ((ctxt->value != NULL) 9551 && (ctxt->value->type == XPATH_NODESET) 9552 && (ctxt->value->nodesetval != NULL)) 9553 xmlXPathNodeSetSort(ctxt->value->nodesetval); 9554 return (total); 9555 default: 9556 return (xmlXPathCompOpEval(ctxt, op)); 9557 } 9558} 9559 9560/** 9561 * xmlXPathCompOpEval: 9562 * @ctxt: the XPath parser context with the compiled expression 9563 * @op: an XPath compiled operation 9564 * 9565 * Evaluate the Precompiled XPath operation 9566 * Returns the number of node traversed 9567 */ 9568static int 9569xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op) 9570{ 9571 int total = 0; 9572 int equal, ret; 9573 xmlXPathCompExprPtr comp; 9574 xmlXPathObjectPtr arg1, arg2; 9575 xmlNodePtr bak; 9576 xmlDocPtr bakd; 9577 9578 CHECK_ERROR0; 9579 comp = ctxt->comp; 9580 switch (op->op) { 9581 case XPATH_OP_END: 9582 return (0); 9583 case XPATH_OP_AND: 9584 bakd = ctxt->context->doc; 9585 bak = ctxt->context->node; 9586 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9587 CHECK_ERROR0; 9588 xmlXPathBooleanFunction(ctxt, 1); 9589 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0)) 9590 return (total); 9591 arg2 = valuePop(ctxt); 9592 ctxt->context->doc = bakd; 9593 ctxt->context->node = bak; 9594 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9595 if (ctxt->error) { 9596 xmlXPathFreeObject(arg2); 9597 return(0); 9598 } 9599 xmlXPathBooleanFunction(ctxt, 1); 9600 arg1 = valuePop(ctxt); 9601 arg1->boolval &= arg2->boolval; 9602 valuePush(ctxt, arg1); 9603 xmlXPathFreeObject(arg2); 9604 return (total); 9605 case XPATH_OP_OR: 9606 bakd = ctxt->context->doc; 9607 bak = ctxt->context->node; 9608 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9609 CHECK_ERROR0; 9610 xmlXPathBooleanFunction(ctxt, 1); 9611 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1)) 9612 return (total); 9613 arg2 = valuePop(ctxt); 9614 ctxt->context->doc = bakd; 9615 ctxt->context->node = bak; 9616 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9617 if (ctxt->error) { 9618 xmlXPathFreeObject(arg2); 9619 return(0); 9620 } 9621 xmlXPathBooleanFunction(ctxt, 1); 9622 arg1 = valuePop(ctxt); 9623 arg1->boolval |= arg2->boolval; 9624 valuePush(ctxt, arg1); 9625 xmlXPathFreeObject(arg2); 9626 return (total); 9627 case XPATH_OP_EQUAL: 9628 bakd = ctxt->context->doc; 9629 bak = ctxt->context->node; 9630 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9631 CHECK_ERROR0; 9632 ctxt->context->doc = bakd; 9633 ctxt->context->node = bak; 9634 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9635 CHECK_ERROR0; 9636 equal = xmlXPathEqualValues(ctxt); 9637 if (op->value) 9638 valuePush(ctxt, xmlXPathNewBoolean(equal)); 9639 else 9640 valuePush(ctxt, xmlXPathNewBoolean(!equal)); 9641 return (total); 9642 case XPATH_OP_CMP: 9643 bakd = ctxt->context->doc; 9644 bak = ctxt->context->node; 9645 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9646 CHECK_ERROR0; 9647 ctxt->context->doc = bakd; 9648 ctxt->context->node = bak; 9649 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9650 CHECK_ERROR0; 9651 ret = xmlXPathCompareValues(ctxt, op->value, op->value2); 9652 valuePush(ctxt, xmlXPathNewBoolean(ret)); 9653 return (total); 9654 case XPATH_OP_PLUS: 9655 bakd = ctxt->context->doc; 9656 bak = ctxt->context->node; 9657 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9658 CHECK_ERROR0; 9659 if (op->ch2 != -1) { 9660 ctxt->context->doc = bakd; 9661 ctxt->context->node = bak; 9662 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9663 } 9664 CHECK_ERROR0; 9665 if (op->value == 0) 9666 xmlXPathSubValues(ctxt); 9667 else if (op->value == 1) 9668 xmlXPathAddValues(ctxt); 9669 else if (op->value == 2) 9670 xmlXPathValueFlipSign(ctxt); 9671 else if (op->value == 3) { 9672 CAST_TO_NUMBER; 9673 CHECK_TYPE0(XPATH_NUMBER); 9674 } 9675 return (total); 9676 case XPATH_OP_MULT: 9677 bakd = ctxt->context->doc; 9678 bak = ctxt->context->node; 9679 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9680 CHECK_ERROR0; 9681 ctxt->context->doc = bakd; 9682 ctxt->context->node = bak; 9683 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9684 CHECK_ERROR0; 9685 if (op->value == 0) 9686 xmlXPathMultValues(ctxt); 9687 else if (op->value == 1) 9688 xmlXPathDivValues(ctxt); 9689 else if (op->value == 2) 9690 xmlXPathModValues(ctxt); 9691 return (total); 9692 case XPATH_OP_UNION: 9693 bakd = ctxt->context->doc; 9694 bak = ctxt->context->node; 9695 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9696 CHECK_ERROR0; 9697 ctxt->context->doc = bakd; 9698 ctxt->context->node = bak; 9699 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9700 CHECK_ERROR0; 9701 CHECK_TYPE0(XPATH_NODESET); 9702 arg2 = valuePop(ctxt); 9703 9704 CHECK_TYPE0(XPATH_NODESET); 9705 arg1 = valuePop(ctxt); 9706 9707 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval, 9708 arg2->nodesetval); 9709 valuePush(ctxt, arg1); 9710 xmlXPathFreeObject(arg2); 9711 return (total); 9712 case XPATH_OP_ROOT: 9713 xmlXPathRoot(ctxt); 9714 return (total); 9715 case XPATH_OP_NODE: 9716 if (op->ch1 != -1) 9717 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9718 CHECK_ERROR0; 9719 if (op->ch2 != -1) 9720 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9721 CHECK_ERROR0; 9722 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node)); 9723 return (total); 9724 case XPATH_OP_RESET: 9725 if (op->ch1 != -1) 9726 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9727 CHECK_ERROR0; 9728 if (op->ch2 != -1) 9729 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9730 CHECK_ERROR0; 9731 ctxt->context->node = NULL; 9732 return (total); 9733 case XPATH_OP_COLLECT:{ 9734 if (op->ch1 == -1) 9735 return (total); 9736 9737 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9738 CHECK_ERROR0; 9739 9740 /* 9741 * Optimization for [n] selection where n is a number 9742 */ 9743 if ((op->ch2 != -1) && 9744 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) && 9745 (comp->steps[op->ch2].ch1 == -1) && 9746 (comp->steps[op->ch2].ch2 != -1) && 9747 (comp->steps[comp->steps[op->ch2].ch2].op == 9748 XPATH_OP_VALUE)) { 9749 xmlXPathObjectPtr val; 9750 9751 val = comp->steps[comp->steps[op->ch2].ch2].value4; 9752 if ((val != NULL) && (val->type == XPATH_NUMBER)) { 9753 int indx = (int) val->floatval; 9754 9755 if (val->floatval == (float) indx) { 9756 total += 9757 xmlXPathNodeCollectAndTestNth(ctxt, op, 9758 indx, NULL, 9759 NULL); 9760 return (total); 9761 } 9762 } 9763 } 9764 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL); 9765 return (total); 9766 } 9767 case XPATH_OP_VALUE: 9768 valuePush(ctxt, 9769 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4)); 9770 return (total); 9771 case XPATH_OP_VARIABLE:{ 9772 xmlXPathObjectPtr val; 9773 9774 if (op->ch1 != -1) 9775 total += 9776 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9777 if (op->value5 == NULL) { 9778 val = xmlXPathVariableLookup(ctxt->context, op->value4); 9779 if (val == NULL) { 9780 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 9781 return(0); 9782 } 9783 valuePush(ctxt, val); 9784 } else { 9785 const xmlChar *URI; 9786 9787 URI = xmlXPathNsLookup(ctxt->context, op->value5); 9788 if (URI == NULL) { 9789 xmlGenericError(xmlGenericErrorContext, 9790 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n", 9791 op->value4, op->value5); 9792 return (total); 9793 } 9794 val = xmlXPathVariableLookupNS(ctxt->context, 9795 op->value4, URI); 9796 if (val == NULL) { 9797 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR; 9798 return(0); 9799 } 9800 valuePush(ctxt, val); 9801 } 9802 return (total); 9803 } 9804 case XPATH_OP_FUNCTION:{ 9805 xmlXPathFunction func; 9806 const xmlChar *oldFunc, *oldFuncURI; 9807 int i; 9808 9809 if (op->ch1 != -1) 9810 total += 9811 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9812 if (ctxt->valueNr < op->value) { 9813 xmlGenericError(xmlGenericErrorContext, 9814 "xmlXPathCompOpEval: parameter error\n"); 9815 ctxt->error = XPATH_INVALID_OPERAND; 9816 return (total); 9817 } 9818 for (i = 0; i < op->value; i++) 9819 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) { 9820 xmlGenericError(xmlGenericErrorContext, 9821 "xmlXPathCompOpEval: parameter error\n"); 9822 ctxt->error = XPATH_INVALID_OPERAND; 9823 return (total); 9824 } 9825 if (op->cache != NULL) 9826 func = (xmlXPathFunction) op->cache; 9827 else { 9828 const xmlChar *URI = NULL; 9829 9830 if (op->value5 == NULL) 9831 func = 9832 xmlXPathFunctionLookup(ctxt->context, 9833 op->value4); 9834 else { 9835 URI = xmlXPathNsLookup(ctxt->context, op->value5); 9836 if (URI == NULL) { 9837 xmlGenericError(xmlGenericErrorContext, 9838 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n", 9839 op->value4, op->value5); 9840 return (total); 9841 } 9842 func = xmlXPathFunctionLookupNS(ctxt->context, 9843 op->value4, URI); 9844 } 9845 if (func == NULL) { 9846 xmlGenericError(xmlGenericErrorContext, 9847 "xmlXPathCompOpEval: function %s not found\n", 9848 op->value4); 9849 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR); 9850 } 9851 op->cache = (void *) func; 9852 op->cacheURI = (void *) URI; 9853 } 9854 oldFunc = ctxt->context->function; 9855 oldFuncURI = ctxt->context->functionURI; 9856 ctxt->context->function = op->value4; 9857 ctxt->context->functionURI = op->cacheURI; 9858 func(ctxt, op->value); 9859 ctxt->context->function = oldFunc; 9860 ctxt->context->functionURI = oldFuncURI; 9861 return (total); 9862 } 9863 case XPATH_OP_ARG: 9864 bakd = ctxt->context->doc; 9865 bak = ctxt->context->node; 9866 if (op->ch1 != -1) 9867 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9868 ctxt->context->doc = bakd; 9869 ctxt->context->node = bak; 9870 CHECK_ERROR0; 9871 if (op->ch2 != -1) 9872 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]); 9873 ctxt->context->doc = bakd; 9874 ctxt->context->node = bak; 9875 CHECK_ERROR0; 9876 return (total); 9877 case XPATH_OP_PREDICATE: 9878 case XPATH_OP_FILTER:{ 9879 xmlXPathObjectPtr res; 9880 xmlXPathObjectPtr obj, tmp; 9881 xmlNodeSetPtr newset = NULL; 9882 xmlNodeSetPtr oldset; 9883 xmlNodePtr oldnode; 9884 int i; 9885 9886 /* 9887 * Optimization for ()[1] selection i.e. the first elem 9888 */ 9889 if ((op->ch1 != -1) && (op->ch2 != -1) && 9890 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 9891 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { 9892 xmlXPathObjectPtr val; 9893 9894 val = comp->steps[op->ch2].value4; 9895 if ((val != NULL) && (val->type == XPATH_NUMBER) && 9896 (val->floatval == 1.0)) { 9897 xmlNodePtr first = NULL; 9898 9899 total += 9900 xmlXPathCompOpEvalFirst(ctxt, 9901 &comp->steps[op->ch1], 9902 &first); 9903 CHECK_ERROR0; 9904 /* 9905 * The nodeset should be in document order, 9906 * Keep only the first value 9907 */ 9908 if ((ctxt->value != NULL) && 9909 (ctxt->value->type == XPATH_NODESET) && 9910 (ctxt->value->nodesetval != NULL) && 9911 (ctxt->value->nodesetval->nodeNr > 1)) 9912 ctxt->value->nodesetval->nodeNr = 1; 9913 return (total); 9914 } 9915 } 9916 /* 9917 * Optimization for ()[last()] selection i.e. the last elem 9918 */ 9919 if ((op->ch1 != -1) && (op->ch2 != -1) && 9920 (comp->steps[op->ch1].op == XPATH_OP_SORT) && 9921 (comp->steps[op->ch2].op == XPATH_OP_SORT)) { 9922 int f = comp->steps[op->ch2].ch1; 9923 9924 if ((f != -1) && 9925 (comp->steps[f].op == XPATH_OP_FUNCTION) && 9926 (comp->steps[f].value5 == NULL) && 9927 (comp->steps[f].value == 0) && 9928 (comp->steps[f].value4 != NULL) && 9929 (xmlStrEqual 9930 (comp->steps[f].value4, BAD_CAST "last"))) { 9931 xmlNodePtr last = NULL; 9932 9933 total += 9934 xmlXPathCompOpEvalLast(ctxt, 9935 &comp->steps[op->ch1], 9936 &last); 9937 CHECK_ERROR0; 9938 /* 9939 * The nodeset should be in document order, 9940 * Keep only the last value 9941 */ 9942 if ((ctxt->value != NULL) && 9943 (ctxt->value->type == XPATH_NODESET) && 9944 (ctxt->value->nodesetval != NULL) && 9945 (ctxt->value->nodesetval->nodeTab != NULL) && 9946 (ctxt->value->nodesetval->nodeNr > 1)) { 9947 ctxt->value->nodesetval->nodeTab[0] = 9948 ctxt->value->nodesetval->nodeTab[ctxt-> 9949 value-> 9950 nodesetval-> 9951 nodeNr - 9952 1]; 9953 ctxt->value->nodesetval->nodeNr = 1; 9954 } 9955 return (total); 9956 } 9957 } 9958 9959 if (op->ch1 != -1) 9960 total += 9961 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 9962 CHECK_ERROR0; 9963 if (op->ch2 == -1) 9964 return (total); 9965 if (ctxt->value == NULL) 9966 return (total); 9967 9968 oldnode = ctxt->context->node; 9969 9970#ifdef LIBXML_XPTR_ENABLED 9971 /* 9972 * Hum are we filtering the result of an XPointer expression 9973 */ 9974 if (ctxt->value->type == XPATH_LOCATIONSET) { 9975 xmlLocationSetPtr newlocset = NULL; 9976 xmlLocationSetPtr oldlocset; 9977 9978 /* 9979 * Extract the old locset, and then evaluate the result of the 9980 * expression for all the element in the locset. use it to grow 9981 * up a new locset. 9982 */ 9983 CHECK_TYPE0(XPATH_LOCATIONSET); 9984 obj = valuePop(ctxt); 9985 oldlocset = obj->user; 9986 ctxt->context->node = NULL; 9987 9988 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) { 9989 ctxt->context->contextSize = 0; 9990 ctxt->context->proximityPosition = 0; 9991 if (op->ch2 != -1) 9992 total += 9993 xmlXPathCompOpEval(ctxt, 9994 &comp->steps[op->ch2]); 9995 res = valuePop(ctxt); 9996 if (res != NULL) 9997 xmlXPathFreeObject(res); 9998 valuePush(ctxt, obj); 9999 CHECK_ERROR0; 10000 return (total); 10001 } 10002 newlocset = xmlXPtrLocationSetCreate(NULL); 10003 10004 for (i = 0; i < oldlocset->locNr; i++) { 10005 /* 10006 * Run the evaluation with a node list made of a 10007 * single item in the nodelocset. 10008 */ 10009 ctxt->context->node = oldlocset->locTab[i]->user; 10010 tmp = xmlXPathNewNodeSet(ctxt->context->node); 10011 valuePush(ctxt, tmp); 10012 ctxt->context->contextSize = oldlocset->locNr; 10013 ctxt->context->proximityPosition = i + 1; 10014 10015 if (op->ch2 != -1) 10016 total += 10017 xmlXPathCompOpEval(ctxt, 10018 &comp->steps[op->ch2]); 10019 CHECK_ERROR0; 10020 10021 /* 10022 * The result of the evaluation need to be tested to 10023 * decided whether the filter succeeded or not 10024 */ 10025 res = valuePop(ctxt); 10026 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 10027 xmlXPtrLocationSetAdd(newlocset, 10028 xmlXPathObjectCopy 10029 (oldlocset->locTab[i])); 10030 } 10031 10032 /* 10033 * Cleanup 10034 */ 10035 if (res != NULL) 10036 xmlXPathFreeObject(res); 10037 if (ctxt->value == tmp) { 10038 res = valuePop(ctxt); 10039 xmlXPathFreeObject(res); 10040 } 10041 10042 ctxt->context->node = NULL; 10043 } 10044 10045 /* 10046 * The result is used as the new evaluation locset. 10047 */ 10048 xmlXPathFreeObject(obj); 10049 ctxt->context->node = NULL; 10050 ctxt->context->contextSize = -1; 10051 ctxt->context->proximityPosition = -1; 10052 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset)); 10053 ctxt->context->node = oldnode; 10054 return (total); 10055 } 10056#endif /* LIBXML_XPTR_ENABLED */ 10057 10058 /* 10059 * Extract the old set, and then evaluate the result of the 10060 * expression for all the element in the set. use it to grow 10061 * up a new set. 10062 */ 10063 CHECK_TYPE0(XPATH_NODESET); 10064 obj = valuePop(ctxt); 10065 oldset = obj->nodesetval; 10066 10067 oldnode = ctxt->context->node; 10068 ctxt->context->node = NULL; 10069 10070 if ((oldset == NULL) || (oldset->nodeNr == 0)) { 10071 ctxt->context->contextSize = 0; 10072 ctxt->context->proximityPosition = 0; 10073 if (op->ch2 != -1) 10074 total += 10075 xmlXPathCompOpEval(ctxt, 10076 &comp->steps[op->ch2]); 10077 CHECK_ERROR0; 10078 res = valuePop(ctxt); 10079 if (res != NULL) 10080 xmlXPathFreeObject(res); 10081 valuePush(ctxt, obj); 10082 ctxt->context->node = oldnode; 10083 CHECK_ERROR0; 10084 } else { 10085 /* 10086 * Initialize the new set. 10087 */ 10088 newset = xmlXPathNodeSetCreate(NULL); 10089 10090 for (i = 0; i < oldset->nodeNr; i++) { 10091 /* 10092 * Run the evaluation with a node list made of 10093 * a single item in the nodeset. 10094 */ 10095 ctxt->context->node = oldset->nodeTab[i]; 10096 tmp = xmlXPathNewNodeSet(ctxt->context->node); 10097 valuePush(ctxt, tmp); 10098 ctxt->context->contextSize = oldset->nodeNr; 10099 ctxt->context->proximityPosition = i + 1; 10100 10101 if (op->ch2 != -1) 10102 total += 10103 xmlXPathCompOpEval(ctxt, 10104 &comp->steps[op->ch2]); 10105 CHECK_ERROR0; 10106 10107 /* 10108 * The result of the evaluation need to be tested to 10109 * decided whether the filter succeeded or not 10110 */ 10111 res = valuePop(ctxt); 10112 if (xmlXPathEvaluatePredicateResult(ctxt, res)) { 10113 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); 10114 } 10115 10116 /* 10117 * Cleanup 10118 */ 10119 if (res != NULL) 10120 xmlXPathFreeObject(res); 10121 if (ctxt->value == tmp) { 10122 res = valuePop(ctxt); 10123 xmlXPathFreeObject(res); 10124 } 10125 10126 ctxt->context->node = NULL; 10127 } 10128 10129 /* 10130 * The result is used as the new evaluation set. 10131 */ 10132 xmlXPathFreeObject(obj); 10133 ctxt->context->node = NULL; 10134 ctxt->context->contextSize = -1; 10135 ctxt->context->proximityPosition = -1; 10136 valuePush(ctxt, xmlXPathWrapNodeSet(newset)); 10137 } 10138 ctxt->context->node = oldnode; 10139 return (total); 10140 } 10141 case XPATH_OP_SORT: 10142 if (op->ch1 != -1) 10143 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10144 CHECK_ERROR0; 10145 if ((ctxt->value != NULL) && 10146 (ctxt->value->type == XPATH_NODESET) && 10147 (ctxt->value->nodesetval != NULL)) 10148 xmlXPathNodeSetSort(ctxt->value->nodesetval); 10149 return (total); 10150#ifdef LIBXML_XPTR_ENABLED 10151 case XPATH_OP_RANGETO:{ 10152 xmlXPathObjectPtr range; 10153 xmlXPathObjectPtr res, obj; 10154 xmlXPathObjectPtr tmp; 10155 xmlLocationSetPtr newset = NULL; 10156 xmlNodeSetPtr oldset; 10157 int i; 10158 10159 if (op->ch1 != -1) 10160 total += 10161 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]); 10162 if (op->ch2 == -1) 10163 return (total); 10164 10165 CHECK_TYPE0(XPATH_NODESET); 10166 obj = valuePop(ctxt); 10167 oldset = obj->nodesetval; 10168 ctxt->context->node = NULL; 10169 10170 newset = xmlXPtrLocationSetCreate(NULL); 10171 10172 if (oldset != NULL) { 10173 for (i = 0; i < oldset->nodeNr; i++) { 10174 /* 10175 * Run the evaluation with a node list made of a single item 10176 * in the nodeset. 10177 */ 10178 ctxt->context->node = oldset->nodeTab[i]; 10179 tmp = xmlXPathNewNodeSet(ctxt->context->node); 10180 valuePush(ctxt, tmp); 10181 10182 if (op->ch2 != -1) 10183 total += 10184 xmlXPathCompOpEval(ctxt, 10185 &comp->steps[op->ch2]); 10186 CHECK_ERROR0; 10187 10188 /* 10189 * The result of the evaluation need to be tested to 10190 * decided whether the filter succeeded or not 10191 */ 10192 res = valuePop(ctxt); 10193 range = 10194 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], 10195 res); 10196 if (range != NULL) { 10197 xmlXPtrLocationSetAdd(newset, range); 10198 } 10199 10200 /* 10201 * Cleanup 10202 */ 10203 if (res != NULL) 10204 xmlXPathFreeObject(res); 10205 if (ctxt->value == tmp) { 10206 res = valuePop(ctxt); 10207 xmlXPathFreeObject(res); 10208 } 10209 10210 ctxt->context->node = NULL; 10211 } 10212 } 10213 10214 /* 10215 * The result is used as the new evaluation set. 10216 */ 10217 xmlXPathFreeObject(obj); 10218 ctxt->context->node = NULL; 10219 ctxt->context->contextSize = -1; 10220 ctxt->context->proximityPosition = -1; 10221 valuePush(ctxt, xmlXPtrWrapLocationSet(newset)); 10222 return (total); 10223 } 10224#endif /* LIBXML_XPTR_ENABLED */ 10225 } 10226 xmlGenericError(xmlGenericErrorContext, 10227 "XPath: unknown precompiled operation %d\n", op->op); 10228 return (total); 10229} 10230 10231/** 10232 * xmlXPathRunEval: 10233 * @ctxt: the XPath parser context with the compiled expression 10234 * 10235 * Evaluate the Precompiled XPath expression in the given context. 10236 */ 10237static void 10238xmlXPathRunEval(xmlXPathParserContextPtr ctxt) { 10239 xmlXPathCompExprPtr comp; 10240 10241 if ((ctxt == NULL) || (ctxt->comp == NULL)) 10242 return; 10243 10244 if (ctxt->valueTab == NULL) { 10245 /* Allocate the value stack */ 10246 ctxt->valueTab = (xmlXPathObjectPtr *) 10247 xmlMalloc(10 * sizeof(xmlXPathObjectPtr)); 10248 if (ctxt->valueTab == NULL) { 10249 xmlFree(ctxt); 10250 } 10251 ctxt->valueNr = 0; 10252 ctxt->valueMax = 10; 10253 ctxt->value = NULL; 10254 } 10255 comp = ctxt->comp; 10256 if(comp->last < 0) { 10257 xmlGenericError(xmlGenericErrorContext, 10258 "xmlXPathRunEval: last is less than zero\n"); 10259 return; 10260 } 10261 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]); 10262} 10263 10264/************************************************************************ 10265 * * 10266 * Public interfaces * 10267 * * 10268 ************************************************************************/ 10269 10270/** 10271 * xmlXPathEvalPredicate: 10272 * @ctxt: the XPath context 10273 * @res: the Predicate Expression evaluation result 10274 * 10275 * Evaluate a predicate result for the current node. 10276 * A PredicateExpr is evaluated by evaluating the Expr and converting 10277 * the result to a boolean. If the result is a number, the result will 10278 * be converted to true if the number is equal to the position of the 10279 * context node in the context node list (as returned by the position 10280 * function) and will be converted to false otherwise; if the result 10281 * is not a number, then the result will be converted as if by a call 10282 * to the boolean function. 10283 * 10284 * Returns 1 if predicate is true, 0 otherwise 10285 */ 10286int 10287xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) { 10288 if (res == NULL) return(0); 10289 switch (res->type) { 10290 case XPATH_BOOLEAN: 10291 return(res->boolval); 10292 case XPATH_NUMBER: 10293 return(res->floatval == ctxt->proximityPosition); 10294 case XPATH_NODESET: 10295 case XPATH_XSLT_TREE: 10296 if (res->nodesetval == NULL) 10297 return(0); 10298 return(res->nodesetval->nodeNr != 0); 10299 case XPATH_STRING: 10300 return((res->stringval != NULL) && 10301 (xmlStrlen(res->stringval) != 0)); 10302 default: 10303 STRANGE 10304 } 10305 return(0); 10306} 10307 10308/** 10309 * xmlXPathEvaluatePredicateResult: 10310 * @ctxt: the XPath Parser context 10311 * @res: the Predicate Expression evaluation result 10312 * 10313 * Evaluate a predicate result for the current node. 10314 * A PredicateExpr is evaluated by evaluating the Expr and converting 10315 * the result to a boolean. If the result is a number, the result will 10316 * be converted to true if the number is equal to the position of the 10317 * context node in the context node list (as returned by the position 10318 * function) and will be converted to false otherwise; if the result 10319 * is not a number, then the result will be converted as if by a call 10320 * to the boolean function. 10321 * 10322 * Returns 1 if predicate is true, 0 otherwise 10323 */ 10324int 10325xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 10326 xmlXPathObjectPtr res) { 10327 if (res == NULL) return(0); 10328 switch (res->type) { 10329 case XPATH_BOOLEAN: 10330 return(res->boolval); 10331 case XPATH_NUMBER: 10332 return(res->floatval == ctxt->context->proximityPosition); 10333 case XPATH_NODESET: 10334 case XPATH_XSLT_TREE: 10335 if (res->nodesetval == NULL) 10336 return(0); 10337 return(res->nodesetval->nodeNr != 0); 10338 case XPATH_STRING: 10339 return((res->stringval != NULL) && 10340 (xmlStrlen(res->stringval) != 0)); 10341 default: 10342 STRANGE 10343 } 10344 return(0); 10345} 10346 10347/** 10348 * xmlXPathCompile: 10349 * @str: the XPath expression 10350 * 10351 * Compile an XPath expression 10352 * 10353 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 10354 * the caller has to free the object. 10355 */ 10356xmlXPathCompExprPtr 10357xmlXPathCompile(const xmlChar *str) { 10358 xmlXPathParserContextPtr ctxt; 10359 xmlXPathCompExprPtr comp; 10360 10361 xmlXPathInit(); 10362 10363 ctxt = xmlXPathNewParserContext(str, NULL); 10364 xmlXPathCompileExpr(ctxt); 10365 10366 if (*ctxt->cur != 0) { 10367 /* 10368 * aleksey: in some cases this line prints *second* error message 10369 * (see bug #78858) and probably this should be fixed. 10370 * However, we are not sure that all error messages are printed 10371 * out in other places. It's not critical so we leave it as-is for now 10372 */ 10373 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 10374 comp = NULL; 10375 } else { 10376 comp = ctxt->comp; 10377 ctxt->comp = NULL; 10378 } 10379 xmlXPathFreeParserContext(ctxt); 10380#ifdef DEBUG_EVAL_COUNTS 10381 if (comp != NULL) { 10382 comp->string = xmlStrdup(str); 10383 comp->nb = 0; 10384 } 10385#endif 10386 return(comp); 10387} 10388 10389/** 10390 * xmlXPathCompiledEval: 10391 * @comp: the compiled XPath expression 10392 * @ctx: the XPath context 10393 * 10394 * Evaluate the Precompiled XPath expression in the given context. 10395 * 10396 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 10397 * the caller has to free the object. 10398 */ 10399xmlXPathObjectPtr 10400xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) { 10401 xmlXPathParserContextPtr ctxt; 10402 xmlXPathObjectPtr res, tmp, init = NULL; 10403 int stack = 0; 10404#ifndef LIBXML_THREAD_ENABLED 10405 static int reentance = 0; 10406#endif 10407 10408 if ((comp == NULL) || (ctx == NULL)) 10409 return(NULL); 10410 xmlXPathInit(); 10411 10412 CHECK_CONTEXT(ctx) 10413 10414#ifndef LIBXML_THREAD_ENABLED 10415 reentance++; 10416 if (reentance > 1) 10417 xmlXPathDisableOptimizer = 1; 10418#endif 10419 10420#ifdef DEBUG_EVAL_COUNTS 10421 comp->nb++; 10422 if ((comp->string != NULL) && (comp->nb > 100)) { 10423 fprintf(stderr, "100 x %s\n", comp->string); 10424 comp->nb = 0; 10425 } 10426#endif 10427 ctxt = xmlXPathCompParserContext(comp, ctx); 10428 xmlXPathRunEval(ctxt); 10429 10430 if (ctxt->value == NULL) { 10431 xmlGenericError(xmlGenericErrorContext, 10432 "xmlXPathCompiledEval: evaluation failed\n"); 10433 res = NULL; 10434 } else { 10435 res = valuePop(ctxt); 10436 } 10437 10438 10439 do { 10440 tmp = valuePop(ctxt); 10441 if (tmp != NULL) { 10442 if (tmp != init) 10443 stack++; 10444 xmlXPathFreeObject(tmp); 10445 } 10446 } while (tmp != NULL); 10447 if ((stack != 0) && (res != NULL)) { 10448 xmlGenericError(xmlGenericErrorContext, 10449 "xmlXPathCompiledEval: %d object left on the stack\n", 10450 stack); 10451 } 10452 if (ctxt->error != XPATH_EXPRESSION_OK) { 10453 xmlXPathFreeObject(res); 10454 res = NULL; 10455 } 10456 10457 10458 ctxt->comp = NULL; 10459 xmlXPathFreeParserContext(ctxt); 10460#ifndef LIBXML_THREAD_ENABLED 10461 reentance--; 10462#endif 10463 return(res); 10464} 10465 10466/** 10467 * xmlXPathEvalExpr: 10468 * @ctxt: the XPath Parser context 10469 * 10470 * Parse and evaluate an XPath expression in the given context, 10471 * then push the result on the context stack 10472 */ 10473void 10474xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) { 10475 xmlXPathCompileExpr(ctxt); 10476 CHECK_ERROR; 10477 xmlXPathRunEval(ctxt); 10478} 10479 10480/** 10481 * xmlXPathEval: 10482 * @str: the XPath expression 10483 * @ctx: the XPath context 10484 * 10485 * Evaluate the XPath Location Path in the given context. 10486 * 10487 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 10488 * the caller has to free the object. 10489 */ 10490xmlXPathObjectPtr 10491xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) { 10492 xmlXPathParserContextPtr ctxt; 10493 xmlXPathObjectPtr res, tmp, init = NULL; 10494 int stack = 0; 10495 10496 xmlXPathInit(); 10497 10498 CHECK_CONTEXT(ctx) 10499 10500 ctxt = xmlXPathNewParserContext(str, ctx); 10501 xmlXPathEvalExpr(ctxt); 10502 10503 if (ctxt->value == NULL) { 10504 xmlGenericError(xmlGenericErrorContext, 10505 "xmlXPathEval: evaluation failed\n"); 10506 res = NULL; 10507 } else if (*ctxt->cur != 0) { 10508 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 10509 res = NULL; 10510 } else { 10511 res = valuePop(ctxt); 10512 } 10513 10514 do { 10515 tmp = valuePop(ctxt); 10516 if (tmp != NULL) { 10517 if (tmp != init) 10518 stack++; 10519 xmlXPathFreeObject(tmp); 10520 } 10521 } while (tmp != NULL); 10522 if ((stack != 0) && (res != NULL)) { 10523 xmlGenericError(xmlGenericErrorContext, 10524 "xmlXPathEval: %d object left on the stack\n", 10525 stack); 10526 } 10527 if (ctxt->error != XPATH_EXPRESSION_OK) { 10528 xmlXPathFreeObject(res); 10529 res = NULL; 10530 } 10531 10532 xmlXPathFreeParserContext(ctxt); 10533 return(res); 10534} 10535 10536/** 10537 * xmlXPathEvalExpression: 10538 * @str: the XPath expression 10539 * @ctxt: the XPath context 10540 * 10541 * Evaluate the XPath expression in the given context. 10542 * 10543 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL. 10544 * the caller has to free the object. 10545 */ 10546xmlXPathObjectPtr 10547xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) { 10548 xmlXPathParserContextPtr pctxt; 10549 xmlXPathObjectPtr res, tmp; 10550 int stack = 0; 10551 10552 xmlXPathInit(); 10553 10554 CHECK_CONTEXT(ctxt) 10555 10556 pctxt = xmlXPathNewParserContext(str, ctxt); 10557 xmlXPathEvalExpr(pctxt); 10558 10559 if (*pctxt->cur != 0) { 10560 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR); 10561 res = NULL; 10562 } else { 10563 res = valuePop(pctxt); 10564 } 10565 do { 10566 tmp = valuePop(pctxt); 10567 if (tmp != NULL) { 10568 xmlXPathFreeObject(tmp); 10569 stack++; 10570 } 10571 } while (tmp != NULL); 10572 if ((stack != 0) && (res != NULL)) { 10573 xmlGenericError(xmlGenericErrorContext, 10574 "xmlXPathEvalExpression: %d object left on the stack\n", 10575 stack); 10576 } 10577 xmlXPathFreeParserContext(pctxt); 10578 return(res); 10579} 10580 10581/** 10582 * xmlXPathRegisterAllFunctions: 10583 * @ctxt: the XPath context 10584 * 10585 * Registers all default XPath functions in this context 10586 */ 10587void 10588xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt) 10589{ 10590 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean", 10591 xmlXPathBooleanFunction); 10592 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling", 10593 xmlXPathCeilingFunction); 10594 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count", 10595 xmlXPathCountFunction); 10596 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat", 10597 xmlXPathConcatFunction); 10598 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains", 10599 xmlXPathContainsFunction); 10600 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id", 10601 xmlXPathIdFunction); 10602 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false", 10603 xmlXPathFalseFunction); 10604 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor", 10605 xmlXPathFloorFunction); 10606 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last", 10607 xmlXPathLastFunction); 10608 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang", 10609 xmlXPathLangFunction); 10610 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name", 10611 xmlXPathLocalNameFunction); 10612 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not", 10613 xmlXPathNotFunction); 10614 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name", 10615 xmlXPathNameFunction); 10616 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri", 10617 xmlXPathNamespaceURIFunction); 10618 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space", 10619 xmlXPathNormalizeFunction); 10620 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number", 10621 xmlXPathNumberFunction); 10622 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position", 10623 xmlXPathPositionFunction); 10624 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round", 10625 xmlXPathRoundFunction); 10626 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string", 10627 xmlXPathStringFunction); 10628 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length", 10629 xmlXPathStringLengthFunction); 10630 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with", 10631 xmlXPathStartsWithFunction); 10632 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring", 10633 xmlXPathSubstringFunction); 10634 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before", 10635 xmlXPathSubstringBeforeFunction); 10636 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after", 10637 xmlXPathSubstringAfterFunction); 10638 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum", 10639 xmlXPathSumFunction); 10640 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true", 10641 xmlXPathTrueFunction); 10642 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate", 10643 xmlXPathTranslateFunction); 10644} 10645 10646#endif /* LIBXML_XPATH_ENABLED */ 10647