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