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
6 * Reference: W3C Recommendation 16 November 1999
7 * http://www.w3.org/TR/1999/REC-xpath-19991116
9 * http://www.w3.org/TR/xpath
11 * See Copyright for the status of this software
13 * Author: daniel@veillard.com
22 #ifdef HAVE_SYS_TYPES_H
23 #include <sys/types.h>
38 #include <libxml/xmlmemory.h>
39 #include <libxml/tree.h>
40 #include <libxml/valid.h>
41 #include <libxml/xpath.h>
42 #include <libxml/xpathInternals.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/hash.h>
45 #ifdef LIBXML_XPTR_ENABLED
46 #include <libxml/xpointer.h>
48 #ifdef LIBXML_DEBUG_ENABLED
49 #include <libxml/debugXML.h>
51 #include <libxml/xmlerror.h>
52 #include <libxml/threads.h>
53 #include <libxml/globals.h>
55 /************************************************************************
57 * Floating point stuff *
59 ************************************************************************/
61 #ifndef TRIO_REPLACE_STDIO
62 #define TRIO_PUBLIC static
67 * The lack of portability of this section of the libc is annoying !
69 double xmlXPathNAN = 0;
70 double xmlXPathPINF = 1;
71 double xmlXPathNINF = -1;
72 double xmlXPathNZERO = 0;
73 static int xmlXPathInitialized = 0;
78 * Initialize the XPath environment
82 if (xmlXPathInitialized) return;
84 xmlXPathPINF = trio_pinf();
85 xmlXPathNINF = trio_ninf();
86 xmlXPathNAN = trio_nan();
87 xmlXPathNZERO = trio_nzero();
89 xmlXPathInitialized = 1;
94 * @val: a double value
96 * Provides a portable isnan() function to detect whether a double
97 * is a NotaNumber. Based on trio code
98 * http://sourceforge.net/projects/ctrio/
100 * Returns 1 if the value is a NaN, 0 otherwise
103 xmlXPathIsNaN(double val) {
104 return(trio_isnan(val));
109 * @val: a double value
111 * Provides a portable isinf() function to detect whether a double
112 * is a +Infinite or -Infinite. Based on trio code
113 * http://sourceforge.net/projects/ctrio/
115 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
118 xmlXPathIsInf(double val) {
119 return(trio_isinf(val));
124 * @val: a double value
126 * Provides a portable function to detect the sign of a double
127 * Modified from trio code
128 * http://sourceforge.net/projects/ctrio/
130 * Returns 1 if the value is Negative, 0 if positive
133 xmlXPathGetSign(double val) {
134 return(trio_signbit(val));
138 #ifdef LIBXML_XPATH_ENABLED
140 * TODO: when compatibility allows remove all "fake node libxslt" strings
141 * the test should just be name[0] = ' '
144 /* #define DEBUG_STEP */
145 /* #define DEBUG_STEP_NTH */
146 /* #define DEBUG_EXPR */
147 /* #define DEBUG_EVAL_COUNTS */
149 static xmlNs xmlXPathXMLNamespaceStruct = {
156 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
157 #ifndef LIBXML_THREAD_ENABLED
159 * Optimizer is disabled only when threaded apps are detected while
160 * the library ain't compiled for thread safety.
162 static int xmlXPathDisableOptimizer = 0;
165 /************************************************************************
169 ************************************************************************/
195 #ifdef LIBXML_XPTR_ENABLED
202 AXIS_ANCESTOR_OR_SELF,
206 AXIS_DESCENDANT_OR_SELF,
208 AXIS_FOLLOWING_SIBLING,
212 AXIS_PRECEDING_SIBLING,
227 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
228 NODE_TYPE_TEXT = XML_TEXT_NODE,
229 NODE_TYPE_PI = XML_PI_NODE
233 typedef struct _xmlXPathStepOp xmlXPathStepOp;
234 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
235 struct _xmlXPathStepOp {
248 struct _xmlXPathCompExpr {
251 xmlXPathStepOp *steps; /* ops for computation */
254 #ifdef DEBUG_EVAL_COUNTS
260 /************************************************************************
262 * Parser Type functions *
264 ************************************************************************/
267 * xmlXPathNewCompExpr:
269 * Create a new Xpath component
271 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
273 static xmlXPathCompExprPtr
274 xmlXPathNewCompExpr(void) {
275 xmlXPathCompExprPtr cur;
277 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
279 xmlGenericError(xmlGenericErrorContext,
280 "xmlXPathNewCompExpr : malloc failed\n");
283 memset(cur, 0, sizeof(xmlXPathCompExpr));
286 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
287 sizeof(xmlXPathStepOp));
288 if (cur->steps == NULL) {
289 xmlGenericError(xmlGenericErrorContext,
290 "xmlXPathNewCompExpr : malloc failed\n");
294 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
296 #ifdef DEBUG_EVAL_COUNTS
303 * xmlXPathFreeCompExpr:
304 * @comp: an XPATH comp
306 * Free up the memory allocated by @comp
309 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
311 xmlXPathStepOpPtr op;
316 for (i = 0; i < comp->nbStep; i++) {
317 op = &comp->steps[i];
318 if (op->value4 != NULL) {
319 if (op->op == XPATH_OP_VALUE)
320 xmlXPathFreeObject(op->value4);
324 if (op->value5 != NULL)
327 if (comp->steps != NULL) {
328 xmlFree(comp->steps);
330 #ifdef DEBUG_EVAL_COUNTS
331 if (comp->string != NULL) {
332 xmlFree(comp->string);
335 if (comp->expr != NULL) {
343 * xmlXPathCompExprAdd:
344 * @comp: the compiled expression
345 * @ch1: first child index
346 * @ch2: second child index
348 * @value: the first int value
349 * @value2: the second int value
350 * @value3: the third int value
351 * @value4: the first string value
352 * @value5: the second string value
354 * Add an step to an XPath Compiled Expression
356 * Returns -1 in case of failure, the index otherwise
359 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
360 xmlXPathOp op, int value,
361 int value2, int value3, void *value4, void *value5) {
362 if (comp->nbStep >= comp->maxStep) {
363 xmlXPathStepOp *real;
366 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
367 comp->maxStep * sizeof(xmlXPathStepOp));
370 xmlGenericError(xmlGenericErrorContext,
371 "xmlXPathCompExprAdd : realloc failed\n");
376 comp->last = comp->nbStep;
377 comp->steps[comp->nbStep].ch1 = ch1;
378 comp->steps[comp->nbStep].ch2 = ch2;
379 comp->steps[comp->nbStep].op = op;
380 comp->steps[comp->nbStep].value = value;
381 comp->steps[comp->nbStep].value2 = value2;
382 comp->steps[comp->nbStep].value3 = value3;
383 comp->steps[comp->nbStep].value4 = value4;
384 comp->steps[comp->nbStep].value5 = value5;
385 comp->steps[comp->nbStep].cache = NULL;
386 return(comp->nbStep++);
391 * @comp: the compiled expression
392 * @op: operation index
394 * Swaps 2 operations in the compiled expression
397 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
400 #ifndef LIBXML_THREAD_ENABLED
402 * Since this manipulates possibly shared variables, this is
403 * disable if one detects that the library is used in a multithreaded
406 if (xmlXPathDisableOptimizer)
415 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
416 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
417 (op), (val), (val2), (val3), (val4), (val5))
418 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
419 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
420 (op), (val), (val2), (val3), (val4), (val5))
422 #define PUSH_LEAVE_EXPR(op, val, val2) \
423 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
425 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
426 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
428 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
429 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), (val), (val2), 0 ,NULL ,NULL)
431 /************************************************************************
433 * Debugging related functions *
435 ************************************************************************/
438 xmlGenericError(xmlGenericErrorContext, \
439 "Unimplemented block at %s:%d\n", \
443 xmlGenericError(xmlGenericErrorContext, \
444 "Internal error at %s:%d\n", \
447 #ifdef LIBXML_DEBUG_ENABLED
449 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
453 for (i = 0;((i < depth) && (i < 25));i++)
454 shift[2 * i] = shift[2 * i + 1] = ' ';
455 shift[2 * i] = shift[2 * i + 1] = 0;
457 fprintf(output, shift);
458 fprintf(output, "Node is NULL !\n");
463 if ((cur->type == XML_DOCUMENT_NODE) ||
464 (cur->type == XML_HTML_DOCUMENT_NODE)) {
465 fprintf(output, shift);
466 fprintf(output, " /\n");
467 } else if (cur->type == XML_ATTRIBUTE_NODE)
468 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
470 xmlDebugDumpOneNode(output, cur, depth);
473 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
478 for (i = 0;((i < depth) && (i < 25));i++)
479 shift[2 * i] = shift[2 * i + 1] = ' ';
480 shift[2 * i] = shift[2 * i + 1] = 0;
482 fprintf(output, shift);
483 fprintf(output, "Node is NULL !\n");
488 while (cur != NULL) {
491 xmlDebugDumpOneNode(output, tmp, depth);
496 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
500 for (i = 0;((i < depth) && (i < 25));i++)
501 shift[2 * i] = shift[2 * i + 1] = ' ';
502 shift[2 * i] = shift[2 * i + 1] = 0;
505 fprintf(output, shift);
506 fprintf(output, "NodeSet is NULL !\n");
512 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
513 for (i = 0;i < cur->nodeNr;i++) {
514 fprintf(output, shift);
515 fprintf(output, "%d", i + 1);
516 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
522 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
526 for (i = 0;((i < depth) && (i < 25));i++)
527 shift[2 * i] = shift[2 * i + 1] = ' ';
528 shift[2 * i] = shift[2 * i + 1] = 0;
530 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
531 fprintf(output, shift);
532 fprintf(output, "Value Tree is NULL !\n");
537 fprintf(output, shift);
538 fprintf(output, "%d", i + 1);
539 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
541 #if defined(LIBXML_XPTR_ENABLED)
543 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
547 for (i = 0;((i < depth) && (i < 25));i++)
548 shift[2 * i] = shift[2 * i + 1] = ' ';
549 shift[2 * i] = shift[2 * i + 1] = 0;
552 fprintf(output, shift);
553 fprintf(output, "LocationSet is NULL !\n");
558 for (i = 0;i < cur->locNr;i++) {
559 fprintf(output, shift);
560 fprintf(output, "%d : ", i + 1);
561 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
564 #endif /* LIBXML_XPTR_ENABLED */
567 * xmlXPathDebugDumpObject:
568 * @output: the FILE * to dump the output
569 * @cur: the object to inspect
570 * @depth: indentation level
572 * Dump the content of the object for debugging purposes
575 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
579 for (i = 0;((i < depth) && (i < 25));i++)
580 shift[2 * i] = shift[2 * i + 1] = ' ';
581 shift[2 * i] = shift[2 * i + 1] = 0;
583 fprintf(output, shift);
586 fprintf(output, "Object is empty (NULL)\n");
590 case XPATH_UNDEFINED:
591 fprintf(output, "Object is uninitialized\n");
594 fprintf(output, "Object is a Node Set :\n");
595 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
597 case XPATH_XSLT_TREE:
598 fprintf(output, "Object is an XSLT value tree :\n");
599 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
602 fprintf(output, "Object is a Boolean : ");
603 if (cur->boolval) fprintf(output, "true\n");
604 else fprintf(output, "false\n");
607 switch (xmlXPathIsInf(cur->floatval)) {
609 fprintf(output, "Object is a number : Infinity\n");
612 fprintf(output, "Object is a number : -Infinity\n");
615 if (xmlXPathIsNaN(cur->floatval)) {
616 fprintf(output, "Object is a number : NaN\n");
617 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
618 fprintf(output, "Object is a number : 0\n");
620 fprintf(output, "Object is a number : %0g\n", cur->floatval);
625 fprintf(output, "Object is a string : ");
626 xmlDebugDumpString(output, cur->stringval);
627 fprintf(output, "\n");
630 fprintf(output, "Object is a point : index %d in node", cur->index);
631 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
632 fprintf(output, "\n");
635 if ((cur->user2 == NULL) ||
636 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
637 fprintf(output, "Object is a collapsed range :\n");
638 fprintf(output, shift);
640 fprintf(output, "index %d in ", cur->index);
641 fprintf(output, "node\n");
642 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
645 fprintf(output, "Object is a range :\n");
646 fprintf(output, shift);
647 fprintf(output, "From ");
649 fprintf(output, "index %d in ", cur->index);
650 fprintf(output, "node\n");
651 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
653 fprintf(output, shift);
654 fprintf(output, "To ");
655 if (cur->index2 >= 0)
656 fprintf(output, "index %d in ", cur->index2);
657 fprintf(output, "node\n");
658 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
660 fprintf(output, "\n");
663 case XPATH_LOCATIONSET:
664 #if defined(LIBXML_XPTR_ENABLED)
665 fprintf(output, "Object is a Location Set:\n");
666 xmlXPathDebugDumpLocationSet(output,
667 (xmlLocationSetPtr) cur->user, depth);
671 fprintf(output, "Object is user defined\n");
677 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
678 xmlXPathStepOpPtr op, int depth) {
682 for (i = 0;((i < depth) && (i < 25));i++)
683 shift[2 * i] = shift[2 * i + 1] = ' ';
684 shift[2 * i] = shift[2 * i + 1] = 0;
686 fprintf(output, shift);
688 fprintf(output, "Step is NULL\n");
693 fprintf(output, "END"); break;
695 fprintf(output, "AND"); break;
697 fprintf(output, "OR"); break;
700 fprintf(output, "EQUAL =");
702 fprintf(output, "EQUAL !=");
706 fprintf(output, "CMP <");
708 fprintf(output, "CMP >");
710 fprintf(output, "=");
714 fprintf(output, "PLUS -");
715 else if (op->value == 1)
716 fprintf(output, "PLUS +");
717 else if (op->value == 2)
718 fprintf(output, "PLUS unary -");
719 else if (op->value == 3)
720 fprintf(output, "PLUS unary - -");
724 fprintf(output, "MULT *");
725 else if (op->value == 1)
726 fprintf(output, "MULT div");
728 fprintf(output, "MULT mod");
731 fprintf(output, "UNION"); break;
733 fprintf(output, "ROOT"); break;
735 fprintf(output, "NODE"); break;
737 fprintf(output, "RESET"); break;
739 fprintf(output, "SORT"); break;
740 case XPATH_OP_COLLECT: {
741 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
742 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
743 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
744 const xmlChar *prefix = op->value4;
745 const xmlChar *name = op->value5;
747 fprintf(output, "COLLECT ");
750 fprintf(output, " 'ancestors' "); break;
751 case AXIS_ANCESTOR_OR_SELF:
752 fprintf(output, " 'ancestors-or-self' "); break;
754 fprintf(output, " 'attributes' "); break;
756 fprintf(output, " 'child' "); break;
757 case AXIS_DESCENDANT:
758 fprintf(output, " 'descendant' "); break;
759 case AXIS_DESCENDANT_OR_SELF:
760 fprintf(output, " 'descendant-or-self' "); break;
762 fprintf(output, " 'following' "); break;
763 case AXIS_FOLLOWING_SIBLING:
764 fprintf(output, " 'following-siblings' "); break;
766 fprintf(output, " 'namespace' "); break;
768 fprintf(output, " 'parent' "); break;
770 fprintf(output, " 'preceding' "); break;
771 case AXIS_PRECEDING_SIBLING:
772 fprintf(output, " 'preceding-sibling' "); break;
774 fprintf(output, " 'self' "); break;
778 fprintf(output, "'none' "); break;
780 fprintf(output, "'type' "); break;
782 fprintf(output, "'PI' "); break;
784 fprintf(output, "'all' "); break;
786 fprintf(output, "'namespace' "); break;
788 fprintf(output, "'name' "); break;
792 fprintf(output, "'node' "); break;
793 case NODE_TYPE_COMMENT:
794 fprintf(output, "'comment' "); break;
796 fprintf(output, "'text' "); break;
798 fprintf(output, "'PI' "); break;
801 fprintf(output, "%s:", prefix);
803 fprintf(output, "%s", (const char *) name);
807 case XPATH_OP_VALUE: {
808 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
810 fprintf(output, "ELEM ");
811 xmlXPathDebugDumpObject(output, object, 0);
814 case XPATH_OP_VARIABLE: {
815 const xmlChar *prefix = op->value5;
816 const xmlChar *name = op->value4;
819 fprintf(output, "VARIABLE %s:%s", prefix, name);
821 fprintf(output, "VARIABLE %s", name);
824 case XPATH_OP_FUNCTION: {
825 int nbargs = op->value;
826 const xmlChar *prefix = op->value5;
827 const xmlChar *name = op->value4;
830 fprintf(output, "FUNCTION %s:%s(%d args)",
831 prefix, name, nbargs);
833 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
836 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
837 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
838 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
839 #ifdef LIBXML_XPTR_ENABLED
840 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
843 fprintf(output, "UNKNOWN %d\n", op->op); return;
845 fprintf(output, "\n");
848 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
850 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
854 * xmlXPathDebugDumpCompExpr:
855 * @output: the FILE * for the output
856 * @comp: the precompiled XPath expression
857 * @depth: the indentation level.
859 * Dumps the tree of the compiled XPath expression.
862 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
867 for (i = 0;((i < depth) && (i < 25));i++)
868 shift[2 * i] = shift[2 * i + 1] = ' ';
869 shift[2 * i] = shift[2 * i + 1] = 0;
871 fprintf(output, shift);
874 fprintf(output, "Compiled Expression is NULL\n");
877 fprintf(output, "Compiled Expression : %d elements\n",
880 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
882 #endif /* LIBXML_DEBUG_ENABLED */
884 /************************************************************************
886 * Parser stacks related functions and macros *
888 ************************************************************************/
892 * @ctxt: an XPath evaluation context
894 * Pops the top XPath object from the value stack
896 * Returns the XPath object just removed
898 extern xmlXPathObjectPtr
899 valuePop(xmlXPathParserContextPtr ctxt)
901 xmlXPathObjectPtr ret;
903 if (ctxt->valueNr <= 0)
906 if (ctxt->valueNr > 0)
907 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
910 ret = ctxt->valueTab[ctxt->valueNr];
911 ctxt->valueTab[ctxt->valueNr] = 0;
916 * @ctxt: an XPath evaluation context
917 * @value: the XPath object
919 * Pushes a new XPath object on top of the value stack
921 * returns the number of items on the value stack
924 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
926 if (ctxt->valueNr >= ctxt->valueMax) {
929 (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
931 sizeof(ctxt->valueTab[0]));
932 if (ctxt->valueTab == NULL) {
933 xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
937 ctxt->valueTab[ctxt->valueNr] = value;
939 return (ctxt->valueNr++);
943 * xmlXPathPopBoolean:
944 * @ctxt: an XPath parser context
946 * Pops a boolean from the stack, handling conversion if needed.
947 * Check error with #xmlXPathCheckError.
949 * Returns the boolean
952 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
953 xmlXPathObjectPtr obj;
956 obj = valuePop(ctxt);
958 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
961 ret = xmlXPathCastToBoolean(obj);
962 xmlXPathFreeObject(obj);
968 * @ctxt: an XPath parser context
970 * Pops a number from the stack, handling conversion if needed.
971 * Check error with #xmlXPathCheckError.
976 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
977 xmlXPathObjectPtr obj;
980 obj = valuePop(ctxt);
982 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
985 ret = xmlXPathCastToNumber(obj);
986 xmlXPathFreeObject(obj);
992 * @ctxt: an XPath parser context
994 * Pops a string from the stack, handling conversion if needed.
995 * Check error with #xmlXPathCheckError.
1000 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
1001 xmlXPathObjectPtr obj;
1004 obj = valuePop(ctxt);
1006 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1009 ret = xmlXPathCastToString(obj);
1010 /* TODO: needs refactoring somewhere else */
1011 if (obj->stringval == ret)
1012 obj->stringval = NULL;
1013 xmlXPathFreeObject(obj);
1018 * xmlXPathPopNodeSet:
1019 * @ctxt: an XPath parser context
1021 * Pops a node-set from the stack, handling conversion if needed.
1022 * Check error with #xmlXPathCheckError.
1024 * Returns the node-set
1027 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
1028 xmlXPathObjectPtr obj;
1031 if (ctxt->value == NULL) {
1032 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1035 if (!xmlXPathStackIsNodeSet(ctxt)) {
1036 xmlXPathSetTypeError(ctxt);
1039 obj = valuePop(ctxt);
1040 ret = obj->nodesetval;
1041 /* to fix memory leak of not clearing obj->user */
1042 if (obj->boolval && obj->user != NULL)
1043 xmlFreeNodeList((xmlNodePtr) obj->user);
1044 xmlXPathFreeNodeSetList(obj);
1049 * xmlXPathPopExternal:
1050 * @ctxt: an XPath parser context
1052 * Pops an external object from the stack, handling conversion if needed.
1053 * Check error with #xmlXPathCheckError.
1055 * Returns the object
1058 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
1059 xmlXPathObjectPtr obj;
1062 if (ctxt->value == NULL) {
1063 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
1066 if (ctxt->value->type != XPATH_USERS) {
1067 xmlXPathSetTypeError(ctxt);
1070 obj = valuePop(ctxt);
1072 xmlXPathFreeObject(obj);
1077 * Macros for accessing the content. Those should be used only by the parser,
1080 * Dirty macros, i.e. one need to make assumption on the context to use them
1082 * CUR_PTR return the current pointer to the xmlChar to be parsed.
1083 * CUR returns the current xmlChar value, i.e. a 8 bit value
1084 * in ISO-Latin or UTF-8.
1085 * This should be used internally by the parser
1086 * only to compare to ASCII values otherwise it would break when
1087 * running with UTF-8 encoding.
1088 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
1089 * to compare on ASCII based substring.
1090 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
1091 * strings within the parser.
1092 * CURRENT Returns the current char value, with the full decoding of
1093 * UTF-8 if we are using this mode. It returns an int.
1094 * NEXT Skip to the next character, this does the proper decoding
1095 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
1096 * It returns the pointer to the current xmlChar.
1099 #define CUR (*ctxt->cur)
1100 #define SKIP(val) ctxt->cur += (val)
1101 #define NXT(val) ctxt->cur[(val)]
1102 #define CUR_PTR ctxt->cur
1103 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
1105 #define COPY_BUF(l,b,i,v) \
1106 if (l == 1) b[i++] = (xmlChar) v; \
1107 else i += xmlCopyChar(l,&b[i],v)
1109 #define NEXTL(l) ctxt->cur += l
1111 #define SKIP_BLANKS \
1112 while (IS_BLANK(*(ctxt->cur))) NEXT
1114 #define CURRENT (*ctxt->cur)
1115 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
1122 #define DBL_EPSILON 1E-9
1125 #define UPPER_DOUBLE 1E9
1126 #define LOWER_DOUBLE 1E-5
1128 #define INTEGER_DIGITS DBL_DIG
1129 #define FRACTION_DIGITS (DBL_DIG + 1)
1130 #define EXPONENT_DIGITS (3 + 2)
1133 * xmlXPathFormatNumber:
1134 * @number: number to format
1135 * @buffer: output buffer
1136 * @buffersize: size of output buffer
1138 * Convert the number into a string representation.
1141 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
1143 switch (xmlXPathIsInf(number)) {
1145 if (buffersize > (int)sizeof("Infinity"))
1146 snprintf(buffer, buffersize, "Infinity");
1149 if (buffersize > (int)sizeof("-Infinity"))
1150 snprintf(buffer, buffersize, "-Infinity");
1153 if (xmlXPathIsNaN(number)) {
1154 if (buffersize > (int)sizeof("NaN"))
1155 snprintf(buffer, buffersize, "NaN");
1156 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
1157 snprintf(buffer, buffersize, "0");
1158 } else if (number == ((int) number)) {
1161 int res, value = (int) number;
1172 while (value != 0) {
1178 while ((cur >= &work[0]) && (ptr - buffer < buffersize)) {
1182 if (ptr - buffer < buffersize) {
1184 } else if (buffersize > 0) {
1189 /* 3 is sign, decimal point, and terminating zero */
1190 char work[DBL_DIG + EXPONENT_DIGITS + 3];
1191 int integer_place, fraction_place;
1193 char *after_fraction;
1194 double absolute_value;
1197 absolute_value = fabs(number);
1200 * First choose format - scientific or regular floating point.
1201 * In either case, result is in work, and after_fraction points
1202 * just past the fractional part.
1204 if ( ((absolute_value > UPPER_DOUBLE) ||
1205 (absolute_value < LOWER_DOUBLE)) &&
1206 (absolute_value != 0.0) ) {
1207 /* Use scientific notation */
1208 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
1209 fraction_place = DBL_DIG - 1;
1210 snprintf(work, sizeof(work),"%*.*e",
1211 integer_place, fraction_place, number);
1212 after_fraction = strchr(work + DBL_DIG, 'e');
1215 /* Use regular notation */
1216 if (absolute_value > 0.0)
1217 integer_place = 1 + (int)log10(absolute_value);
1220 fraction_place = (integer_place > 0)
1221 ? DBL_DIG - integer_place
1223 size = snprintf(work, sizeof(work), "%0.*f",
1224 fraction_place, number);
1225 after_fraction = work + size;
1228 /* Remove fractional trailing zeroes */
1229 ptr = after_fraction;
1230 while (*(--ptr) == '0')
1234 strcpy(ptr, after_fraction);
1236 /* Finally copy result back to caller */
1237 size = strlen(work) + 1;
1238 if (size > buffersize) {
1239 work[buffersize - 1] = 0;
1242 memcpy(buffer, work, size);
1248 /************************************************************************
1250 * Error handling routines *
1252 ************************************************************************/
1255 static const char *xmlXPathErrorMessages[] = {
1258 "Unfinished literal",
1260 "Expected $ for variable reference",
1261 "Undefined variable",
1262 "Invalid predicate",
1263 "Invalid expression",
1264 "Missing closing curly brace",
1265 "Unregistered function",
1268 "Invalid number of arguments",
1269 "Invalid context size",
1270 "Invalid context position",
1271 "Memory allocation error",
1274 "Sub resource error",
1275 "Undefined namespace prefix",
1277 "Char out of XML range"
1282 * @ctxt: the XPath Parser context
1283 * @file: the file name
1284 * @line: the line number
1285 * @no: the error number
1287 * Formats an error message.
1290 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
1291 int line ATTRIBUTE_UNUSED, int no) {
1294 const xmlChar *base;
1298 if ((cur == NULL) || (base == NULL)) {
1299 if ((ctxt->comp != NULL) && (ctxt->comp->expr != NULL)) {
1300 xmlGenericError(xmlGenericErrorContext,
1301 "XPath error %s in %s\n", xmlXPathErrorMessages[no],
1304 xmlGenericError(xmlGenericErrorContext,
1305 "XPath error %s\n", xmlXPathErrorMessages[no]);
1310 xmlGenericError(xmlGenericErrorContext,
1311 "XPath error %s\n", xmlXPathErrorMessages[no]);
1313 while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
1317 while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
1319 if ((*cur == '\n') || (*cur == '\r')) cur++;
1322 while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
1323 xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
1326 xmlGenericError(xmlGenericErrorContext, "\n");
1328 while ((*cur == '\n') || (*cur == '\r'))
1331 while ((cur != base) && (n++ < 80)) {
1332 xmlGenericError(xmlGenericErrorContext, " ");
1335 xmlGenericError(xmlGenericErrorContext,"^\n");
1339 /************************************************************************
1341 * Routines to handle NodeSets *
1343 ************************************************************************/
1346 * xmlXPathOrderDocElems:
1347 * @doc: an input document
1349 * Call this routine to speed up XPath computation on static documents.
1350 * This stamps all the element nodes with the document order
1351 * Like for line information, the order is kept in the element->content
1352 * field, the value stored is actually - the node number (startting at -1)
1353 * to be able to differenciate from line numbers.
1355 * Returns the number of element found in the document or -1 in case
1359 xmlXPathOrderDocElems(xmlDocPtr doc) {
1365 cur = doc->children;
1366 while (cur != NULL) {
1367 if (cur->type == XML_ELEMENT_NODE) {
1368 cur->content = (void *) (-(++count));
1369 if (cur->children != NULL) {
1370 cur = cur->children;
1374 if (cur->next != NULL) {
1382 if (cur == (xmlNodePtr) doc) {
1386 if (cur->next != NULL) {
1390 } while (cur != NULL);
1397 * @node1: the first node
1398 * @node2: the second node
1400 * Compare two nodes w.r.t document order
1402 * Returns -2 in case of error 1 if first point < second point, 0 if
1403 * that's the same node, -1 otherwise
1406 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
1408 int attr1 = 0, attr2 = 0;
1409 xmlNodePtr cur, root;
1411 if ((node1 == NULL) || (node2 == NULL))
1414 * a couple of optimizations which will avoid computations in most cases
1416 if (node1->type == XML_ATTRIBUTE_NODE) {
1418 node1 = node1->parent;
1420 if (node2->type == XML_ATTRIBUTE_NODE) {
1422 node2 = node2->parent;
1424 if (node1 == node2) {
1431 if ((node1->type == XML_NAMESPACE_DECL) ||
1432 (node2->type == XML_NAMESPACE_DECL))
1434 if (node1 == node2->prev)
1436 if (node1 == node2->next)
1440 * Speedup using document order if availble.
1442 if ((node1->type == XML_ELEMENT_NODE) &&
1443 (node2->type == XML_ELEMENT_NODE) &&
1444 (0 > (long) node1->content) &&
1445 (0 > (long) node2->content) &&
1446 (node1->doc == node2->doc)) {
1449 l1 = -((long) node1->content);
1450 l2 = -((long) node2->content);
1458 * compute depth to root
1460 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
1466 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
1472 * Distinct document (or distinct entities :-( ) case.
1478 * get the nearest common ancestor.
1480 while (depth1 > depth2) {
1482 node1 = node1->parent;
1484 while (depth2 > depth1) {
1486 node2 = node2->parent;
1488 while (node1->parent != node2->parent) {
1489 node1 = node1->parent;
1490 node2 = node2->parent;
1491 /* should not happen but just in case ... */
1492 if ((node1 == NULL) || (node2 == NULL))
1498 if (node1 == node2->next)
1500 for (cur = node1->next;cur != NULL;cur = cur->next)
1503 return(-1); /* assume there is no sibling list corruption */
1507 * xmlXPathNodeSetSort:
1508 * @set: the node set
1510 * Sort the node set in document order
1513 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
1514 int i, j, incr, len;
1520 /* Use Shell's sort to sort the node-set */
1522 for (incr = len / 2; incr > 0; incr /= 2) {
1523 for (i = incr; i < len; i++) {
1526 if (xmlXPathCmpNodes(set->nodeTab[j],
1527 set->nodeTab[j + incr]) == -1) {
1528 tmp = set->nodeTab[j];
1529 set->nodeTab[j] = set->nodeTab[j + incr];
1530 set->nodeTab[j + incr] = tmp;
1539 #define XML_NODESET_DEFAULT 10
1541 * xmlXPathNodeSetDupNs:
1542 * @node: the parent node of the namespace XPath node
1543 * @ns: the libxml namespace declaration node.
1545 * Namespace node in libxml don't match the XPath semantic. In a node set
1546 * the namespace nodes are duplicated and the next pointer is set to the
1547 * parent node in the XPath semantic.
1549 * Returns the newly created object.
1552 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
1555 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1557 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
1558 return((xmlNodePtr) ns);
1561 * Allocate a new Namespace and fill the fields.
1563 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
1565 xmlGenericError(xmlGenericErrorContext,
1566 "xmlXPathNodeSetDupNs : malloc failed\n");
1569 memset(cur, 0, sizeof(xmlNs));
1570 cur->type = XML_NAMESPACE_DECL;
1571 if (ns->href != NULL)
1572 cur->href = xmlStrdup(ns->href);
1573 if (ns->prefix != NULL)
1574 cur->prefix = xmlStrdup(ns->prefix);
1575 cur->next = (xmlNsPtr) node;
1576 return((xmlNodePtr) cur);
1580 * xmlXPathNodeSetFreeNs:
1581 * @ns: the XPath namespace node found in a nodeset.
1583 * Namespace node in libxml don't match the XPath semantic. In a node set
1584 * the namespace nodes are duplicated and the next pointer is set to the
1585 * parent node in the XPath semantic. Check if such a node need to be freed
1588 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
1589 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
1592 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
1593 if (ns->href != NULL)
1594 xmlFree((xmlChar *)ns->href);
1595 if (ns->prefix != NULL)
1596 xmlFree((xmlChar *)ns->prefix);
1602 * xmlXPathNodeSetCreate:
1603 * @val: an initial xmlNodePtr, or NULL
1605 * Create a new xmlNodeSetPtr of type double and of value @val
1607 * Returns the newly created object.
1610 xmlXPathNodeSetCreate(xmlNodePtr val) {
1613 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
1615 xmlGenericError(xmlGenericErrorContext,
1616 "xmlXPathNodeSetCreate: out of memory\n");
1619 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
1621 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1622 sizeof(xmlNodePtr));
1623 if (ret->nodeTab == NULL) {
1624 xmlGenericError(xmlGenericErrorContext,
1625 "xmlXPathNodeSetCreate: out of memory\n");
1628 memset(ret->nodeTab, 0 ,
1629 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1630 ret->nodeMax = XML_NODESET_DEFAULT;
1631 if (val->type == XML_NAMESPACE_DECL) {
1632 xmlNsPtr ns = (xmlNsPtr) val;
1634 ret->nodeTab[ret->nodeNr++] =
1635 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1637 ret->nodeTab[ret->nodeNr++] = val;
1643 * xmlXPathNodeSetContains:
1644 * @cur: the node-set
1647 * checks whether @cur contains @val
1649 * Returns true (1) if @cur contains @val, false (0) otherwise
1652 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
1655 if (val->type == XML_NAMESPACE_DECL) {
1656 for (i = 0; i < cur->nodeNr; i++) {
1657 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1660 ns1 = (xmlNsPtr) val;
1661 ns2 = (xmlNsPtr) cur->nodeTab[i];
1664 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
1665 (xmlStrEqual(ns1->prefix, ns2->prefix)))
1670 for (i = 0; i < cur->nodeNr; i++) {
1671 if (cur->nodeTab[i] == val)
1679 * xmlXPathNodeSetAddNs:
1680 * @cur: the initial node set
1681 * @node: the hosting node
1682 * @ns: a the namespace node
1684 * add a new namespace node to an existing NodeSet
1687 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
1690 if ((ns == NULL) || (node == NULL) || (ns->type != XML_NAMESPACE_DECL) ||
1691 (node->type != XML_ELEMENT_NODE))
1694 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1696 * check against doublons
1698 for (i = 0;i < cur->nodeNr;i++) {
1699 if ((cur->nodeTab[i] != NULL) &&
1700 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
1701 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
1702 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
1707 * grow the nodeTab if needed
1709 if (cur->nodeMax == 0) {
1710 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1711 sizeof(xmlNodePtr));
1712 if (cur->nodeTab == NULL) {
1713 xmlGenericError(xmlGenericErrorContext,
1714 "xmlXPathNodeSetAdd: out of memory\n");
1717 memset(cur->nodeTab, 0 ,
1718 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1719 cur->nodeMax = XML_NODESET_DEFAULT;
1720 } else if (cur->nodeNr == cur->nodeMax) {
1724 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1725 sizeof(xmlNodePtr));
1727 xmlGenericError(xmlGenericErrorContext,
1728 "xmlXPathNodeSetAdd: out of memory\n");
1731 cur->nodeTab = temp;
1733 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
1737 * xmlXPathNodeSetAdd:
1738 * @cur: the initial node set
1739 * @val: a new xmlNodePtr
1741 * add a new xmlNodePtr to an existing NodeSet
1744 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
1747 if (val == NULL) return;
1750 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1751 return; /* an XSLT fake node */
1754 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1756 * check against doublons
1758 for (i = 0;i < cur->nodeNr;i++)
1759 if (cur->nodeTab[i] == val) return;
1762 * grow the nodeTab if needed
1764 if (cur->nodeMax == 0) {
1765 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1766 sizeof(xmlNodePtr));
1767 if (cur->nodeTab == NULL) {
1768 xmlGenericError(xmlGenericErrorContext,
1769 "xmlXPathNodeSetAdd: out of memory\n");
1772 memset(cur->nodeTab, 0 ,
1773 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1774 cur->nodeMax = XML_NODESET_DEFAULT;
1775 } else if (cur->nodeNr == cur->nodeMax) {
1779 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1780 sizeof(xmlNodePtr));
1782 xmlGenericError(xmlGenericErrorContext,
1783 "xmlXPathNodeSetAdd: out of memory\n");
1786 cur->nodeTab = temp;
1788 if (val->type == XML_NAMESPACE_DECL) {
1789 xmlNsPtr ns = (xmlNsPtr) val;
1791 cur->nodeTab[cur->nodeNr++] =
1792 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1794 cur->nodeTab[cur->nodeNr++] = val;
1798 * xmlXPathNodeSetAddUnique:
1799 * @cur: the initial node set
1800 * @val: a new xmlNodePtr
1802 * add a new xmlNodePtr to an existing NodeSet, optimized version
1803 * when we are sure the node is not already in the set.
1806 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
1807 if (val == NULL) return;
1810 if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
1811 return; /* an XSLT fake node */
1814 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1816 * grow the nodeTab if needed
1818 if (cur->nodeMax == 0) {
1819 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1820 sizeof(xmlNodePtr));
1821 if (cur->nodeTab == NULL) {
1822 xmlGenericError(xmlGenericErrorContext,
1823 "xmlXPathNodeSetAddUnique: out of memory\n");
1826 memset(cur->nodeTab, 0 ,
1827 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1828 cur->nodeMax = XML_NODESET_DEFAULT;
1829 } else if (cur->nodeNr == cur->nodeMax) {
1833 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
1834 sizeof(xmlNodePtr));
1836 xmlGenericError(xmlGenericErrorContext,
1837 "xmlXPathNodeSetAddUnique: out of memory\n");
1840 cur->nodeTab = temp;
1842 if (val->type == XML_NAMESPACE_DECL) {
1843 xmlNsPtr ns = (xmlNsPtr) val;
1845 cur->nodeTab[cur->nodeNr++] =
1846 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1848 cur->nodeTab[cur->nodeNr++] = val;
1852 * xmlXPathNodeSetMerge:
1853 * @val1: the first NodeSet or NULL
1854 * @val2: the second NodeSet
1856 * Merges two nodesets, all nodes from @val2 are added to @val1
1857 * if @val1 is NULL, a new set is created and copied from @val2
1859 * Returns @val1 once extended or NULL in case of error.
1862 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1863 int i, j, initNr, skip;
1865 if (val2 == NULL) return(val1);
1867 val1 = xmlXPathNodeSetCreate(NULL);
1870 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1871 initNr = val1->nodeNr;
1873 for (i = 0;i < val2->nodeNr;i++) {
1875 * check against doublons
1878 for (j = 0; j < initNr; j++) {
1879 if (val1->nodeTab[j] == val2->nodeTab[i]) {
1882 } else if ((val1->nodeTab[j]->type == XML_NAMESPACE_DECL) &&
1883 (val2->nodeTab[i]->type == XML_NAMESPACE_DECL)) {
1885 ns1 = (xmlNsPtr) val1->nodeTab[j];
1886 ns2 = (xmlNsPtr) val2->nodeTab[i];
1887 if ((ns1->next == ns2->next) &&
1888 (xmlStrEqual(ns1->prefix, ns2->prefix))) {
1898 * grow the nodeTab if needed
1900 if (val1->nodeMax == 0) {
1901 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1902 sizeof(xmlNodePtr));
1903 if (val1->nodeTab == NULL) {
1904 xmlGenericError(xmlGenericErrorContext,
1905 "xmlXPathNodeSetMerge: out of memory\n");
1908 memset(val1->nodeTab, 0 ,
1909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1910 val1->nodeMax = XML_NODESET_DEFAULT;
1911 } else if (val1->nodeNr == val1->nodeMax) {
1915 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1916 sizeof(xmlNodePtr));
1918 xmlGenericError(xmlGenericErrorContext,
1919 "xmlXPathNodeSetMerge: out of memory\n");
1922 val1->nodeTab = temp;
1924 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1925 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1927 val1->nodeTab[val1->nodeNr++] =
1928 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1930 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1937 * xmlXPathNodeSetMergeUnique:
1938 * @val1: the first NodeSet or NULL
1939 * @val2: the second NodeSet
1941 * Merges two nodesets, all nodes from @val2 are added to @val1
1942 * if @val1 is NULL, a new set is created and copied from @val2
1944 * Returns @val1 once extended or NULL in case of error.
1946 static xmlNodeSetPtr
1947 xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
1950 if (val2 == NULL) return(val1);
1952 val1 = xmlXPathNodeSetCreate(NULL);
1955 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
1957 for (i = 0;i < val2->nodeNr;i++) {
1959 * grow the nodeTab if needed
1961 if (val1->nodeMax == 0) {
1962 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
1963 sizeof(xmlNodePtr));
1964 if (val1->nodeTab == NULL) {
1965 xmlGenericError(xmlGenericErrorContext,
1966 "xmlXPathNodeSetMerge: out of memory\n");
1969 memset(val1->nodeTab, 0 ,
1970 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
1971 val1->nodeMax = XML_NODESET_DEFAULT;
1972 } else if (val1->nodeNr == val1->nodeMax) {
1976 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
1977 sizeof(xmlNodePtr));
1979 xmlGenericError(xmlGenericErrorContext,
1980 "xmlXPathNodeSetMerge: out of memory\n");
1983 val1->nodeTab = temp;
1985 if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
1986 xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
1988 val1->nodeTab[val1->nodeNr++] =
1989 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
1991 val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
1998 * xmlXPathNodeSetDel:
1999 * @cur: the initial node set
2000 * @val: an xmlNodePtr
2002 * Removes an xmlNodePtr from an existing NodeSet
2005 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
2008 if (cur == NULL) return;
2009 if (val == NULL) return;
2012 * check against doublons
2014 for (i = 0;i < cur->nodeNr;i++)
2015 if (cur->nodeTab[i] == val) break;
2017 if (i >= cur->nodeNr) {
2019 xmlGenericError(xmlGenericErrorContext,
2020 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
2025 if ((cur->nodeTab[i] != NULL) &&
2026 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
2027 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
2029 for (;i < cur->nodeNr;i++)
2030 cur->nodeTab[i] = cur->nodeTab[i + 1];
2031 cur->nodeTab[cur->nodeNr] = NULL;
2035 * xmlXPathNodeSetRemove:
2036 * @cur: the initial node set
2037 * @val: the index to remove
2039 * Removes an entry from an existing NodeSet list.
2042 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
2043 if (cur == NULL) return;
2044 if (val >= cur->nodeNr) return;
2045 if ((cur->nodeTab[val] != NULL) &&
2046 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
2047 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
2049 for (;val < cur->nodeNr;val++)
2050 cur->nodeTab[val] = cur->nodeTab[val + 1];
2051 cur->nodeTab[cur->nodeNr] = NULL;
2055 * xmlXPathFreeNodeSet:
2056 * @obj: the xmlNodeSetPtr to free
2058 * Free the NodeSet compound (not the actual nodes !).
2061 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
2062 if (obj == NULL) return;
2063 if (obj->nodeTab != NULL) {
2066 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2067 for (i = 0;i < obj->nodeNr;i++)
2068 if ((obj->nodeTab[i] != NULL) &&
2069 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
2070 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2071 xmlFree(obj->nodeTab);
2077 * xmlXPathFreeValueTree:
2078 * @obj: the xmlNodeSetPtr to free
2080 * Free the NodeSet compound and the actual tree, this is different
2081 * from xmlXPathFreeNodeSet()
2084 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
2087 if (obj == NULL) return;
2089 if (obj->nodeTab != NULL) {
2090 for (i = 0;i < obj->nodeNr;i++) {
2091 if (obj->nodeTab[i] != NULL) {
2092 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
2093 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
2095 xmlFreeNodeList(obj->nodeTab[i]);
2099 xmlFree(obj->nodeTab);
2104 #if defined(DEBUG) || defined(DEBUG_STEP)
2106 * xmlGenericErrorContextNodeSet:
2107 * @output: a FILE * for the output
2108 * @obj: the xmlNodeSetPtr to free
2110 * Quick display of a NodeSet
2113 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
2116 if (output == NULL) output = xmlGenericErrorContext;
2118 fprintf(output, "NodeSet == NULL !\n");
2121 if (obj->nodeNr == 0) {
2122 fprintf(output, "NodeSet is empty\n");
2125 if (obj->nodeTab == NULL) {
2126 fprintf(output, " nodeTab == NULL !\n");
2129 for (i = 0; i < obj->nodeNr; i++) {
2130 if (obj->nodeTab[i] == NULL) {
2131 fprintf(output, " NULL !\n");
2134 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
2135 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
2136 fprintf(output, " /");
2137 else if (obj->nodeTab[i]->name == NULL)
2138 fprintf(output, " noname!");
2139 else fprintf(output, " %s", obj->nodeTab[i]->name);
2141 fprintf(output, "\n");
2146 * xmlXPathNewNodeSet:
2147 * @val: the NodePtr value
2149 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2150 * it with the single Node @val
2152 * Returns the newly created object.
2155 xmlXPathNewNodeSet(xmlNodePtr val) {
2156 xmlXPathObjectPtr ret;
2158 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2160 xmlGenericError(xmlGenericErrorContext,
2161 "xmlXPathNewNodeSet: out of memory\n");
2164 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2165 ret->type = XPATH_NODESET;
2167 ret->nodesetval = xmlXPathNodeSetCreate(val);
2168 /* @@ with_ns to check wether namespace nodes should be looked at @@ */
2173 * xmlXPathNewValueTree:
2174 * @val: the NodePtr value
2176 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
2177 * it with the tree root @val
2179 * Returns the newly created object.
2182 xmlXPathNewValueTree(xmlNodePtr val) {
2183 xmlXPathObjectPtr ret;
2185 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2187 xmlGenericError(xmlGenericErrorContext,
2188 "xmlXPathNewNodeSet: out of memory\n");
2191 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2192 ret->type = XPATH_XSLT_TREE;
2194 ret->user = (void *) val;
2195 ret->nodesetval = xmlXPathNodeSetCreate(val);
2200 * xmlXPathNewNodeSetList:
2201 * @val: an existing NodeSet
2203 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
2204 * it with the Nodeset @val
2206 * Returns the newly created object.
2209 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
2211 xmlXPathObjectPtr ret;
2216 else if (val->nodeTab == NULL)
2217 ret = xmlXPathNewNodeSet(NULL);
2219 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
2220 for (i = 1; i < val->nodeNr; ++i)
2221 xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
2228 * xmlXPathWrapNodeSet:
2229 * @val: the NodePtr value
2231 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2233 * Returns the newly created object.
2236 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
2237 xmlXPathObjectPtr ret;
2239 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
2241 xmlGenericError(xmlGenericErrorContext,
2242 "xmlXPathWrapNodeSet: out of memory\n");
2245 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
2246 ret->type = XPATH_NODESET;
2247 ret->nodesetval = val;
2252 * xmlXPathFreeNodeSetList:
2253 * @obj: an existing NodeSetList object
2255 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
2256 * the list contrary to xmlXPathFreeObject().
2259 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
2260 if (obj == NULL) return;
2265 * xmlXPathDifference:
2266 * @nodes1: a node-set
2267 * @nodes2: a node-set
2269 * Implements the EXSLT - Sets difference() function:
2270 * node-set set:difference (node-set, node-set)
2272 * Returns the difference between the two node sets, or nodes1 if
2276 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2281 if (xmlXPathNodeSetIsEmpty(nodes2))
2284 ret = xmlXPathNodeSetCreate(NULL);
2285 if (xmlXPathNodeSetIsEmpty(nodes1))
2288 l1 = xmlXPathNodeSetGetLength(nodes1);
2290 for (i = 0; i < l1; i++) {
2291 cur = xmlXPathNodeSetItem(nodes1, i);
2292 if (!xmlXPathNodeSetContains(nodes2, cur))
2293 xmlXPathNodeSetAddUnique(ret, cur);
2299 * xmlXPathIntersection:
2300 * @nodes1: a node-set
2301 * @nodes2: a node-set
2303 * Implements the EXSLT - Sets intersection() function:
2304 * node-set set:intersection (node-set, node-set)
2306 * Returns a node set comprising the nodes that are within both the
2307 * node sets passed as arguments
2310 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2311 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
2315 if (xmlXPathNodeSetIsEmpty(nodes1))
2317 if (xmlXPathNodeSetIsEmpty(nodes2))
2320 l1 = xmlXPathNodeSetGetLength(nodes1);
2322 for (i = 0; i < l1; i++) {
2323 cur = xmlXPathNodeSetItem(nodes1, i);
2324 if (xmlXPathNodeSetContains(nodes2, cur))
2325 xmlXPathNodeSetAddUnique(ret, cur);
2331 * xmlXPathDistinctSorted:
2332 * @nodes: a node-set, sorted by document order
2334 * Implements the EXSLT - Sets distinct() function:
2335 * node-set set:distinct (node-set)
2337 * Returns a subset of the nodes contained in @nodes, or @nodes if
2341 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
2343 xmlHashTablePtr hash;
2348 if (xmlXPathNodeSetIsEmpty(nodes))
2351 ret = xmlXPathNodeSetCreate(NULL);
2352 l = xmlXPathNodeSetGetLength(nodes);
2353 hash = xmlHashCreate (l);
2354 for (i = 0; i < l; i++) {
2355 cur = xmlXPathNodeSetItem(nodes, i);
2356 strval = xmlXPathCastNodeToString(cur);
2357 if (xmlHashLookup(hash, strval) == NULL) {
2358 xmlHashAddEntry(hash, strval, strval);
2359 xmlXPathNodeSetAddUnique(ret, cur);
2364 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
2370 * @nodes: a node-set
2372 * Implements the EXSLT - Sets distinct() function:
2373 * node-set set:distinct (node-set)
2374 * @nodes is sorted by document order, then #exslSetsDistinctSorted
2375 * is called with the sorted node-set
2377 * Returns a subset of the nodes contained in @nodes, or @nodes if
2381 xmlXPathDistinct (xmlNodeSetPtr nodes) {
2382 if (xmlXPathNodeSetIsEmpty(nodes))
2385 xmlXPathNodeSetSort(nodes);
2386 return(xmlXPathDistinctSorted(nodes));
2390 * xmlXPathHasSameNodes:
2391 * @nodes1: a node-set
2392 * @nodes2: a node-set
2394 * Implements the EXSLT - Sets has-same-nodes function:
2395 * boolean set:has-same-node(node-set, node-set)
2397 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
2401 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2405 if (xmlXPathNodeSetIsEmpty(nodes1) ||
2406 xmlXPathNodeSetIsEmpty(nodes2))
2409 l = xmlXPathNodeSetGetLength(nodes1);
2410 for (i = 0; i < l; i++) {
2411 cur = xmlXPathNodeSetItem(nodes1, i);
2412 if (xmlXPathNodeSetContains(nodes2, cur))
2419 * xmlXPathNodeLeadingSorted:
2420 * @nodes: a node-set, sorted by document order
2423 * Implements the EXSLT - Sets leading() function:
2424 * node-set set:leading (node-set, node-set)
2426 * Returns the nodes in @nodes that precede @node in document order,
2427 * @nodes if @node is NULL or an empty node-set if @nodes
2428 * doesn't contain @node
2431 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2439 ret = xmlXPathNodeSetCreate(NULL);
2440 if (xmlXPathNodeSetIsEmpty(nodes) ||
2441 (!xmlXPathNodeSetContains(nodes, node)))
2444 l = xmlXPathNodeSetGetLength(nodes);
2445 for (i = 0; i < l; i++) {
2446 cur = xmlXPathNodeSetItem(nodes, i);
2449 xmlXPathNodeSetAddUnique(ret, cur);
2455 * xmlXPathNodeLeading:
2456 * @nodes: a node-set
2459 * Implements the EXSLT - Sets leading() function:
2460 * node-set set:leading (node-set, node-set)
2461 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
2464 * Returns the nodes in @nodes that precede @node in document order,
2465 * @nodes if @node is NULL or an empty node-set if @nodes
2466 * doesn't contain @node
2469 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
2470 xmlXPathNodeSetSort(nodes);
2471 return(xmlXPathNodeLeadingSorted(nodes, node));
2475 * xmlXPathLeadingSorted:
2476 * @nodes1: a node-set, sorted by document order
2477 * @nodes2: a node-set, sorted by document order
2479 * Implements the EXSLT - Sets leading() function:
2480 * node-set set:leading (node-set, node-set)
2482 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2483 * in document order, @nodes1 if @nodes2 is NULL or empty or
2484 * an empty node-set if @nodes1 doesn't contain @nodes2
2487 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2488 if (xmlXPathNodeSetIsEmpty(nodes2))
2490 return(xmlXPathNodeLeadingSorted(nodes1,
2491 xmlXPathNodeSetItem(nodes2, 1)));
2496 * @nodes1: a node-set
2497 * @nodes2: a node-set
2499 * Implements the EXSLT - Sets leading() function:
2500 * node-set set:leading (node-set, node-set)
2501 * @nodes1 and @nodes2 are sorted by document order, then
2502 * #exslSetsLeadingSorted is called.
2504 * Returns the nodes in @nodes1 that precede the first node in @nodes2
2505 * in document order, @nodes1 if @nodes2 is NULL or empty or
2506 * an empty node-set if @nodes1 doesn't contain @nodes2
2509 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2510 if (xmlXPathNodeSetIsEmpty(nodes2))
2512 if (xmlXPathNodeSetIsEmpty(nodes1))
2513 return(xmlXPathNodeSetCreate(NULL));
2514 xmlXPathNodeSetSort(nodes1);
2515 xmlXPathNodeSetSort(nodes2);
2516 return(xmlXPathNodeLeadingSorted(nodes1,
2517 xmlXPathNodeSetItem(nodes2, 1)));
2521 * xmlXPathNodeTrailingSorted:
2522 * @nodes: a node-set, sorted by document order
2525 * Implements the EXSLT - Sets trailing() function:
2526 * node-set set:trailing (node-set, node-set)
2528 * Returns the nodes in @nodes that follow @node in document order,
2529 * @nodes if @node is NULL or an empty node-set if @nodes
2530 * doesn't contain @node
2533 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
2541 ret = xmlXPathNodeSetCreate(NULL);
2542 if (xmlXPathNodeSetIsEmpty(nodes) ||
2543 (!xmlXPathNodeSetContains(nodes, node)))
2546 l = xmlXPathNodeSetGetLength(nodes);
2547 for (i = l; i > 0; i--) {
2548 cur = xmlXPathNodeSetItem(nodes, i);
2551 xmlXPathNodeSetAddUnique(ret, cur);
2557 * xmlXPathNodeTrailing:
2558 * @nodes: a node-set
2561 * Implements the EXSLT - Sets trailing() function:
2562 * node-set set:trailing (node-set, node-set)
2563 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
2566 * Returns the nodes in @nodes that follow @node in document order,
2567 * @nodes if @node is NULL or an empty node-set if @nodes
2568 * doesn't contain @node
2571 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
2572 xmlXPathNodeSetSort(nodes);
2573 return(xmlXPathNodeTrailingSorted(nodes, node));
2577 * xmlXPathTrailingSorted:
2578 * @nodes1: a node-set, sorted by document order
2579 * @nodes2: a node-set, sorted by document order
2581 * Implements the EXSLT - Sets trailing() function:
2582 * node-set set:trailing (node-set, node-set)
2584 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2585 * in document order, @nodes1 if @nodes2 is NULL or empty or
2586 * an empty node-set if @nodes1 doesn't contain @nodes2
2589 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2590 if (xmlXPathNodeSetIsEmpty(nodes2))
2592 return(xmlXPathNodeTrailingSorted(nodes1,
2593 xmlXPathNodeSetItem(nodes2, 0)));
2598 * @nodes1: a node-set
2599 * @nodes2: a node-set
2601 * Implements the EXSLT - Sets trailing() function:
2602 * node-set set:trailing (node-set, node-set)
2603 * @nodes1 and @nodes2 are sorted by document order, then
2604 * #xmlXPathTrailingSorted is called.
2606 * Returns the nodes in @nodes1 that follow the first node in @nodes2
2607 * in document order, @nodes1 if @nodes2 is NULL or empty or
2608 * an empty node-set if @nodes1 doesn't contain @nodes2
2611 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
2612 if (xmlXPathNodeSetIsEmpty(nodes2))
2614 if (xmlXPathNodeSetIsEmpty(nodes1))
2615 return(xmlXPathNodeSetCreate(NULL));
2616 xmlXPathNodeSetSort(nodes1);
2617 xmlXPathNodeSetSort(nodes2);
2618 return(xmlXPathNodeTrailingSorted(nodes1,
2619 xmlXPathNodeSetItem(nodes2, 0)));
2622 /************************************************************************
2624 * Routines to handle extra functions *
2626 ************************************************************************/
2629 * xmlXPathRegisterFunc:
2630 * @ctxt: the XPath context
2631 * @name: the function name
2632 * @f: the function implementation or NULL
2634 * Register a new function. If @f is NULL it unregisters the function
2636 * Returns 0 in case of success, -1 in case of error
2639 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
2640 xmlXPathFunction f) {
2641 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
2645 * xmlXPathRegisterFuncNS:
2646 * @ctxt: the XPath context
2647 * @name: the function name
2648 * @ns_uri: the function namespace URI
2649 * @f: the function implementation or NULL
2651 * Register a new function. If @f is NULL it unregisters the function
2653 * Returns 0 in case of success, -1 in case of error
2656 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2657 const xmlChar *ns_uri, xmlXPathFunction f) {
2663 if (ctxt->funcHash == NULL)
2664 ctxt->funcHash = xmlHashCreate(0);
2665 if (ctxt->funcHash == NULL)
2667 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
2671 * xmlXPathRegisterFuncLookup:
2672 * @ctxt: the XPath context
2673 * @f: the lookup function
2674 * @funcCtxt: the lookup data
2676 * Registers an external mechanism to do function lookup.
2679 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
2680 xmlXPathFuncLookupFunc f,
2684 ctxt->funcLookupFunc = (void *) f;
2685 ctxt->funcLookupData = funcCtxt;
2689 * xmlXPathFunctionLookup:
2690 * @ctxt: the XPath context
2691 * @name: the function name
2693 * Search in the Function array of the context for the given
2696 * Returns the xmlXPathFunction or NULL if not found
2699 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2703 if (ctxt->funcLookupFunc != NULL) {
2704 xmlXPathFunction ret;
2705 xmlXPathFuncLookupFunc f;
2707 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
2708 ret = f(ctxt->funcLookupData, name, NULL);
2712 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
2716 * xmlXPathFunctionLookupNS:
2717 * @ctxt: the XPath context
2718 * @name: the function name
2719 * @ns_uri: the function namespace URI
2721 * Search in the Function array of the context for the given
2724 * Returns the xmlXPathFunction or NULL if not found
2727 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2728 const xmlChar *ns_uri) {
2734 if (ctxt->funcLookupFunc != NULL) {
2735 xmlXPathFunction ret;
2736 xmlXPathFuncLookupFunc f;
2738 f = (xmlXPathFuncLookupFunc) ctxt->funcLookupFunc;
2739 ret = f(ctxt->funcLookupData, name, ns_uri);
2744 if (ctxt->funcHash == NULL)
2747 return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
2751 * xmlXPathRegisteredFuncsCleanup:
2752 * @ctxt: the XPath context
2754 * Cleanup the XPath context data associated to registered functions
2757 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
2761 xmlHashFree(ctxt->funcHash, NULL);
2762 ctxt->funcHash = NULL;
2765 /************************************************************************
2767 * Routines to handle Variable *
2769 ************************************************************************/
2772 * xmlXPathRegisterVariable:
2773 * @ctxt: the XPath context
2774 * @name: the variable name
2775 * @value: the variable value or NULL
2777 * Register a new variable value. If @value is NULL it unregisters
2780 * Returns 0 in case of success, -1 in case of error
2783 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
2784 xmlXPathObjectPtr value) {
2785 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
2789 * xmlXPathRegisterVariableNS:
2790 * @ctxt: the XPath context
2791 * @name: the variable name
2792 * @ns_uri: the variable namespace URI
2793 * @value: the variable value or NULL
2795 * Register a new variable value. If @value is NULL it unregisters
2798 * Returns 0 in case of success, -1 in case of error
2801 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2802 const xmlChar *ns_uri,
2803 xmlXPathObjectPtr value) {
2809 if (ctxt->varHash == NULL)
2810 ctxt->varHash = xmlHashCreate(0);
2811 if (ctxt->varHash == NULL)
2813 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
2815 (xmlHashDeallocator)xmlXPathFreeObject));
2819 * xmlXPathRegisterVariableLookup:
2820 * @ctxt: the XPath context
2821 * @f: the lookup function
2822 * @data: the lookup data
2824 * register an external mechanism to do variable lookup
2827 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
2828 xmlXPathVariableLookupFunc f, void *data) {
2831 ctxt->varLookupFunc = (void *) f;
2832 ctxt->varLookupData = data;
2836 * xmlXPathVariableLookup:
2837 * @ctxt: the XPath context
2838 * @name: the variable name
2840 * Search in the Variable array of the context for the given
2843 * Returns a copy of the value or NULL if not found
2846 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
2850 if (ctxt->varLookupFunc != NULL) {
2851 xmlXPathObjectPtr ret;
2853 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2854 (ctxt->varLookupData, name, NULL);
2857 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
2861 * xmlXPathVariableLookupNS:
2862 * @ctxt: the XPath context
2863 * @name: the variable name
2864 * @ns_uri: the variable namespace URI
2866 * Search in the Variable array of the context for the given
2869 * Returns the a copy of the value or NULL if not found
2872 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
2873 const xmlChar *ns_uri) {
2877 if (ctxt->varLookupFunc != NULL) {
2878 xmlXPathObjectPtr ret;
2880 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
2881 (ctxt->varLookupData, name, ns_uri);
2882 if (ret != NULL) return(ret);
2885 if (ctxt->varHash == NULL)
2890 return(xmlXPathObjectCopy((xmlXPathObjectPtr)
2891 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
2895 * xmlXPathRegisteredVariablesCleanup:
2896 * @ctxt: the XPath context
2898 * Cleanup the XPath context data associated to registered variables
2901 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
2905 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
2906 ctxt->varHash = NULL;
2910 * xmlXPathRegisterNs:
2911 * @ctxt: the XPath context
2912 * @prefix: the namespace prefix
2913 * @ns_uri: the namespace name
2915 * Register a new namespace. If @ns_uri is NULL it unregisters
2918 * Returns 0 in case of success, -1 in case of error
2921 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
2922 const xmlChar *ns_uri) {
2928 if (ctxt->nsHash == NULL)
2929 ctxt->nsHash = xmlHashCreate(10);
2930 if (ctxt->nsHash == NULL)
2932 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
2933 (xmlHashDeallocator)xmlFree));
2938 * @ctxt: the XPath context
2939 * @prefix: the namespace prefix value
2941 * Search in the namespace declaration array of the context for the given
2942 * namespace name associated to the given prefix
2944 * Returns the value or NULL if not found
2947 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
2953 #ifdef XML_XML_NAMESPACE
2954 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
2955 return(XML_XML_NAMESPACE);
2958 if (ctxt->namespaces != NULL) {
2961 for (i = 0;i < ctxt->nsNr;i++) {
2962 if ((ctxt->namespaces[i] != NULL) &&
2963 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
2964 return(ctxt->namespaces[i]->href);
2968 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
2972 * xmlXPathRegisteredNsCleanup:
2973 * @ctxt: the XPath context
2975 * Cleanup the XPath context data associated to registered variables
2978 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
2982 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
2983 ctxt->nsHash = NULL;
2986 /************************************************************************
2988 * Routines to handle Values *
2990 ************************************************************************/
2992 /* Allocations are terrible, one need to optimize all this !!! */
2996 * @val: the double value
2998 * Create a new xmlXPathObjectPtr of type double and of value @val
3000 * Returns the newly created object.
3003 xmlXPathNewFloat(double val) {
3004 xmlXPathObjectPtr ret;
3006 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3008 xmlGenericError(xmlGenericErrorContext,
3009 "xmlXPathNewFloat: out of memory\n");
3012 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3013 ret->type = XPATH_NUMBER;
3014 ret->floatval = val;
3019 * xmlXPathNewBoolean:
3020 * @val: the boolean value
3022 * Create a new xmlXPathObjectPtr of type boolean and of value @val
3024 * Returns the newly created object.
3027 xmlXPathNewBoolean(int val) {
3028 xmlXPathObjectPtr ret;
3030 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3032 xmlGenericError(xmlGenericErrorContext,
3033 "xmlXPathNewBoolean: out of memory\n");
3036 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3037 ret->type = XPATH_BOOLEAN;
3038 ret->boolval = (val != 0);
3043 * xmlXPathNewString:
3044 * @val: the xmlChar * value
3046 * Create a new xmlXPathObjectPtr of type string and of value @val
3048 * Returns the newly created object.
3051 xmlXPathNewString(const xmlChar *val) {
3052 xmlXPathObjectPtr ret;
3054 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3056 xmlGenericError(xmlGenericErrorContext,
3057 "xmlXPathNewString: out of memory\n");
3060 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3061 ret->type = XPATH_STRING;
3063 ret->stringval = xmlStrdup(val);
3065 ret->stringval = xmlStrdup((const xmlChar *)"");
3070 * xmlXPathWrapString:
3071 * @val: the xmlChar * value
3073 * Wraps the @val string into an XPath object.
3075 * Returns the newly created object.
3078 xmlXPathWrapString (xmlChar *val) {
3079 xmlXPathObjectPtr ret;
3081 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3083 xmlGenericError(xmlGenericErrorContext,
3084 "xmlXPathWrapString: out of memory\n");
3087 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3088 ret->type = XPATH_STRING;
3089 ret->stringval = val;
3094 * xmlXPathNewCString:
3095 * @val: the char * value
3097 * Create a new xmlXPathObjectPtr of type string and of value @val
3099 * Returns the newly created object.
3102 xmlXPathNewCString(const char *val) {
3103 xmlXPathObjectPtr ret;
3105 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3107 xmlGenericError(xmlGenericErrorContext,
3108 "xmlXPathNewCString: out of memory\n");
3111 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3112 ret->type = XPATH_STRING;
3113 ret->stringval = xmlStrdup(BAD_CAST val);
3118 * xmlXPathWrapCString:
3119 * @val: the char * value
3121 * Wraps a string into an XPath object.
3123 * Returns the newly created object.
3126 xmlXPathWrapCString (char * val) {
3127 return(xmlXPathWrapString((xmlChar *)(val)));
3131 * xmlXPathWrapExternal:
3132 * @val: the user data
3134 * Wraps the @val data into an XPath object.
3136 * Returns the newly created object.
3139 xmlXPathWrapExternal (void *val) {
3140 xmlXPathObjectPtr ret;
3142 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3144 xmlGenericError(xmlGenericErrorContext,
3145 "xmlXPathWrapExternal: out of memory\n");
3148 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
3149 ret->type = XPATH_USERS;
3155 * xmlXPathObjectCopy:
3156 * @val: the original object
3158 * allocate a new copy of a given object
3160 * Returns the newly created object.
3163 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
3164 xmlXPathObjectPtr ret;
3169 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
3171 xmlGenericError(xmlGenericErrorContext,
3172 "xmlXPathObjectCopy: out of memory\n");
3175 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
3176 switch (val->type) {
3183 ret->stringval = xmlStrdup(val->stringval);
3185 case XPATH_XSLT_TREE:
3186 if ((val->nodesetval != NULL) &&
3187 (val->nodesetval->nodeTab != NULL)) {
3188 xmlNodePtr cur, tmp;
3192 top = xmlNewDoc(NULL);
3193 top->name = (char *)
3194 xmlStrdup(val->nodesetval->nodeTab[0]->name);
3198 cur = val->nodesetval->nodeTab[0]->children;
3199 while (cur != NULL) {
3200 tmp = xmlDocCopyNode(cur, top, 1);
3201 xmlAddChild((xmlNodePtr) top, tmp);
3205 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
3207 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
3208 /* Deallocate the copied tree value */
3211 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
3212 /* Do not deallocate the copied tree value */
3215 case XPATH_LOCATIONSET:
3216 #ifdef LIBXML_XPTR_ENABLED
3218 xmlLocationSetPtr loc = val->user;
3219 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
3224 ret->user = val->user;
3226 case XPATH_UNDEFINED:
3227 xmlGenericError(xmlGenericErrorContext,
3228 "xmlXPathObjectCopy: unsupported type %d\n",
3236 * xmlXPathFreeObject:
3237 * @obj: the object to free
3239 * Free up an xmlXPathObjectPtr object.
3242 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
3243 if (obj == NULL) return;
3244 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
3246 if (obj->user != NULL) {
3247 xmlXPathFreeNodeSet(obj->nodesetval);
3248 xmlFreeNodeList((xmlNodePtr) obj->user);
3249 } else if (obj->nodesetval != NULL)
3250 xmlXPathFreeValueTree(obj->nodesetval);
3252 if (obj->nodesetval != NULL)
3253 xmlXPathFreeNodeSet(obj->nodesetval);
3255 #ifdef LIBXML_XPTR_ENABLED
3256 } else if (obj->type == XPATH_LOCATIONSET) {
3257 if (obj->user != NULL)
3258 xmlXPtrFreeLocationSet(obj->user);
3260 } else if (obj->type == XPATH_STRING) {
3261 if (obj->stringval != NULL)
3262 xmlFree(obj->stringval);
3269 /************************************************************************
3271 * Type Casting Routines *
3273 ************************************************************************/
3276 * xmlXPathCastBooleanToString:
3279 * Converts a boolean to its string value.
3281 * Returns a newly allocated string.
3284 xmlXPathCastBooleanToString (int val) {
3287 ret = xmlStrdup((const xmlChar *) "true");
3289 ret = xmlStrdup((const xmlChar *) "false");
3294 * xmlXPathCastNumberToString:
3297 * Converts a number to its string value.
3299 * Returns a newly allocated string.
3302 xmlXPathCastNumberToString (double val) {
3304 switch (xmlXPathIsInf(val)) {
3306 ret = xmlStrdup((const xmlChar *) "Infinity");
3309 ret = xmlStrdup((const xmlChar *) "-Infinity");
3312 if (xmlXPathIsNaN(val)) {
3313 ret = xmlStrdup((const xmlChar *) "NaN");
3314 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
3315 ret = xmlStrdup((const xmlChar *) "0");
3317 /* could be improved */
3319 xmlXPathFormatNumber(val, buf, 100);
3320 ret = xmlStrdup((const xmlChar *) buf);
3327 * xmlXPathCastNodeToString:
3330 * Converts a node to its string value.
3332 * Returns a newly allocated string.
3335 xmlXPathCastNodeToString (xmlNodePtr node) {
3336 return(xmlNodeGetContent(node));
3340 * xmlXPathCastNodeSetToString:
3343 * Converts a node-set to its string value.
3345 * Returns a newly allocated string.
3348 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
3349 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
3350 return(xmlStrdup((const xmlChar *) ""));
3352 xmlXPathNodeSetSort(ns);
3353 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
3357 * xmlXPathCastToString:
3358 * @val: an XPath object
3360 * Converts an existing object to its string() equivalent
3362 * Returns the string value of the object, NULL in case of error.
3363 * A new string is allocated only if needed (@val isn't a
3367 xmlXPathCastToString(xmlXPathObjectPtr val) {
3368 xmlChar *ret = NULL;
3371 return(xmlStrdup((const xmlChar *) ""));
3372 switch (val->type) {
3373 case XPATH_UNDEFINED:
3375 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
3377 ret = xmlStrdup((const xmlChar *) "");
3380 case XPATH_XSLT_TREE:
3381 ret = xmlXPathCastNodeSetToString(val->nodesetval);
3384 return(xmlStrdup(val->stringval));
3386 ret = xmlXPathCastBooleanToString(val->boolval);
3388 case XPATH_NUMBER: {
3389 ret = xmlXPathCastNumberToString(val->floatval);
3395 case XPATH_LOCATIONSET:
3397 ret = xmlStrdup((const xmlChar *) "");
3404 * xmlXPathConvertString:
3405 * @val: an XPath object
3407 * Converts an existing object to its string() equivalent
3409 * Returns the new object, the old one is freed (or the operation
3410 * is done directly on @val)
3413 xmlXPathConvertString(xmlXPathObjectPtr val) {
3414 xmlChar *res = NULL;
3417 return(xmlXPathNewCString(""));
3419 switch (val->type) {
3420 case XPATH_UNDEFINED:
3422 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
3426 case XPATH_XSLT_TREE:
3427 res = xmlXPathCastNodeSetToString(val->nodesetval);
3432 res = xmlXPathCastBooleanToString(val->boolval);
3435 res = xmlXPathCastNumberToString(val->floatval);
3440 case XPATH_LOCATIONSET:
3444 xmlXPathFreeObject(val);
3446 return(xmlXPathNewCString(""));
3447 return(xmlXPathWrapString(res));
3451 * xmlXPathCastBooleanToNumber:
3454 * Converts a boolean to its number value
3456 * Returns the number value
3459 xmlXPathCastBooleanToNumber(int val) {
3466 * xmlXPathCastStringToNumber:
3469 * Converts a string to its number value
3471 * Returns the number value
3474 xmlXPathCastStringToNumber(const xmlChar * val) {
3475 return(xmlXPathStringEvalNumber(val));
3479 * xmlXPathCastNodeToNumber:
3482 * Converts a node to its number value
3484 * Returns the number value
3487 xmlXPathCastNodeToNumber (xmlNodePtr node) {
3492 return(xmlXPathNAN);
3493 strval = xmlXPathCastNodeToString(node);
3495 return(xmlXPathNAN);
3496 ret = xmlXPathCastStringToNumber(strval);
3503 * xmlXPathCastNodeSetToNumber:
3506 * Converts a node-set to its number value
3508 * Returns the number value
3511 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
3516 return(xmlXPathNAN);
3517 str = xmlXPathCastNodeSetToString(ns);
3518 ret = xmlXPathCastStringToNumber(str);
3524 * xmlXPathCastToNumber:
3525 * @val: an XPath object
3527 * Converts an XPath object to its number value
3529 * Returns the number value
3532 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
3536 return(xmlXPathNAN);
3537 switch (val->type) {
3538 case XPATH_UNDEFINED:
3540 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
3545 case XPATH_XSLT_TREE:
3546 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
3549 ret = xmlXPathCastStringToNumber(val->stringval);
3552 ret = val->floatval;
3555 ret = xmlXPathCastBooleanToNumber(val->boolval);
3560 case XPATH_LOCATIONSET:
3569 * xmlXPathConvertNumber:
3570 * @val: an XPath object
3572 * Converts an existing object to its number() equivalent
3574 * Returns the new object, the old one is freed (or the operation
3575 * is done directly on @val)
3578 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
3579 xmlXPathObjectPtr ret;
3582 return(xmlXPathNewFloat(0.0));
3583 if (val->type == XPATH_NUMBER)
3585 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
3586 xmlXPathFreeObject(val);
3591 * xmlXPathCastNumberToBoolean:
3594 * Converts a number to its boolean value
3596 * Returns the boolean value
3599 xmlXPathCastNumberToBoolean (double val) {
3600 if (xmlXPathIsNaN(val) || (val == 0.0))
3606 * xmlXPathCastStringToBoolean:
3609 * Converts a string to its boolean value
3611 * Returns the boolean value
3614 xmlXPathCastStringToBoolean (const xmlChar *val) {
3615 if ((val == NULL) || (xmlStrlen(val) == 0))
3621 * xmlXPathCastNodeSetToBoolean:
3624 * Converts a node-set to its boolean value
3626 * Returns the boolean value
3629 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
3630 if ((ns == NULL) || (ns->nodeNr == 0))
3636 * xmlXPathCastToBoolean:
3637 * @val: an XPath object
3639 * Converts an XPath object to its boolean value
3641 * Returns the boolean value
3644 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
3649 switch (val->type) {
3650 case XPATH_UNDEFINED:
3652 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
3657 case XPATH_XSLT_TREE:
3658 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
3661 ret = xmlXPathCastStringToBoolean(val->stringval);
3664 ret = xmlXPathCastNumberToBoolean(val->floatval);
3672 case XPATH_LOCATIONSET:
3682 * xmlXPathConvertBoolean:
3683 * @val: an XPath object
3685 * Converts an existing object to its boolean() equivalent
3687 * Returns the new object, the old one is freed (or the operation
3688 * is done directly on @val)
3691 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
3692 xmlXPathObjectPtr ret;
3695 return(xmlXPathNewBoolean(0));
3696 if (val->type == XPATH_BOOLEAN)
3698 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
3699 xmlXPathFreeObject(val);
3703 /************************************************************************
3705 * Routines to handle XPath contexts *
3707 ************************************************************************/
3710 * xmlXPathNewContext:
3711 * @doc: the XML document
3713 * Create a new xmlXPathContext
3715 * Returns the xmlXPathContext just allocated. The caller will need to free it.
3718 xmlXPathNewContext(xmlDocPtr doc) {
3719 xmlXPathContextPtr ret;
3721 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
3723 xmlGenericError(xmlGenericErrorContext,
3724 "xmlXPathNewContext: out of memory\n");
3727 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
3731 ret->varHash = NULL;
3737 ret->funcHash = xmlHashCreate(0);
3746 ret->contextSize = -1;
3747 ret->proximityPosition = -1;
3749 xmlXPathRegisterAllFunctions(ret);
3755 * xmlXPathFreeContext:
3756 * @ctxt: the context to free
3758 * Free up an xmlXPathContext
3761 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
3762 xmlXPathRegisteredNsCleanup(ctxt);
3763 xmlXPathRegisteredFuncsCleanup(ctxt);
3764 xmlXPathRegisteredVariablesCleanup(ctxt);
3768 /************************************************************************
3770 * Routines to handle XPath parser contexts *
3772 ************************************************************************/
3774 #define CHECK_CTXT(ctxt) \
3775 if (ctxt == NULL) { \
3776 xmlGenericError(xmlGenericErrorContext, \
3777 "%s:%d Internal error: ctxt == NULL\n", \
3778 __FILE__, __LINE__); \
3782 #define CHECK_CONTEXT(ctxt) \
3783 if (ctxt == NULL) { \
3784 xmlGenericError(xmlGenericErrorContext, \
3785 "%s:%d Internal error: no context\n", \
3786 __FILE__, __LINE__); \
3788 else if (ctxt->doc == NULL) { \
3789 xmlGenericError(xmlGenericErrorContext, \
3790 "%s:%d Internal error: no document\n", \
3791 __FILE__, __LINE__); \
3793 else if (ctxt->doc->children == NULL) { \
3794 xmlGenericError(xmlGenericErrorContext, \
3795 "%s:%d Internal error: document without root\n", \
3796 __FILE__, __LINE__); \
3801 * xmlXPathNewParserContext:
3802 * @str: the XPath expression
3803 * @ctxt: the XPath context
3805 * Create a new xmlXPathParserContext
3807 * Returns the xmlXPathParserContext just allocated.
3809 xmlXPathParserContextPtr
3810 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
3811 xmlXPathParserContextPtr ret;
3813 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3815 xmlGenericError(xmlGenericErrorContext,
3816 "xmlXPathNewParserContext: out of memory\n");
3819 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3820 ret->cur = ret->base = str;
3821 ret->context = ctxt;
3823 ret->comp = xmlXPathNewCompExpr();
3824 if (ret->comp == NULL) {
3825 xmlFree(ret->valueTab);
3834 * xmlXPathCompParserContext:
3835 * @comp: the XPath compiled expression
3836 * @ctxt: the XPath context
3838 * Create a new xmlXPathParserContext when processing a compiled expression
3840 * Returns the xmlXPathParserContext just allocated.
3842 static xmlXPathParserContextPtr
3843 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
3844 xmlXPathParserContextPtr ret;
3846 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
3848 xmlGenericError(xmlGenericErrorContext,
3849 "xmlXPathCompParserContext: out of memory\n");
3852 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
3854 /* Allocate the value stack */
3855 ret->valueTab = (xmlXPathObjectPtr *)
3856 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
3857 if (ret->valueTab == NULL) {
3859 xmlGenericError(xmlGenericErrorContext,
3860 "xmlXPathCompParserContext: out of memory\n");
3867 ret->context = ctxt;
3874 * xmlXPathFreeParserContext:
3875 * @ctxt: the context to free
3877 * Free up an xmlXPathParserContext
3880 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
3881 if (ctxt->valueTab != NULL) {
3882 xmlFree(ctxt->valueTab);
3885 xmlXPathFreeCompExpr(ctxt->comp);
3889 /************************************************************************
3891 * The implicit core function library *
3893 ************************************************************************/
3896 * xmlXPathNodeValHash:
3897 * @node: a node pointer
3899 * Function computing the beginning of the string value of the node,
3900 * used to speed up comparisons
3902 * Returns an int usable as a hash
3905 xmlXPathNodeValHash(xmlNodePtr node) {
3907 const xmlChar * string = NULL;
3908 xmlNodePtr tmp = NULL;
3909 unsigned int ret = 0;
3914 if (node->type == XML_DOCUMENT_NODE) {
3915 tmp = xmlDocGetRootElement((xmlDocPtr) node);
3917 node = node->children;
3925 switch (node->type) {
3926 case XML_COMMENT_NODE:
3928 case XML_CDATA_SECTION_NODE:
3930 string = node->content;
3935 return(((unsigned int) string[0]) +
3936 (((unsigned int) string[1]) << 8));
3937 case XML_NAMESPACE_DECL:
3938 string = ((xmlNsPtr)node)->href;
3943 return(((unsigned int) string[0]) +
3944 (((unsigned int) string[1]) << 8));
3945 case XML_ATTRIBUTE_NODE:
3946 tmp = ((xmlAttrPtr) node)->children;
3948 case XML_ELEMENT_NODE:
3949 tmp = node->children;
3954 while (tmp != NULL) {
3955 switch (tmp->type) {
3956 case XML_COMMENT_NODE:
3958 case XML_CDATA_SECTION_NODE:
3960 string = tmp->content;
3962 case XML_NAMESPACE_DECL:
3963 string = ((xmlNsPtr)tmp)->href;
3968 if ((string != NULL) && (string[0] != 0)) {
3972 return(ret + (((unsigned int) string[0]) << 8));
3974 if (string[1] == 0) {
3976 ret = (unsigned int) string[0];
3978 return(((unsigned int) string[0]) +
3979 (((unsigned int) string[1]) << 8));
3985 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
3986 if (tmp->children->type != XML_ENTITY_DECL) {
3987 tmp = tmp->children;
3994 if (tmp->next != NULL) {
4007 if (tmp->next != NULL) {
4011 } while (tmp != NULL);
4017 * xmlXPathStringHash:
4020 * Function computing the beginning of the string value of the node,
4021 * used to speed up comparisons
4023 * Returns an int usable as a hash
4026 xmlXPathStringHash(const xmlChar * string) {
4028 return((unsigned int) 0);
4031 return(((unsigned int) string[0]) +
4032 (((unsigned int) string[1]) << 8));
4036 * xmlXPathCompareNodeSetFloat:
4037 * @ctxt: the XPath Parser context
4038 * @inf: less than (1) or greater than (0)
4039 * @strict: is the comparison strict
4040 * @arg: the node set
4043 * Implement the compare operation between a nodeset and a number
4044 * @ns < @val (1, 1, ...
4045 * @ns <= @val (1, 0, ...
4046 * @ns > @val (0, 1, ...
4047 * @ns >= @val (0, 0, ...
4049 * If one object to be compared is a node-set and the other is a number,
4050 * then the comparison will be true if and only if there is a node in the
4051 * node-set such that the result of performing the comparison on the number
4052 * to be compared and on the result of converting the string-value of that
4053 * node to a number using the number function is true.
4055 * Returns 0 or 1 depending on the results of the test.
4058 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
4059 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
4064 if ((f == NULL) || (arg == NULL) ||
4065 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4066 xmlXPathFreeObject(arg);
4067 xmlXPathFreeObject(f);
4070 ns = arg->nodesetval;
4072 for (i = 0;i < ns->nodeNr;i++) {
4073 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4076 xmlXPathNewString(str2));
4078 xmlXPathNumberFunction(ctxt, 1);
4079 valuePush(ctxt, xmlXPathObjectCopy(f));
4080 ret = xmlXPathCompareValues(ctxt, inf, strict);
4086 xmlXPathFreeObject(arg);
4087 xmlXPathFreeObject(f);
4092 * xmlXPathCompareNodeSetString:
4093 * @ctxt: the XPath Parser context
4094 * @inf: less than (1) or greater than (0)
4095 * @strict: is the comparison strict
4096 * @arg: the node set
4099 * Implement the compare operation between a nodeset and a string
4100 * @ns < @val (1, 1, ...
4101 * @ns <= @val (1, 0, ...
4102 * @ns > @val (0, 1, ...
4103 * @ns >= @val (0, 0, ...
4105 * If one object to be compared is a node-set and the other is a string,
4106 * then the comparison will be true if and only if there is a node in
4107 * the node-set such that the result of performing the comparison on the
4108 * string-value of the node and the other string is true.
4110 * Returns 0 or 1 depending on the results of the test.
4113 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
4114 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
4119 if ((s == NULL) || (arg == NULL) ||
4120 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
4121 xmlXPathFreeObject(arg);
4122 xmlXPathFreeObject(s);
4125 ns = arg->nodesetval;
4127 for (i = 0;i < ns->nodeNr;i++) {
4128 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4131 xmlXPathNewString(str2));
4133 valuePush(ctxt, xmlXPathObjectCopy(s));
4134 ret = xmlXPathCompareValues(ctxt, inf, strict);
4140 xmlXPathFreeObject(arg);
4141 xmlXPathFreeObject(s);
4146 * xmlXPathCompareNodeSets:
4147 * @inf: less than (1) or greater than (0)
4148 * @strict: is the comparison strict
4149 * @arg1: the first node set object
4150 * @arg2: the second node set object
4152 * Implement the compare operation on nodesets:
4154 * If both objects to be compared are node-sets, then the comparison
4155 * will be true if and only if there is a node in the first node-set
4156 * and a node in the second node-set such that the result of performing
4157 * the comparison on the string-values of the two nodes is true.
4159 * When neither object to be compared is a node-set and the operator
4160 * is <=, <, >= or >, then the objects are compared by converting both
4161 * objects to numbers and comparing the numbers according to IEEE 754.
4163 * The number function converts its argument to a number as follows:
4164 * - a string that consists of optional whitespace followed by an
4165 * optional minus sign followed by a Number followed by whitespace
4166 * is converted to the IEEE 754 number that is nearest (according
4167 * to the IEEE 754 round-to-nearest rule) to the mathematical value
4168 * represented by the string; any other string is converted to NaN
4170 * Conclusion all nodes need to be converted first to their string value
4171 * and then the comparison must be done when possible
4174 xmlXPathCompareNodeSets(int inf, int strict,
4175 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4183 if ((arg1 == NULL) ||
4184 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
4185 xmlXPathFreeObject(arg2);
4188 if ((arg2 == NULL) ||
4189 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
4190 xmlXPathFreeObject(arg1);
4191 xmlXPathFreeObject(arg2);
4195 ns1 = arg1->nodesetval;
4196 ns2 = arg2->nodesetval;
4198 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
4199 xmlXPathFreeObject(arg1);
4200 xmlXPathFreeObject(arg2);
4203 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
4204 xmlXPathFreeObject(arg1);
4205 xmlXPathFreeObject(arg2);
4209 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
4210 if (values2 == NULL) {
4211 xmlXPathFreeObject(arg1);
4212 xmlXPathFreeObject(arg2);
4215 for (i = 0;i < ns1->nodeNr;i++) {
4216 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
4217 if (xmlXPathIsNaN(val1))
4219 for (j = 0;j < ns2->nodeNr;j++) {
4221 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
4223 if (xmlXPathIsNaN(values2[j]))
4226 ret = (val1 < values2[j]);
4227 else if (inf && !strict)
4228 ret = (val1 <= values2[j]);
4229 else if (!inf && strict)
4230 ret = (val1 > values2[j]);
4231 else if (!inf && !strict)
4232 ret = (val1 >= values2[j]);
4241 xmlXPathFreeObject(arg1);
4242 xmlXPathFreeObject(arg2);
4247 * xmlXPathCompareNodeSetValue:
4248 * @ctxt: the XPath Parser context
4249 * @inf: less than (1) or greater than (0)
4250 * @strict: is the comparison strict
4251 * @arg: the node set
4254 * Implement the compare operation between a nodeset and a value
4255 * @ns < @val (1, 1, ...
4256 * @ns <= @val (1, 0, ...
4257 * @ns > @val (0, 1, ...
4258 * @ns >= @val (0, 0, ...
4260 * If one object to be compared is a node-set and the other is a boolean,
4261 * then the comparison will be true if and only if the result of performing
4262 * the comparison on the boolean and on the result of converting
4263 * the node-set to a boolean using the boolean function is true.
4265 * Returns 0 or 1 depending on the results of the test.
4268 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
4269 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
4270 if ((val == NULL) || (arg == NULL) ||
4271 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4276 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
4278 case XPATH_XSLT_TREE:
4279 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
4281 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
4283 valuePush(ctxt, arg);
4284 xmlXPathBooleanFunction(ctxt, 1);
4285 valuePush(ctxt, val);
4286 return(xmlXPathCompareValues(ctxt, inf, strict));
4294 * xmlXPathEqualNodeSetString:
4295 * @arg: the nodeset object argument
4296 * @str: the string to compare to.
4297 * @neq: flag to show whether for '=' (0) or '!=' (1)
4299 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4300 * If one object to be compared is a node-set and the other is a string,
4301 * then the comparison will be true if and only if there is a node in
4302 * the node-set such that the result of performing the comparison on the
4303 * string-value of the node and the other string is true.
4305 * Returns 0 or 1 depending on the results of the test.
4308 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
4315 if ((str == NULL) || (arg == NULL) ||
4316 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4318 ns = arg->nodesetval;
4319 hash = xmlXPathStringHash(str);
4322 if (ns->nodeNr <= 0) {
4327 for (i = 0; i < ns->nodeNr; i++) {
4328 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
4329 str2 = xmlNodeGetContent(ns->nodeTab[i]);
4330 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
4335 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
4353 * xmlXPathEqualNodeSetFloat:
4354 * @arg: the nodeset object argument
4355 * @f: the float to compare to
4356 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
4358 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4359 * If one object to be compared is a node-set and the other is a number,
4360 * then the comparison will be true if and only if there is a node in
4361 * the node-set such that the result of performing the comparison on the
4362 * number to be compared and on the result of converting the string-value
4363 * of that node to a number using the number function is true.
4365 * Returns 0 or 1 depending on the results of the test.
4368 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
4369 xmlXPathObjectPtr arg, double f, int neq) {
4373 xmlXPathObjectPtr val;
4376 if ((arg == NULL) ||
4377 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
4380 ns = arg->nodesetval;
4382 for (i=0;i<ns->nodeNr;i++) {
4383 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
4385 valuePush(ctxt, xmlXPathNewString(str2));
4387 xmlXPathNumberFunction(ctxt, 1);
4388 val = valuePop(ctxt);
4390 xmlXPathFreeObject(val);
4391 if (!xmlXPathIsNaN(v)) {
4392 if ((!neq) && (v==f)) {
4395 } else if ((neq) && (v!=f)) {
4409 * xmlXPathEqualNodeSets:
4410 * @arg1: first nodeset object argument
4411 * @arg2: second nodeset object argument
4412 * @neq: flag to show whether to test '=' (0) or '!=' (1)
4414 * Implement the equal / not equal operation on XPath nodesets:
4415 * @arg1 == @arg2 or @arg1 != @arg2
4416 * If both objects to be compared are node-sets, then the comparison
4417 * will be true if and only if there is a node in the first node-set and
4418 * a node in the second node-set such that the result of performing the
4419 * comparison on the string-values of the two nodes is true.
4421 * (needless to say, this is a costly operation)
4423 * Returns 0 or 1 depending on the results of the test.
4426 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
4428 unsigned int *hashs1;
4429 unsigned int *hashs2;
4436 if ((arg1 == NULL) ||
4437 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
4439 if ((arg2 == NULL) ||
4440 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
4443 ns1 = arg1->nodesetval;
4444 ns2 = arg2->nodesetval;
4446 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
4448 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
4452 * for equal, check if there is a node pertaining to both sets
4455 for (i = 0;i < ns1->nodeNr;i++)
4456 for (j = 0;j < ns2->nodeNr;j++)
4457 if (ns1->nodeTab[i] == ns2->nodeTab[j])
4460 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
4461 if (values1 == NULL)
4463 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
4464 if (hashs1 == NULL) {
4468 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
4469 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
4470 if (values2 == NULL) {
4475 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
4476 if (hashs2 == NULL) {
4482 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
4483 for (i = 0;i < ns1->nodeNr;i++) {
4484 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
4485 for (j = 0;j < ns2->nodeNr;j++) {
4487 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
4488 if (hashs1[i] != hashs2[j]) {
4495 if (values1[i] == NULL)
4496 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
4497 if (values2[j] == NULL)
4498 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
4499 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
4507 for (i = 0;i < ns1->nodeNr;i++)
4508 if (values1[i] != NULL)
4509 xmlFree(values1[i]);
4510 for (j = 0;j < ns2->nodeNr;j++)
4511 if (values2[j] != NULL)
4512 xmlFree(values2[j]);
4521 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
4522 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
4525 *At this point we are assured neither arg1 nor arg2
4526 *is a nodeset, so we can just pick the appropriate routine.
4528 switch (arg1->type) {
4529 case XPATH_UNDEFINED:
4531 xmlGenericError(xmlGenericErrorContext,
4532 "Equal: undefined\n");
4536 switch (arg2->type) {
4537 case XPATH_UNDEFINED:
4539 xmlGenericError(xmlGenericErrorContext,
4540 "Equal: undefined\n");
4545 xmlGenericError(xmlGenericErrorContext,
4546 "Equal: %d boolean %d \n",
4547 arg1->boolval, arg2->boolval);
4549 ret = (arg1->boolval == arg2->boolval);
4552 ret = (arg1->boolval ==
4553 xmlXPathCastNumberToBoolean(arg2->floatval));
4556 if ((arg2->stringval == NULL) ||
4557 (arg2->stringval[0] == 0)) ret = 0;
4560 ret = (arg1->boolval == ret);
4565 case XPATH_LOCATIONSET:
4569 case XPATH_XSLT_TREE:
4574 switch (arg2->type) {
4575 case XPATH_UNDEFINED:
4577 xmlGenericError(xmlGenericErrorContext,
4578 "Equal: undefined\n");
4582 ret = (arg2->boolval==
4583 xmlXPathCastNumberToBoolean(arg1->floatval));
4586 valuePush(ctxt, arg2);
4587 xmlXPathNumberFunction(ctxt, 1);
4588 arg2 = valuePop(ctxt);
4589 /* no break on purpose */
4591 /* Hand check NaN and Infinity equalities */
4592 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4594 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4595 if (xmlXPathIsInf(arg2->floatval) == 1)
4599 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4600 if (xmlXPathIsInf(arg2->floatval) == -1)
4604 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4605 if (xmlXPathIsInf(arg1->floatval) == 1)
4609 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4610 if (xmlXPathIsInf(arg1->floatval) == -1)
4615 ret = (arg1->floatval == arg2->floatval);
4621 case XPATH_LOCATIONSET:
4625 case XPATH_XSLT_TREE:
4630 switch (arg2->type) {
4631 case XPATH_UNDEFINED:
4633 xmlGenericError(xmlGenericErrorContext,
4634 "Equal: undefined\n");
4638 if ((arg1->stringval == NULL) ||
4639 (arg1->stringval[0] == 0)) ret = 0;
4642 ret = (arg2->boolval == ret);
4645 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
4648 valuePush(ctxt, arg1);
4649 xmlXPathNumberFunction(ctxt, 1);
4650 arg1 = valuePop(ctxt);
4651 /* Hand check NaN and Infinity equalities */
4652 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4654 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
4655 if (xmlXPathIsInf(arg2->floatval) == 1)
4659 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
4660 if (xmlXPathIsInf(arg2->floatval) == -1)
4664 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
4665 if (xmlXPathIsInf(arg1->floatval) == 1)
4669 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
4670 if (xmlXPathIsInf(arg1->floatval) == -1)
4675 ret = (arg1->floatval == arg2->floatval);
4681 case XPATH_LOCATIONSET:
4685 case XPATH_XSLT_TREE:
4692 case XPATH_LOCATIONSET:
4696 case XPATH_XSLT_TREE:
4699 xmlXPathFreeObject(arg1);
4700 xmlXPathFreeObject(arg2);
4705 * xmlXPathEqualValues:
4706 * @ctxt: the XPath Parser context
4708 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4710 * Returns 0 or 1 depending on the results of the test.
4713 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
4714 xmlXPathObjectPtr arg1, arg2, argtmp;
4717 arg2 = valuePop(ctxt);
4718 arg1 = valuePop(ctxt);
4719 if ((arg1 == NULL) || (arg2 == NULL)) {
4721 xmlXPathFreeObject(arg1);
4723 xmlXPathFreeObject(arg2);
4724 XP_ERROR0(XPATH_INVALID_OPERAND);
4729 xmlGenericError(xmlGenericErrorContext,
4730 "Equal: by pointer\n");
4736 *If either argument is a nodeset, it's a 'special case'
4738 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4739 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4741 *Hack it to assure arg1 is the nodeset
4743 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4748 switch (arg2->type) {
4749 case XPATH_UNDEFINED:
4751 xmlGenericError(xmlGenericErrorContext,
4752 "Equal: undefined\n");
4756 case XPATH_XSLT_TREE:
4757 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
4760 if ((arg1->nodesetval == NULL) ||
4761 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4764 ret = (ret == arg2->boolval);
4767 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
4770 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
4775 case XPATH_LOCATIONSET:
4779 xmlXPathFreeObject(arg1);
4780 xmlXPathFreeObject(arg2);
4784 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4788 * xmlXPathNotEqualValues:
4789 * @ctxt: the XPath Parser context
4791 * Implement the equal operation on XPath objects content: @arg1 == @arg2
4793 * Returns 0 or 1 depending on the results of the test.
4796 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
4797 xmlXPathObjectPtr arg1, arg2, argtmp;
4800 arg2 = valuePop(ctxt);
4801 arg1 = valuePop(ctxt);
4802 if ((arg1 == NULL) || (arg2 == NULL)) {
4804 xmlXPathFreeObject(arg1);
4806 xmlXPathFreeObject(arg2);
4807 XP_ERROR0(XPATH_INVALID_OPERAND);
4812 xmlGenericError(xmlGenericErrorContext,
4813 "NotEqual: by pointer\n");
4819 *If either argument is a nodeset, it's a 'special case'
4821 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4822 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4824 *Hack it to assure arg1 is the nodeset
4826 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
4831 switch (arg2->type) {
4832 case XPATH_UNDEFINED:
4834 xmlGenericError(xmlGenericErrorContext,
4835 "NotEqual: undefined\n");
4839 case XPATH_XSLT_TREE:
4840 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
4843 if ((arg1->nodesetval == NULL) ||
4844 (arg1->nodesetval->nodeNr == 0)) ret = 0;
4847 ret = (ret != arg2->boolval);
4850 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
4853 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
4858 case XPATH_LOCATIONSET:
4862 xmlXPathFreeObject(arg1);
4863 xmlXPathFreeObject(arg2);
4867 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
4871 * xmlXPathCompareValues:
4872 * @ctxt: the XPath Parser context
4873 * @inf: less than (1) or greater than (0)
4874 * @strict: is the comparison strict
4876 * Implement the compare operation on XPath objects:
4877 * @arg1 < @arg2 (1, 1, ...
4878 * @arg1 <= @arg2 (1, 0, ...
4879 * @arg1 > @arg2 (0, 1, ...
4880 * @arg1 >= @arg2 (0, 0, ...
4882 * When neither object to be compared is a node-set and the operator is
4883 * <=, <, >=, >, then the objects are compared by converted both objects
4884 * to numbers and comparing the numbers according to IEEE 754. The <
4885 * comparison will be true if and only if the first number is less than the
4886 * second number. The <= comparison will be true if and only if the first
4887 * number is less than or equal to the second number. The > comparison
4888 * will be true if and only if the first number is greater than the second
4889 * number. The >= comparison will be true if and only if the first number
4890 * is greater than or equal to the second number.
4892 * Returns 1 if the comparison succeeded, 0 if it failed
4895 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
4896 int ret = 0, arg1i = 0, arg2i = 0;
4897 xmlXPathObjectPtr arg1, arg2;
4899 arg2 = valuePop(ctxt);
4900 arg1 = valuePop(ctxt);
4901 if ((arg1 == NULL) || (arg2 == NULL)) {
4903 xmlXPathFreeObject(arg1);
4905 xmlXPathFreeObject(arg2);
4906 XP_ERROR0(XPATH_INVALID_OPERAND);
4909 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
4910 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4911 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
4912 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
4913 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
4915 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
4916 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
4919 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
4926 if (arg1->type != XPATH_NUMBER) {
4927 valuePush(ctxt, arg1);
4928 xmlXPathNumberFunction(ctxt, 1);
4929 arg1 = valuePop(ctxt);
4931 if (arg1->type != XPATH_NUMBER) {
4932 xmlXPathFreeObject(arg1);
4933 xmlXPathFreeObject(arg2);
4934 XP_ERROR0(XPATH_INVALID_OPERAND);
4936 if (arg2->type != XPATH_NUMBER) {
4937 valuePush(ctxt, arg2);
4938 xmlXPathNumberFunction(ctxt, 1);
4939 arg2 = valuePop(ctxt);
4941 if (arg2->type != XPATH_NUMBER) {
4942 xmlXPathFreeObject(arg1);
4943 xmlXPathFreeObject(arg2);
4944 XP_ERROR0(XPATH_INVALID_OPERAND);
4947 * Add tests for infinity and nan
4948 * => feedback on 3.4 for Inf and NaN
4950 /* Hand check NaN and Infinity comparisons */
4951 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
4954 arg1i=xmlXPathIsInf(arg1->floatval);
4955 arg2i=xmlXPathIsInf(arg2->floatval);
4956 if (inf && strict) {
4957 if ((arg1i == -1 && arg2i != -1) ||
4958 (arg2i == 1 && arg1i != 1)) {
4960 } else if (arg1i == 0 && arg2i == 0) {
4961 ret = (arg1->floatval < arg2->floatval);
4966 else if (inf && !strict) {
4967 if (arg1i == -1 || arg2i == 1) {
4969 } else if (arg1i == 0 && arg2i == 0) {
4970 ret = (arg1->floatval <= arg2->floatval);
4975 else if (!inf && strict) {
4976 if ((arg1i == 1 && arg2i != 1) ||
4977 (arg2i == -1 && arg1i != -1)) {
4979 } else if (arg1i == 0 && arg2i == 0) {
4980 ret = (arg1->floatval > arg2->floatval);
4985 else if (!inf && !strict) {
4986 if (arg1i == 1 || arg2i == -1) {
4988 } else if (arg1i == 0 && arg2i == 0) {
4989 ret = (arg1->floatval >= arg2->floatval);
4995 xmlXPathFreeObject(arg1);
4996 xmlXPathFreeObject(arg2);
5001 * xmlXPathValueFlipSign:
5002 * @ctxt: the XPath Parser context
5004 * Implement the unary - operation on an XPath object
5005 * The numeric operators convert their operands to numbers as if
5006 * by calling the number function.
5009 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
5011 CHECK_TYPE(XPATH_NUMBER);
5012 if (xmlXPathIsNaN(ctxt->value->floatval))
5013 ctxt->value->floatval=xmlXPathNAN;
5014 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
5015 ctxt->value->floatval=xmlXPathNINF;
5016 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
5017 ctxt->value->floatval=xmlXPathPINF;
5018 else if (ctxt->value->floatval == 0) {
5019 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
5020 ctxt->value->floatval = xmlXPathNZERO;
5022 ctxt->value->floatval = 0;
5025 ctxt->value->floatval = - ctxt->value->floatval;
5029 * xmlXPathAddValues:
5030 * @ctxt: the XPath Parser context
5032 * Implement the add operation on XPath objects:
5033 * The numeric operators convert their operands to numbers as if
5034 * by calling the number function.
5037 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
5038 xmlXPathObjectPtr arg;
5041 arg = valuePop(ctxt);
5043 XP_ERROR(XPATH_INVALID_OPERAND);
5044 val = xmlXPathCastToNumber(arg);
5045 xmlXPathFreeObject(arg);
5048 CHECK_TYPE(XPATH_NUMBER);
5049 ctxt->value->floatval += val;
5053 * xmlXPathSubValues:
5054 * @ctxt: the XPath Parser context
5056 * Implement the subtraction operation on XPath objects:
5057 * The numeric operators convert their operands to numbers as if
5058 * by calling the number function.
5061 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
5062 xmlXPathObjectPtr arg;
5065 arg = valuePop(ctxt);
5067 XP_ERROR(XPATH_INVALID_OPERAND);
5068 val = xmlXPathCastToNumber(arg);
5069 xmlXPathFreeObject(arg);
5072 CHECK_TYPE(XPATH_NUMBER);
5073 ctxt->value->floatval -= val;
5077 * xmlXPathMultValues:
5078 * @ctxt: the XPath Parser context
5080 * Implement the multiply operation on XPath objects:
5081 * The numeric operators convert their operands to numbers as if
5082 * by calling the number function.
5085 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
5086 xmlXPathObjectPtr arg;
5089 arg = valuePop(ctxt);
5091 XP_ERROR(XPATH_INVALID_OPERAND);
5092 val = xmlXPathCastToNumber(arg);
5093 xmlXPathFreeObject(arg);
5096 CHECK_TYPE(XPATH_NUMBER);
5097 ctxt->value->floatval *= val;
5101 * xmlXPathDivValues:
5102 * @ctxt: the XPath Parser context
5104 * Implement the div operation on XPath objects @arg1 / @arg2:
5105 * The numeric operators convert their operands to numbers as if
5106 * by calling the number function.
5109 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
5110 xmlXPathObjectPtr arg;
5113 arg = valuePop(ctxt);
5115 XP_ERROR(XPATH_INVALID_OPERAND);
5116 val = xmlXPathCastToNumber(arg);
5117 xmlXPathFreeObject(arg);
5120 CHECK_TYPE(XPATH_NUMBER);
5121 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
5122 ctxt->value->floatval = xmlXPathNAN;
5123 else if (val == 0 && xmlXPathGetSign(val) != 0) {
5124 if (ctxt->value->floatval == 0)
5125 ctxt->value->floatval = xmlXPathNAN;
5126 else if (ctxt->value->floatval > 0)
5127 ctxt->value->floatval = xmlXPathNINF;
5128 else if (ctxt->value->floatval < 0)
5129 ctxt->value->floatval = xmlXPathPINF;
5131 else if (val == 0) {
5132 if (ctxt->value->floatval == 0)
5133 ctxt->value->floatval = xmlXPathNAN;
5134 else if (ctxt->value->floatval > 0)
5135 ctxt->value->floatval = xmlXPathPINF;
5136 else if (ctxt->value->floatval < 0)
5137 ctxt->value->floatval = xmlXPathNINF;
5139 ctxt->value->floatval /= val;
5143 * xmlXPathModValues:
5144 * @ctxt: the XPath Parser context
5146 * Implement the mod operation on XPath objects: @arg1 / @arg2
5147 * The numeric operators convert their operands to numbers as if
5148 * by calling the number function.
5151 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
5152 xmlXPathObjectPtr arg;
5155 arg = valuePop(ctxt);
5157 XP_ERROR(XPATH_INVALID_OPERAND);
5158 arg2 = xmlXPathCastToNumber(arg);
5159 xmlXPathFreeObject(arg);
5162 CHECK_TYPE(XPATH_NUMBER);
5163 arg1 = ctxt->value->floatval;
5165 ctxt->value->floatval = xmlXPathNAN;
5167 ctxt->value->floatval = fmod(arg1, arg2);
5171 /************************************************************************
5173 * The traversal functions *
5175 ************************************************************************/
5178 * A traversal function enumerates nodes along an axis.
5179 * Initially it must be called with NULL, and it indicates
5180 * termination on the axis by returning NULL.
5182 typedef xmlNodePtr (*xmlXPathTraversalFunction)
5183 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
5187 * @ctxt: the XPath Parser context
5188 * @cur: the current node in the traversal
5190 * Traversal function for the "self" direction
5191 * The self axis contains just the context node itself
5193 * Returns the next element following that axis
5196 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5198 return(ctxt->context->node);
5203 * xmlXPathNextChild:
5204 * @ctxt: the XPath Parser context
5205 * @cur: the current node in the traversal
5207 * Traversal function for the "child" direction
5208 * The child axis contains the children of the context node in document order.
5210 * Returns the next element following that axis
5213 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5215 if (ctxt->context->node == NULL) return(NULL);
5216 switch (ctxt->context->node->type) {
5217 case XML_ELEMENT_NODE:
5219 case XML_CDATA_SECTION_NODE:
5220 case XML_ENTITY_REF_NODE:
5221 case XML_ENTITY_NODE:
5223 case XML_COMMENT_NODE:
5224 case XML_NOTATION_NODE:
5226 return(ctxt->context->node->children);
5227 case XML_DOCUMENT_NODE:
5228 case XML_DOCUMENT_TYPE_NODE:
5229 case XML_DOCUMENT_FRAG_NODE:
5230 case XML_HTML_DOCUMENT_NODE:
5231 #ifdef LIBXML_DOCB_ENABLED
5232 case XML_DOCB_DOCUMENT_NODE:
5234 return(((xmlDocPtr) ctxt->context->node)->children);
5235 case XML_ELEMENT_DECL:
5236 case XML_ATTRIBUTE_DECL:
5237 case XML_ENTITY_DECL:
5238 case XML_ATTRIBUTE_NODE:
5239 case XML_NAMESPACE_DECL:
5240 case XML_XINCLUDE_START:
5241 case XML_XINCLUDE_END:
5246 if ((cur->type == XML_DOCUMENT_NODE) ||
5247 (cur->type == XML_HTML_DOCUMENT_NODE))
5253 * xmlXPathNextDescendant:
5254 * @ctxt: the XPath Parser context
5255 * @cur: the current node in the traversal
5257 * Traversal function for the "descendant" direction
5258 * the descendant axis contains the descendants of the context node in document
5259 * order; a descendant is a child or a child of a child and so on.
5261 * Returns the next element following that axis
5264 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5266 if (ctxt->context->node == NULL)
5268 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5269 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5272 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5273 return(ctxt->context->doc->children);
5274 return(ctxt->context->node->children);
5277 if (cur->children != NULL) {
5279 * Do not descend on entities declarations
5281 if (cur->children->type != XML_ENTITY_DECL) {
5282 cur = cur->children;
5286 if (cur->type != XML_DTD_NODE)
5291 if (cur == ctxt->context->node) return(NULL);
5293 while (cur->next != NULL) {
5295 if ((cur->type != XML_ENTITY_DECL) &&
5296 (cur->type != XML_DTD_NODE))
5302 if (cur == NULL) return(NULL);
5303 if (cur == ctxt->context->node) return(NULL);
5304 if (cur->next != NULL) {
5308 } while (cur != NULL);
5313 * xmlXPathNextDescendantOrSelf:
5314 * @ctxt: the XPath Parser context
5315 * @cur: the current node in the traversal
5317 * Traversal function for the "descendant-or-self" direction
5318 * the descendant-or-self axis contains the context node and the descendants
5319 * of the context node in document order; thus the context node is the first
5320 * node on the axis, and the first child of the context node is the second node
5323 * Returns the next element following that axis
5326 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5328 if (ctxt->context->node == NULL)
5330 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5331 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5333 return(ctxt->context->node);
5336 return(xmlXPathNextDescendant(ctxt, cur));
5340 * xmlXPathNextParent:
5341 * @ctxt: the XPath Parser context
5342 * @cur: the current node in the traversal
5344 * Traversal function for the "parent" direction
5345 * The parent axis contains the parent of the context node, if there is one.
5347 * Returns the next element following that axis
5350 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5352 * the parent of an attribute or namespace node is the element
5353 * to which the attribute or namespace node is attached
5354 * Namespace handling !!!
5357 if (ctxt->context->node == NULL) return(NULL);
5358 switch (ctxt->context->node->type) {
5359 case XML_ELEMENT_NODE:
5361 case XML_CDATA_SECTION_NODE:
5362 case XML_ENTITY_REF_NODE:
5363 case XML_ENTITY_NODE:
5365 case XML_COMMENT_NODE:
5366 case XML_NOTATION_NODE:
5368 case XML_ELEMENT_DECL:
5369 case XML_ATTRIBUTE_DECL:
5370 case XML_XINCLUDE_START:
5371 case XML_XINCLUDE_END:
5372 case XML_ENTITY_DECL:
5373 if (ctxt->context->node->parent == NULL)
5374 return((xmlNodePtr) ctxt->context->doc);
5375 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5376 ((ctxt->context->node->parent->name[0] == ' ') ||
5377 (xmlStrEqual(ctxt->context->node->parent->name,
5378 BAD_CAST "fake node libxslt"))))
5380 return(ctxt->context->node->parent);
5381 case XML_ATTRIBUTE_NODE: {
5382 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5384 return(att->parent);
5386 case XML_DOCUMENT_NODE:
5387 case XML_DOCUMENT_TYPE_NODE:
5388 case XML_DOCUMENT_FRAG_NODE:
5389 case XML_HTML_DOCUMENT_NODE:
5390 #ifdef LIBXML_DOCB_ENABLED
5391 case XML_DOCB_DOCUMENT_NODE:
5394 case XML_NAMESPACE_DECL: {
5395 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5397 if ((ns->next != NULL) &&
5398 (ns->next->type != XML_NAMESPACE_DECL))
5399 return((xmlNodePtr) ns->next);
5408 * xmlXPathNextAncestor:
5409 * @ctxt: the XPath Parser context
5410 * @cur: the current node in the traversal
5412 * Traversal function for the "ancestor" direction
5413 * the ancestor axis contains the ancestors of the context node; the ancestors
5414 * of the context node consist of the parent of context node and the parent's
5415 * parent and so on; the nodes are ordered in reverse document order; thus the
5416 * parent is the first node on the axis, and the parent's parent is the second
5419 * Returns the next element following that axis
5422 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5424 * the parent of an attribute or namespace node is the element
5425 * to which the attribute or namespace node is attached
5429 if (ctxt->context->node == NULL) return(NULL);
5430 switch (ctxt->context->node->type) {
5431 case XML_ELEMENT_NODE:
5433 case XML_CDATA_SECTION_NODE:
5434 case XML_ENTITY_REF_NODE:
5435 case XML_ENTITY_NODE:
5437 case XML_COMMENT_NODE:
5439 case XML_ELEMENT_DECL:
5440 case XML_ATTRIBUTE_DECL:
5441 case XML_ENTITY_DECL:
5442 case XML_NOTATION_NODE:
5443 case XML_XINCLUDE_START:
5444 case XML_XINCLUDE_END:
5445 if (ctxt->context->node->parent == NULL)
5446 return((xmlNodePtr) ctxt->context->doc);
5447 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
5448 ((ctxt->context->node->parent->name[0] == ' ') ||
5449 (xmlStrEqual(ctxt->context->node->parent->name,
5450 BAD_CAST "fake node libxslt"))))
5452 return(ctxt->context->node->parent);
5453 case XML_ATTRIBUTE_NODE: {
5454 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
5456 return(tmp->parent);
5458 case XML_DOCUMENT_NODE:
5459 case XML_DOCUMENT_TYPE_NODE:
5460 case XML_DOCUMENT_FRAG_NODE:
5461 case XML_HTML_DOCUMENT_NODE:
5462 #ifdef LIBXML_DOCB_ENABLED
5463 case XML_DOCB_DOCUMENT_NODE:
5466 case XML_NAMESPACE_DECL: {
5467 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5469 if ((ns->next != NULL) &&
5470 (ns->next->type != XML_NAMESPACE_DECL))
5471 return((xmlNodePtr) ns->next);
5472 /* Bad, how did that namespace ended-up there ? */
5478 if (cur == ctxt->context->doc->children)
5479 return((xmlNodePtr) ctxt->context->doc);
5480 if (cur == (xmlNodePtr) ctxt->context->doc)
5482 switch (cur->type) {
5483 case XML_ELEMENT_NODE:
5485 case XML_CDATA_SECTION_NODE:
5486 case XML_ENTITY_REF_NODE:
5487 case XML_ENTITY_NODE:
5489 case XML_COMMENT_NODE:
5490 case XML_NOTATION_NODE:
5492 case XML_ELEMENT_DECL:
5493 case XML_ATTRIBUTE_DECL:
5494 case XML_ENTITY_DECL:
5495 case XML_XINCLUDE_START:
5496 case XML_XINCLUDE_END:
5497 if (cur->parent == NULL)
5499 if ((cur->parent->type == XML_ELEMENT_NODE) &&
5500 ((cur->parent->name[0] == ' ') ||
5501 (xmlStrEqual(cur->parent->name,
5502 BAD_CAST "fake node libxslt"))))
5504 return(cur->parent);
5505 case XML_ATTRIBUTE_NODE: {
5506 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
5508 return(att->parent);
5510 case XML_NAMESPACE_DECL: {
5511 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
5513 if ((ns->next != NULL) &&
5514 (ns->next->type != XML_NAMESPACE_DECL))
5515 return((xmlNodePtr) ns->next);
5516 /* Bad, how did that namespace ended-up there ? */
5519 case XML_DOCUMENT_NODE:
5520 case XML_DOCUMENT_TYPE_NODE:
5521 case XML_DOCUMENT_FRAG_NODE:
5522 case XML_HTML_DOCUMENT_NODE:
5523 #ifdef LIBXML_DOCB_ENABLED
5524 case XML_DOCB_DOCUMENT_NODE:
5532 * xmlXPathNextAncestorOrSelf:
5533 * @ctxt: the XPath Parser context
5534 * @cur: the current node in the traversal
5536 * Traversal function for the "ancestor-or-self" direction
5537 * he ancestor-or-self axis contains the context node and ancestors of
5538 * the context node in reverse document order; thus the context node is
5539 * the first node on the axis, and the context node's parent the second;
5540 * parent here is defined the same as with the parent axis.
5542 * Returns the next element following that axis
5545 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5547 return(ctxt->context->node);
5548 return(xmlXPathNextAncestor(ctxt, cur));
5552 * xmlXPathNextFollowingSibling:
5553 * @ctxt: the XPath Parser context
5554 * @cur: the current node in the traversal
5556 * Traversal function for the "following-sibling" direction
5557 * The following-sibling axis contains the following siblings of the context
5558 * node in document order.
5560 * Returns the next element following that axis
5563 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5564 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5565 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5567 if (cur == (xmlNodePtr) ctxt->context->doc)
5570 return(ctxt->context->node->next);
5575 * xmlXPathNextPrecedingSibling:
5576 * @ctxt: the XPath Parser context
5577 * @cur: the current node in the traversal
5579 * Traversal function for the "preceding-sibling" direction
5580 * The preceding-sibling axis contains the preceding siblings of the context
5581 * node in reverse document order; the first preceding sibling is first on the
5582 * axis; the sibling preceding that node is the second on the axis and so on.
5584 * Returns the next element following that axis
5587 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5588 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
5589 (ctxt->context->node->type == XML_NAMESPACE_DECL))
5591 if (cur == (xmlNodePtr) ctxt->context->doc)
5594 return(ctxt->context->node->prev);
5595 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
5598 return(ctxt->context->node->prev);
5604 * xmlXPathNextFollowing:
5605 * @ctxt: the XPath Parser context
5606 * @cur: the current node in the traversal
5608 * Traversal function for the "following" direction
5609 * The following axis contains all nodes in the same document as the context
5610 * node that are after the context node in document order, excluding any
5611 * descendants and excluding attribute nodes and namespace nodes; the nodes
5612 * are ordered in document order
5614 * Returns the next element following that axis
5617 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5618 if (cur != NULL && cur->children != NULL)
5619 return cur->children ;
5620 if (cur == NULL) cur = ctxt->context->node;
5621 if (cur == NULL) return(NULL) ; /* ERROR */
5622 if (cur->next != NULL) return(cur->next) ;
5625 if (cur == NULL) return(NULL);
5626 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
5627 if (cur->next != NULL) return(cur->next);
5628 } while (cur != NULL);
5633 * xmlXPathIsAncestor:
5634 * @ancestor: the ancestor node
5635 * @node: the current node
5637 * Check that @ancestor is a @node's ancestor
5639 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
5642 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
5643 if ((ancestor == NULL) || (node == NULL)) return(0);
5644 /* nodes need to be in the same document */
5645 if (ancestor->doc != node->doc) return(0);
5646 /* avoid searching if ancestor or node is the root node */
5647 if (ancestor == (xmlNodePtr) node->doc) return(1);
5648 if (node == (xmlNodePtr) ancestor->doc) return(0);
5649 while (node->parent != NULL) {
5650 if (node->parent == ancestor)
5652 node = node->parent;
5658 * xmlXPathNextPreceding:
5659 * @ctxt: the XPath Parser context
5660 * @cur: the current node in the traversal
5662 * Traversal function for the "preceding" direction
5663 * the preceding axis contains all nodes in the same document as the context
5664 * node that are before the context node in document order, excluding any
5665 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5666 * ordered in reverse document order
5668 * Returns the next element following that axis
5671 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
5674 cur = ctxt->context->node;
5677 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5680 if (cur->prev != NULL) {
5681 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
5688 if (cur == ctxt->context->doc->children)
5690 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
5695 * xmlXPathNextPrecedingInternal:
5696 * @ctxt: the XPath Parser context
5697 * @cur: the current node in the traversal
5699 * Traversal function for the "preceding" direction
5700 * the preceding axis contains all nodes in the same document as the context
5701 * node that are before the context node in document order, excluding any
5702 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
5703 * ordered in reverse document order
5704 * This is a faster implementation but internal only since it requires a
5705 * state kept in the parser context: ctxt->ancestor.
5707 * Returns the next element following that axis
5710 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
5714 cur = ctxt->context->node;
5717 ctxt->ancestor = cur->parent;
5719 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
5721 while (cur->prev == NULL) {
5725 if (cur == ctxt->context->doc->children)
5727 if (cur != ctxt->ancestor)
5729 ctxt->ancestor = cur->parent;
5732 while (cur->last != NULL)
5738 * xmlXPathNextNamespace:
5739 * @ctxt: the XPath Parser context
5740 * @cur: the current attribute in the traversal
5742 * Traversal function for the "namespace" direction
5743 * the namespace axis contains the namespace nodes of the context node;
5744 * the order of nodes on this axis is implementation-defined; the axis will
5745 * be empty unless the context node is an element
5747 * We keep the XML namespace node at the end of the list.
5749 * Returns the next element following that axis
5752 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5753 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
5754 if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) {
5755 if (ctxt->context->tmpNsList != NULL)
5756 xmlFree(ctxt->context->tmpNsList);
5757 ctxt->context->tmpNsList =
5758 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
5759 ctxt->context->tmpNsNr = 0;
5760 if (ctxt->context->tmpNsList != NULL) {
5761 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
5762 ctxt->context->tmpNsNr++;
5765 return((xmlNodePtr) xmlXPathXMLNamespace);
5767 if (ctxt->context->tmpNsNr > 0) {
5768 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
5770 if (ctxt->context->tmpNsList != NULL)
5771 xmlFree(ctxt->context->tmpNsList);
5772 ctxt->context->tmpNsList = NULL;
5778 * xmlXPathNextAttribute:
5779 * @ctxt: the XPath Parser context
5780 * @cur: the current attribute in the traversal
5782 * Traversal function for the "attribute" direction
5783 * TODO: support DTD inherited default attributes
5785 * Returns the next element following that axis
5788 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
5789 if (ctxt->context->node == NULL)
5791 if (ctxt->context->node->type != XML_ELEMENT_NODE)
5794 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
5796 return((xmlNodePtr)ctxt->context->node->properties);
5798 return((xmlNodePtr)cur->next);
5801 /************************************************************************
5803 * NodeTest Functions *
5805 ************************************************************************/
5807 #define IS_FUNCTION 200
5810 /************************************************************************
5812 * Implicit tree core function library *
5814 ************************************************************************/
5818 * @ctxt: the XPath Parser context
5820 * Initialize the context to the root of the document
5823 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
5824 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
5825 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
5828 /************************************************************************
5830 * The explicit core function library *
5831 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
5833 ************************************************************************/
5837 * xmlXPathLastFunction:
5838 * @ctxt: the XPath Parser context
5839 * @nargs: the number of arguments
5841 * Implement the last() XPath function
5843 * The last function returns the number of nodes in the context node list.
5846 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5848 if (ctxt->context->contextSize >= 0) {
5849 valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
5851 xmlGenericError(xmlGenericErrorContext,
5852 "last() : %d\n", ctxt->context->contextSize);
5855 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
5860 * xmlXPathPositionFunction:
5861 * @ctxt: the XPath Parser context
5862 * @nargs: the number of arguments
5864 * Implement the position() XPath function
5866 * The position function returns the position of the context node in the
5867 * context node list. The first position is 1, and so the last position
5868 * will be equal to last().
5871 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5873 if (ctxt->context->proximityPosition >= 0) {
5875 xmlXPathNewFloat((double) ctxt->context->proximityPosition));
5877 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
5878 ctxt->context->proximityPosition);
5881 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
5886 * xmlXPathCountFunction:
5887 * @ctxt: the XPath Parser context
5888 * @nargs: the number of arguments
5890 * Implement the count() XPath function
5891 * number count(node-set)
5894 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
5895 xmlXPathObjectPtr cur;
5898 if ((ctxt->value == NULL) ||
5899 ((ctxt->value->type != XPATH_NODESET) &&
5900 (ctxt->value->type != XPATH_XSLT_TREE)))
5901 XP_ERROR(XPATH_INVALID_TYPE);
5902 cur = valuePop(ctxt);
5904 if ((cur == NULL) || (cur->nodesetval == NULL))
5905 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5906 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
5907 valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
5909 if ((cur->nodesetval->nodeNr != 1) ||
5910 (cur->nodesetval->nodeTab == NULL)) {
5911 valuePush(ctxt, xmlXPathNewFloat((double) 0));
5916 tmp = cur->nodesetval->nodeTab[0];
5918 tmp = tmp->children;
5919 while (tmp != NULL) {
5924 valuePush(ctxt, xmlXPathNewFloat((double) i));
5927 xmlXPathFreeObject(cur);
5931 * xmlXPathGetElementsByIds:
5932 * @doc: the document
5933 * @ids: a whitespace separated list of IDs
5935 * Selects elements by their unique ID.
5937 * Returns a node-set of selected elements.
5939 static xmlNodeSetPtr
5940 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
5942 const xmlChar *cur = ids;
5945 xmlNodePtr elem = NULL;
5947 if (ids == NULL) return(NULL);
5949 ret = xmlXPathNodeSetCreate(NULL);
5951 while (IS_BLANK(*cur)) cur++;
5953 while ((!IS_BLANK(*cur)) && (*cur != 0))
5956 ID = xmlStrndup(ids, cur - ids);
5958 if (xmlValidateNCName(ID, 1) == 0) {
5959 attr = xmlGetID(doc, ID);
5961 if (attr->type == XML_ATTRIBUTE_NODE)
5962 elem = attr->parent;
5963 else if (attr->type == XML_ELEMENT_NODE)
5964 elem = (xmlNodePtr) attr;
5968 xmlXPathNodeSetAdd(ret, elem);
5974 while (IS_BLANK(*cur)) cur++;
5981 * xmlXPathIdFunction:
5982 * @ctxt: the XPath Parser context
5983 * @nargs: the number of arguments
5985 * Implement the id() XPath function
5986 * node-set id(object)
5987 * The id function selects elements by their unique ID
5988 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
5989 * then the result is the union of the result of applying id to the
5990 * string value of each of the nodes in the argument node-set. When the
5991 * argument to id is of any other type, the argument is converted to a
5992 * string as if by a call to the string function; the string is split
5993 * into a whitespace-separated list of tokens (whitespace is any sequence
5994 * of characters matching the production S); the result is a node-set
5995 * containing the elements in the same document as the context node that
5996 * have a unique ID equal to any of the tokens in the list.
5999 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6002 xmlXPathObjectPtr obj;
6005 obj = valuePop(ctxt);
6006 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6007 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
6011 ret = xmlXPathNodeSetCreate(NULL);
6013 if (obj->nodesetval != NULL) {
6014 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
6016 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
6017 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
6018 ret = xmlXPathNodeSetMerge(ret, ns);
6019 xmlXPathFreeNodeSet(ns);
6025 xmlXPathFreeObject(obj);
6026 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6029 obj = xmlXPathConvertString(obj);
6031 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
6032 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
6034 xmlXPathFreeObject(obj);
6039 * xmlXPathLocalNameFunction:
6040 * @ctxt: the XPath Parser context
6041 * @nargs: the number of arguments
6043 * Implement the local-name() XPath function
6044 * string local-name(node-set?)
6045 * The local-name function returns a string containing the local part
6046 * of the name of the node in the argument node-set that is first in
6047 * document order. If the node-set is empty or the first node has no
6048 * name, an empty string is returned. If the argument is omitted it
6049 * defaults to the context node.
6052 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6053 xmlXPathObjectPtr cur;
6056 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6061 if ((ctxt->value == NULL) ||
6062 ((ctxt->value->type != XPATH_NODESET) &&
6063 (ctxt->value->type != XPATH_XSLT_TREE)))
6064 XP_ERROR(XPATH_INVALID_TYPE);
6065 cur = valuePop(ctxt);
6067 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6068 valuePush(ctxt, xmlXPathNewCString(""));
6070 int i = 0; /* Should be first in document order !!!!! */
6071 switch (cur->nodesetval->nodeTab[i]->type) {
6072 case XML_ELEMENT_NODE:
6073 case XML_ATTRIBUTE_NODE:
6075 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6076 valuePush(ctxt, xmlXPathNewCString(""));
6079 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6081 case XML_NAMESPACE_DECL:
6082 valuePush(ctxt, xmlXPathNewString(
6083 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
6086 valuePush(ctxt, xmlXPathNewCString(""));
6089 xmlXPathFreeObject(cur);
6093 * xmlXPathNamespaceURIFunction:
6094 * @ctxt: the XPath Parser context
6095 * @nargs: the number of arguments
6097 * Implement the namespace-uri() XPath function
6098 * string namespace-uri(node-set?)
6099 * The namespace-uri function returns a string containing the
6100 * namespace URI of the expanded name of the node in the argument
6101 * node-set that is first in document order. If the node-set is empty,
6102 * the first node has no name, or the expanded name has no namespace
6103 * URI, an empty string is returned. If the argument is omitted it
6104 * defaults to the context node.
6107 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6108 xmlXPathObjectPtr cur;
6111 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6115 if ((ctxt->value == NULL) ||
6116 ((ctxt->value->type != XPATH_NODESET) &&
6117 (ctxt->value->type != XPATH_XSLT_TREE)))
6118 XP_ERROR(XPATH_INVALID_TYPE);
6119 cur = valuePop(ctxt);
6121 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6122 valuePush(ctxt, xmlXPathNewCString(""));
6124 int i = 0; /* Should be first in document order !!!!! */
6125 switch (cur->nodesetval->nodeTab[i]->type) {
6126 case XML_ELEMENT_NODE:
6127 case XML_ATTRIBUTE_NODE:
6128 if (cur->nodesetval->nodeTab[i]->ns == NULL)
6129 valuePush(ctxt, xmlXPathNewCString(""));
6131 valuePush(ctxt, xmlXPathNewString(
6132 cur->nodesetval->nodeTab[i]->ns->href));
6135 valuePush(ctxt, xmlXPathNewCString(""));
6138 xmlXPathFreeObject(cur);
6142 * xmlXPathNameFunction:
6143 * @ctxt: the XPath Parser context
6144 * @nargs: the number of arguments
6146 * Implement the name() XPath function
6147 * string name(node-set?)
6148 * The name function returns a string containing a QName representing
6149 * the name of the node in the argument node-set that is first in document
6150 * order. The QName must represent the name with respect to the namespace
6151 * declarations in effect on the node whose name is being represented.
6152 * Typically, this will be the form in which the name occurred in the XML
6153 * source. This need not be the case if there are namespace declarations
6154 * in effect on the node that associate multiple prefixes with the same
6155 * namespace. However, an implementation may include information about
6156 * the original prefix in its representation of nodes; in this case, an
6157 * implementation can ensure that the returned string is always the same
6158 * as the QName used in the XML source. If the argument it omitted it
6159 * defaults to the context node.
6160 * Libxml keep the original prefix so the "real qualified name" used is
6164 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
6166 xmlXPathObjectPtr cur;
6169 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
6174 if ((ctxt->value == NULL) ||
6175 ((ctxt->value->type != XPATH_NODESET) &&
6176 (ctxt->value->type != XPATH_XSLT_TREE)))
6177 XP_ERROR(XPATH_INVALID_TYPE);
6178 cur = valuePop(ctxt);
6180 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6181 valuePush(ctxt, xmlXPathNewCString(""));
6183 int i = 0; /* Should be first in document order !!!!! */
6185 switch (cur->nodesetval->nodeTab[i]->type) {
6186 case XML_ELEMENT_NODE:
6187 case XML_ATTRIBUTE_NODE:
6188 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
6189 valuePush(ctxt, xmlXPathNewCString(""));
6190 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
6191 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
6193 xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
6198 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
6199 cur->nodesetval->nodeTab[i]->ns->prefix,
6201 if (fullname == cur->nodesetval->nodeTab[i]->name)
6202 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
6203 if (fullname == NULL) {
6204 XP_ERROR(XPATH_MEMORY_ERROR);
6206 valuePush(ctxt, xmlXPathWrapString(fullname));
6211 xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
6212 xmlXPathLocalNameFunction(ctxt, 1);
6215 xmlXPathFreeObject(cur);
6220 * xmlXPathStringFunction:
6221 * @ctxt: the XPath Parser context
6222 * @nargs: the number of arguments
6224 * Implement the string() XPath function
6225 * string string(object?)
6226 * he string function converts an object to a string as follows:
6227 * - A node-set is converted to a string by returning the value of
6228 * the node in the node-set that is first in document order.
6229 * If the node-set is empty, an empty string is returned.
6230 * - A number is converted to a string as follows
6231 * + NaN is converted to the string NaN
6232 * + positive zero is converted to the string 0
6233 * + negative zero is converted to the string 0
6234 * + positive infinity is converted to the string Infinity
6235 * + negative infinity is converted to the string -Infinity
6236 * + if the number is an integer, the number is represented in
6237 * decimal form as a Number with no decimal point and no leading
6238 * zeros, preceded by a minus sign (-) if the number is negative
6239 * + otherwise, the number is represented in decimal form as a
6240 * Number including a decimal point with at least one digit
6241 * before the decimal point and at least one digit after the
6242 * decimal point, preceded by a minus sign (-) if the number
6243 * is negative; there must be no leading zeros before the decimal
6244 * point apart possibly from the one required digit immediately
6245 * before the decimal point; beyond the one required digit
6246 * after the decimal point there must be as many, but only as
6247 * many, more digits as are needed to uniquely distinguish the
6248 * number from all other IEEE 754 numeric values.
6249 * - The boolean false value is converted to the string false.
6250 * The boolean true value is converted to the string true.
6252 * If the argument is omitted, it defaults to a node-set with the
6253 * context node as its only member.
6256 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6257 xmlXPathObjectPtr cur;
6262 xmlXPathCastNodeToString(ctxt->context->node)));
6267 cur = valuePop(ctxt);
6268 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6269 cur = xmlXPathConvertString(cur);
6270 valuePush(ctxt, cur);
6274 * xmlXPathStringLengthFunction:
6275 * @ctxt: the XPath Parser context
6276 * @nargs: the number of arguments
6278 * Implement the string-length() XPath function
6279 * number string-length(string?)
6280 * The string-length returns the number of characters in the string
6281 * (see [3.6 Strings]). If the argument is omitted, it defaults to
6282 * the context node converted to a string, in other words the value
6283 * of the context node.
6286 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6287 xmlXPathObjectPtr cur;
6290 if (ctxt->context->node == NULL) {
6291 valuePush(ctxt, xmlXPathNewFloat(0));
6295 content = xmlXPathCastNodeToString(ctxt->context->node);
6296 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(content)));
6303 CHECK_TYPE(XPATH_STRING);
6304 cur = valuePop(ctxt);
6305 valuePush(ctxt, xmlXPathNewFloat(xmlUTF8Strlen(cur->stringval)));
6306 xmlXPathFreeObject(cur);
6310 * xmlXPathConcatFunction:
6311 * @ctxt: the XPath Parser context
6312 * @nargs: the number of arguments
6314 * Implement the concat() XPath function
6315 * string concat(string, string, string*)
6316 * The concat function returns the concatenation of its arguments.
6319 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6320 xmlXPathObjectPtr cur, newobj;
6328 cur = valuePop(ctxt);
6329 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
6330 xmlXPathFreeObject(cur);
6337 newobj = valuePop(ctxt);
6338 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
6339 xmlXPathFreeObject(newobj);
6340 xmlXPathFreeObject(cur);
6341 XP_ERROR(XPATH_INVALID_TYPE);
6343 tmp = xmlStrcat(newobj->stringval, cur->stringval);
6344 newobj->stringval = cur->stringval;
6345 cur->stringval = tmp;
6347 xmlXPathFreeObject(newobj);
6350 valuePush(ctxt, cur);
6354 * xmlXPathContainsFunction:
6355 * @ctxt: the XPath Parser context
6356 * @nargs: the number of arguments
6358 * Implement the contains() XPath function
6359 * boolean contains(string, string)
6360 * The contains function returns true if the first argument string
6361 * contains the second argument string, and otherwise returns false.
6364 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6365 xmlXPathObjectPtr hay, needle;
6369 CHECK_TYPE(XPATH_STRING);
6370 needle = valuePop(ctxt);
6372 hay = valuePop(ctxt);
6373 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6374 xmlXPathFreeObject(hay);
6375 xmlXPathFreeObject(needle);
6376 XP_ERROR(XPATH_INVALID_TYPE);
6378 if (xmlStrstr(hay->stringval, needle->stringval))
6379 valuePush(ctxt, xmlXPathNewBoolean(1));
6381 valuePush(ctxt, xmlXPathNewBoolean(0));
6382 xmlXPathFreeObject(hay);
6383 xmlXPathFreeObject(needle);
6387 * xmlXPathStartsWithFunction:
6388 * @ctxt: the XPath Parser context
6389 * @nargs: the number of arguments
6391 * Implement the starts-with() XPath function
6392 * boolean starts-with(string, string)
6393 * The starts-with function returns true if the first argument string
6394 * starts with the second argument string, and otherwise returns false.
6397 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6398 xmlXPathObjectPtr hay, needle;
6403 CHECK_TYPE(XPATH_STRING);
6404 needle = valuePop(ctxt);
6406 hay = valuePop(ctxt);
6407 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
6408 xmlXPathFreeObject(hay);
6409 xmlXPathFreeObject(needle);
6410 XP_ERROR(XPATH_INVALID_TYPE);
6412 n = xmlStrlen(needle->stringval);
6413 if (xmlStrncmp(hay->stringval, needle->stringval, n))
6414 valuePush(ctxt, xmlXPathNewBoolean(0));
6416 valuePush(ctxt, xmlXPathNewBoolean(1));
6417 xmlXPathFreeObject(hay);
6418 xmlXPathFreeObject(needle);
6422 * xmlXPathSubstringFunction:
6423 * @ctxt: the XPath Parser context
6424 * @nargs: the number of arguments
6426 * Implement the substring() XPath function
6427 * string substring(string, number, number?)
6428 * The substring function returns the substring of the first argument
6429 * starting at the position specified in the second argument with
6430 * length specified in the third argument. For example,
6431 * substring("12345",2,3) returns "234". If the third argument is not
6432 * specified, it returns the substring starting at the position specified
6433 * in the second argument and continuing to the end of the string. For
6434 * example, substring("12345",2) returns "2345". More precisely, each
6435 * character in the string (see [3.6 Strings]) is considered to have a
6436 * numeric position: the position of the first character is 1, the position
6437 * of the second character is 2 and so on. The returned substring contains
6438 * those characters for which the position of the character is greater than
6439 * or equal to the second argument and, if the third argument is specified,
6440 * less than the sum of the second and third arguments; the comparisons
6441 * and addition used for the above follow the standard IEEE 754 rules. Thus:
6442 * - substring("12345", 1.5, 2.6) returns "234"
6443 * - substring("12345", 0, 3) returns "12"
6444 * - substring("12345", 0 div 0, 3) returns ""
6445 * - substring("12345", 1, 0 div 0) returns ""
6446 * - substring("12345", -42, 1 div 0) returns "12345"
6447 * - substring("12345", -1 div 0, 1 div 0) returns ""
6450 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6451 xmlXPathObjectPtr str, start, len;
6463 * take care of possible last (position) argument
6467 CHECK_TYPE(XPATH_NUMBER);
6468 len = valuePop(ctxt);
6470 xmlXPathFreeObject(len);
6474 CHECK_TYPE(XPATH_NUMBER);
6475 start = valuePop(ctxt);
6476 in = start->floatval;
6477 xmlXPathFreeObject(start);
6479 CHECK_TYPE(XPATH_STRING);
6480 str = valuePop(ctxt);
6481 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
6484 * If last pos not present, calculate last position
6492 /* Need to check for the special cases where either
6493 * the index is NaN, the length is NaN, or both
6494 * arguments are infinity (relying on Inf + -Inf = NaN)
6496 if (!xmlXPathIsNaN(in + le) && !xmlXPathIsInf(in)) {
6498 * To meet the requirements of the spec, the arguments
6499 * must be converted to integer format before
6500 * initial index calculations are done
6502 * First we go to integer form, rounding up
6503 * and checking for special cases
6506 if (((double)i)+0.5 <= in) i++;
6508 if (xmlXPathIsInf(le) == 1) {
6513 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
6517 if (((double)l)+0.5 <= le) l++;
6520 /* Now we normalize inidices */
6528 /* number of chars to copy */
6531 ret = xmlUTF8Strsub(str->stringval, i, l);
6538 valuePush(ctxt, xmlXPathNewCString(""));
6540 valuePush(ctxt, xmlXPathNewString(ret));
6544 xmlXPathFreeObject(str);
6548 * xmlXPathSubstringBeforeFunction:
6549 * @ctxt: the XPath Parser context
6550 * @nargs: the number of arguments
6552 * Implement the substring-before() XPath function
6553 * string substring-before(string, string)
6554 * The substring-before function returns the substring of the first
6555 * argument string that precedes the first occurrence of the second
6556 * argument string in the first argument string, or the empty string
6557 * if the first argument string does not contain the second argument
6558 * string. For example, substring-before("1999/04/01","/") returns 1999.
6561 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6562 xmlXPathObjectPtr str;
6563 xmlXPathObjectPtr find;
6564 xmlBufferPtr target;
6565 const xmlChar *point;
6570 find = valuePop(ctxt);
6572 str = valuePop(ctxt);
6574 target = xmlBufferCreate();
6576 point = xmlStrstr(str->stringval, find->stringval);
6578 offset = (int)(point - str->stringval);
6579 xmlBufferAdd(target, str->stringval, offset);
6581 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6582 xmlBufferFree(target);
6585 xmlXPathFreeObject(str);
6586 xmlXPathFreeObject(find);
6590 * xmlXPathSubstringAfterFunction:
6591 * @ctxt: the XPath Parser context
6592 * @nargs: the number of arguments
6594 * Implement the substring-after() XPath function
6595 * string substring-after(string, string)
6596 * The substring-after function returns the substring of the first
6597 * argument string that follows the first occurrence of the second
6598 * argument string in the first argument string, or the empty stringi
6599 * if the first argument string does not contain the second argument
6600 * string. For example, substring-after("1999/04/01","/") returns 04/01,
6601 * and substring-after("1999/04/01","19") returns 99/04/01.
6604 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6605 xmlXPathObjectPtr str;
6606 xmlXPathObjectPtr find;
6607 xmlBufferPtr target;
6608 const xmlChar *point;
6613 find = valuePop(ctxt);
6615 str = valuePop(ctxt);
6617 target = xmlBufferCreate();
6619 point = xmlStrstr(str->stringval, find->stringval);
6621 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
6622 xmlBufferAdd(target, &str->stringval[offset],
6623 xmlStrlen(str->stringval) - offset);
6625 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6626 xmlBufferFree(target);
6629 xmlXPathFreeObject(str);
6630 xmlXPathFreeObject(find);
6634 * xmlXPathNormalizeFunction:
6635 * @ctxt: the XPath Parser context
6636 * @nargs: the number of arguments
6638 * Implement the normalize-space() XPath function
6639 * string normalize-space(string?)
6640 * The normalize-space function returns the argument string with white
6641 * space normalized by stripping leading and trailing whitespace
6642 * and replacing sequences of whitespace characters by a single
6643 * space. Whitespace characters are the same allowed by the S production
6644 * in XML. If the argument is omitted, it defaults to the context
6645 * node converted to a string, in other words the value of the context node.
6648 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6649 xmlXPathObjectPtr obj = NULL;
6650 xmlChar *source = NULL;
6651 xmlBufferPtr target;
6655 /* Use current context node */
6658 xmlXPathCastNodeToString(ctxt->context->node)));
6664 CHECK_TYPE(XPATH_STRING);
6665 obj = valuePop(ctxt);
6666 source = obj->stringval;
6668 target = xmlBufferCreate();
6669 if (target && source) {
6671 /* Skip leading whitespaces */
6672 while (IS_BLANK(*source))
6675 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
6678 if (IS_BLANK(*source)) {
6682 xmlBufferAdd(target, &blank, 1);
6685 xmlBufferAdd(target, source, 1);
6690 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6691 xmlBufferFree(target);
6693 xmlXPathFreeObject(obj);
6697 * xmlXPathTranslateFunction:
6698 * @ctxt: the XPath Parser context
6699 * @nargs: the number of arguments
6701 * Implement the translate() XPath function
6702 * string translate(string, string, string)
6703 * The translate function returns the first argument string with
6704 * occurrences of characters in the second argument string replaced
6705 * by the character at the corresponding position in the third argument
6706 * string. For example, translate("bar","abc","ABC") returns the string
6707 * BAr. If there is a character in the second argument string with no
6708 * character at a corresponding position in the third argument string
6709 * (because the second argument string is longer than the third argument
6710 * string), then occurrences of that character in the first argument
6711 * string are removed. For example, translate("--aaa--","abc-","ABC")
6712 * returns "AAA". If a character occurs more than once in second
6713 * argument string, then the first occurrence determines the replacement
6714 * character. If the third argument string is longer than the second
6715 * argument string, then excess characters are ignored.
6718 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6719 xmlXPathObjectPtr str;
6720 xmlXPathObjectPtr from;
6721 xmlXPathObjectPtr to;
6722 xmlBufferPtr target;
6731 to = valuePop(ctxt);
6733 from = valuePop(ctxt);
6735 str = valuePop(ctxt);
6737 target = xmlBufferCreate();
6739 max = xmlUTF8Strlen(to->stringval);
6740 for (cptr = str->stringval; (ch=*cptr); ) {
6741 offset = xmlUTF8Strloc(from->stringval, cptr);
6744 point = xmlUTF8Strpos(to->stringval, offset);
6746 xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
6749 xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
6751 /* Step to next character in input */
6754 /* if not simple ascii, verify proper format */
6755 if ( (ch & 0xc0) != 0xc0 ) {
6756 xmlGenericError(xmlGenericErrorContext,
6757 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6760 /* then skip over remaining bytes for this char */
6761 while ( (ch <<= 1) & 0x80 )
6762 if ( (*cptr++ & 0xc0) != 0x80 ) {
6763 xmlGenericError(xmlGenericErrorContext,
6764 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
6767 if (ch & 0x80) /* must have had error encountered */
6772 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
6773 xmlBufferFree(target);
6774 xmlXPathFreeObject(str);
6775 xmlXPathFreeObject(from);
6776 xmlXPathFreeObject(to);
6780 * xmlXPathBooleanFunction:
6781 * @ctxt: the XPath Parser context
6782 * @nargs: the number of arguments
6784 * Implement the boolean() XPath function
6785 * boolean boolean(object)
6786 * he boolean function converts its argument to a boolean as follows:
6787 * - a number is true if and only if it is neither positive or
6788 * negative zero nor NaN
6789 * - a node-set is true if and only if it is non-empty
6790 * - a string is true if and only if its length is non-zero
6793 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6794 xmlXPathObjectPtr cur;
6797 cur = valuePop(ctxt);
6798 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
6799 cur = xmlXPathConvertBoolean(cur);
6800 valuePush(ctxt, cur);
6804 * xmlXPathNotFunction:
6805 * @ctxt: the XPath Parser context
6806 * @nargs: the number of arguments
6808 * Implement the not() XPath function
6809 * boolean not(boolean)
6810 * The not function returns true if its argument is false,
6811 * and false otherwise.
6814 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6817 CHECK_TYPE(XPATH_BOOLEAN);
6818 ctxt->value->boolval = ! ctxt->value->boolval;
6822 * xmlXPathTrueFunction:
6823 * @ctxt: the XPath Parser context
6824 * @nargs: the number of arguments
6826 * Implement the true() XPath function
6830 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6832 valuePush(ctxt, xmlXPathNewBoolean(1));
6836 * xmlXPathFalseFunction:
6837 * @ctxt: the XPath Parser context
6838 * @nargs: the number of arguments
6840 * Implement the false() XPath function
6844 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6846 valuePush(ctxt, xmlXPathNewBoolean(0));
6850 * xmlXPathLangFunction:
6851 * @ctxt: the XPath Parser context
6852 * @nargs: the number of arguments
6854 * Implement the lang() XPath function
6855 * boolean lang(string)
6856 * The lang function returns true or false depending on whether the
6857 * language of the context node as specified by xml:lang attributes
6858 * is the same as or is a sublanguage of the language specified by
6859 * the argument string. The language of the context node is determined
6860 * by the value of the xml:lang attribute on the context node, or, if
6861 * the context node has no xml:lang attribute, by the value of the
6862 * xml:lang attribute on the nearest ancestor of the context node that
6863 * has an xml:lang attribute. If there is no such attribute, then lang
6864 * returns false. If there is such an attribute, then lang returns
6865 * true if the attribute value is equal to the argument ignoring case,
6866 * or if there is some suffix starting with - such that the attribute
6867 * value is equal to the argument ignoring that suffix of the attribute
6868 * value and ignoring case.
6871 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6872 xmlXPathObjectPtr val;
6873 const xmlChar *theLang;
6874 const xmlChar *lang;
6880 CHECK_TYPE(XPATH_STRING);
6881 val = valuePop(ctxt);
6882 lang = val->stringval;
6883 theLang = xmlNodeGetLang(ctxt->context->node);
6884 if ((theLang != NULL) && (lang != NULL)) {
6885 for (i = 0;lang[i] != 0;i++)
6886 if (toupper(lang[i]) != toupper(theLang[i]))
6891 xmlXPathFreeObject(val);
6892 valuePush(ctxt, xmlXPathNewBoolean(ret));
6896 * xmlXPathNumberFunction:
6897 * @ctxt: the XPath Parser context
6898 * @nargs: the number of arguments
6900 * Implement the number() XPath function
6901 * number number(object?)
6904 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6905 xmlXPathObjectPtr cur;
6909 if (ctxt->context->node == NULL) {
6910 valuePush(ctxt, xmlXPathNewFloat(0.0));
6912 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
6914 res = xmlXPathStringEvalNumber(content);
6915 valuePush(ctxt, xmlXPathNewFloat(res));
6922 cur = valuePop(ctxt);
6923 cur = xmlXPathConvertNumber(cur);
6924 valuePush(ctxt, cur);
6928 * xmlXPathSumFunction:
6929 * @ctxt: the XPath Parser context
6930 * @nargs: the number of arguments
6932 * Implement the sum() XPath function
6933 * number sum(node-set)
6934 * The sum function returns the sum of the values of the nodes in
6935 * the argument node-set.
6938 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6939 xmlXPathObjectPtr cur;
6944 if ((ctxt->value == NULL) ||
6945 ((ctxt->value->type != XPATH_NODESET) &&
6946 (ctxt->value->type != XPATH_XSLT_TREE)))
6947 XP_ERROR(XPATH_INVALID_TYPE);
6948 cur = valuePop(ctxt);
6950 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
6951 valuePush(ctxt, xmlXPathNewFloat(0.0));
6953 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
6954 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
6956 valuePush(ctxt, xmlXPathNewFloat(res));
6958 xmlXPathFreeObject(cur);
6962 * xmlXPathFloorFunction:
6963 * @ctxt: the XPath Parser context
6964 * @nargs: the number of arguments
6966 * Implement the floor() XPath function
6967 * number floor(number)
6968 * The floor function returns the largest (closest to positive infinity)
6969 * number that is not greater than the argument and that is an integer.
6972 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
6977 CHECK_TYPE(XPATH_NUMBER);
6979 f = (double)((int) ctxt->value->floatval);
6980 if (f != ctxt->value->floatval) {
6981 if (ctxt->value->floatval > 0)
6982 ctxt->value->floatval = f;
6984 ctxt->value->floatval = f - 1;
6989 * xmlXPathCeilingFunction:
6990 * @ctxt: the XPath Parser context
6991 * @nargs: the number of arguments
6993 * Implement the ceiling() XPath function
6994 * number ceiling(number)
6995 * The ceiling function returns the smallest (closest to negative infinity)
6996 * number that is not less than the argument and that is an integer.
6999 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7004 CHECK_TYPE(XPATH_NUMBER);
7007 ctxt->value->floatval = ceil(ctxt->value->floatval);
7009 f = (double)((int) ctxt->value->floatval);
7010 if (f != ctxt->value->floatval) {
7011 if (ctxt->value->floatval > 0)
7012 ctxt->value->floatval = f + 1;
7014 if (ctxt->value->floatval < 0 && f == 0)
7015 ctxt->value->floatval = xmlXPathNZERO;
7017 ctxt->value->floatval = f;
7025 * xmlXPathRoundFunction:
7026 * @ctxt: the XPath Parser context
7027 * @nargs: the number of arguments
7029 * Implement the round() XPath function
7030 * number round(number)
7031 * The round function returns the number that is closest to the
7032 * argument and that is an integer. If there are two such numbers,
7033 * then the one that is even is returned.
7036 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
7041 CHECK_TYPE(XPATH_NUMBER);
7043 if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
7044 (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
7045 (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
7046 (ctxt->value->floatval == 0.0))
7049 f = (double)((int) ctxt->value->floatval);
7050 if (ctxt->value->floatval < 0) {
7051 if (ctxt->value->floatval < f - 0.5)
7052 ctxt->value->floatval = f - 1;
7054 ctxt->value->floatval = f;
7055 if (ctxt->value->floatval == 0)
7056 ctxt->value->floatval = xmlXPathNZERO;
7058 if (ctxt->value->floatval < f + 0.5)
7059 ctxt->value->floatval = f;
7061 ctxt->value->floatval = f + 1;
7065 /************************************************************************
7069 ************************************************************************/
7072 * a couple of forward declarations since we use a recursive call based
7075 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt);
7076 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
7077 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
7078 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
7079 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
7083 * xmlXPathCurrentChar:
7084 * @ctxt: the XPath parser context
7085 * @cur: pointer to the beginning of the char
7086 * @len: pointer to the length of the char read
7088 * The current char value, if using UTF-8 this may actually span multiple
7089 * bytes in the input buffer.
7091 * Returns the current char value and its length
7095 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
7105 * We are supposed to handle UTF8, check it's valid
7106 * From rfc2044: encoding of the Unicode values on UTF-8:
7108 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
7109 * 0000 0000-0000 007F 0xxxxxxx
7110 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
7111 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
7113 * Check for the 0x110000 limit too
7117 if ((cur[1] & 0xc0) != 0x80)
7118 goto encoding_error;
7119 if ((c & 0xe0) == 0xe0) {
7121 if ((cur[2] & 0xc0) != 0x80)
7122 goto encoding_error;
7123 if ((c & 0xf0) == 0xf0) {
7124 if (((c & 0xf8) != 0xf0) ||
7125 ((cur[3] & 0xc0) != 0x80))
7126 goto encoding_error;
7129 val = (cur[0] & 0x7) << 18;
7130 val |= (cur[1] & 0x3f) << 12;
7131 val |= (cur[2] & 0x3f) << 6;
7132 val |= cur[3] & 0x3f;
7136 val = (cur[0] & 0xf) << 12;
7137 val |= (cur[1] & 0x3f) << 6;
7138 val |= cur[2] & 0x3f;
7143 val = (cur[0] & 0x1f) << 6;
7144 val |= cur[1] & 0x3f;
7146 if (!IS_CHAR(val)) {
7147 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
7157 * If we detect an UTF8 error that probably mean that the
7158 * input encoding didn't get properly advertized in the
7159 * declaration header. Report the error and switch the encoding
7160 * to ISO-Latin-1 (if you don't like this policy, just declare the
7164 XP_ERROR0(XPATH_ENCODING_ERROR);
7168 * xmlXPathParseNCName:
7169 * @ctxt: the XPath Parser context
7171 * parse an XML namespace non qualified name.
7173 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
7175 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
7176 * CombiningChar | Extender
7178 * Returns the namespace name or NULL
7182 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
7188 * Accelerator for simple ASCII names
7191 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7192 ((*in >= 0x41) && (*in <= 0x5A)) ||
7195 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7196 ((*in >= 0x41) && (*in <= 0x5A)) ||
7197 ((*in >= 0x30) && (*in <= 0x39)) ||
7198 (*in == '_') || (*in == '.') ||
7201 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
7202 (*in == '[') || (*in == ']') || (*in == ':') ||
7203 (*in == '@') || (*in == '*')) {
7204 count = in - ctxt->cur;
7207 ret = xmlStrndup(ctxt->cur, count);
7212 return(xmlXPathParseNameComplex(ctxt, 0));
7217 * xmlXPathParseQName:
7218 * @ctxt: the XPath Parser context
7219 * @prefix: a xmlChar **
7221 * parse an XML qualified name
7223 * [NS 5] QName ::= (Prefix ':')? LocalPart
7225 * [NS 6] Prefix ::= NCName
7227 * [NS 7] LocalPart ::= NCName
7229 * Returns the function returns the local part, and prefix is updated
7230 * to get the Prefix if any.
7234 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
7235 xmlChar *ret = NULL;
7238 ret = xmlXPathParseNCName(ctxt);
7242 ret = xmlXPathParseNCName(ctxt);
7248 * xmlXPathParseName:
7249 * @ctxt: the XPath Parser context
7253 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7254 * CombiningChar | Extender
7256 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7258 * Returns the namespace name or NULL
7262 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
7268 * Accelerator for simple ASCII names
7271 if (((*in >= 0x61) && (*in <= 0x7A)) ||
7272 ((*in >= 0x41) && (*in <= 0x5A)) ||
7273 (*in == '_') || (*in == ':')) {
7275 while (((*in >= 0x61) && (*in <= 0x7A)) ||
7276 ((*in >= 0x41) && (*in <= 0x5A)) ||
7277 ((*in >= 0x30) && (*in <= 0x39)) ||
7278 (*in == '_') || (*in == '-') ||
7279 (*in == ':') || (*in == '.'))
7281 if ((*in > 0) && (*in < 0x80)) {
7282 count = in - ctxt->cur;
7283 ret = xmlStrndup(ctxt->cur, count);
7288 return(xmlXPathParseNameComplex(ctxt, 1));
7292 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
7293 xmlChar buf[XML_MAX_NAMELEN + 5];
7298 * Handler for more complex cases
7301 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
7302 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
7303 (c == '*') || /* accelerators */
7304 (!IS_LETTER(c) && (c != '_') &&
7305 ((qualified) && (c != ':')))) {
7309 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
7310 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
7311 (c == '.') || (c == '-') ||
7312 (c == '_') || ((qualified) && (c == ':')) ||
7313 (IS_COMBINING(c)) ||
7314 (IS_EXTENDER(c)))) {
7315 COPY_BUF(l,buf,len,c);
7318 if (len >= XML_MAX_NAMELEN) {
7320 * Okay someone managed to make a huge name, so he's ready to pay
7321 * for the processing speed.
7326 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
7327 if (buffer == NULL) {
7328 XP_ERROR0(XPATH_MEMORY_ERROR);
7330 memcpy(buffer, buf, len);
7331 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
7332 (c == '.') || (c == '-') ||
7333 (c == '_') || ((qualified) && (c == ':')) ||
7334 (IS_COMBINING(c)) ||
7336 if (len + 10 > max) {
7338 buffer = (xmlChar *) xmlRealloc(buffer,
7339 max * sizeof(xmlChar));
7340 if (buffer == NULL) {
7341 XP_ERROR0(XPATH_MEMORY_ERROR);
7344 COPY_BUF(l,buffer,len,c);
7354 return(xmlStrndup(buf, len));
7359 static double my_pow10[MAX_FRAC] = {
7360 1.0, 10.0, 100.0, 1000.0, 10000.0,
7361 100000.0, 1000000.0, 10000000.0, 100000000.0, 1000000000.0,
7362 10000000000.0, 100000000000.0, 1000000000000.0, 10000000000000.0,
7364 1000000000000000.0, 10000000000000000.0, 100000000000000000.0,
7365 1000000000000000000.0, 10000000000000000000.0
7369 * xmlXPathStringEvalNumber:
7370 * @str: A string to scan
7372 * [30a] Float ::= Number ('e' Digits?)?
7374 * [30] Number ::= Digits ('.' Digits?)?
7376 * [31] Digits ::= [0-9]+
7378 * Compile a Number in the string
7379 * In complement of the Number expression, this function also handles
7380 * negative values : '-' Number.
7382 * Returns the double value.
7385 xmlXPathStringEvalNumber(const xmlChar *str) {
7386 const xmlChar *cur = str;
7391 int is_exponent_negative = 0;
7393 unsigned long tmp = 0;
7396 if (cur == NULL) return(0);
7397 while (IS_BLANK(*cur)) cur++;
7398 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
7399 return(xmlXPathNAN);
7408 * tmp/temp is a workaround against a gcc compiler bug
7409 * http://veillard.com/gcc.bug
7412 while ((*cur >= '0') && (*cur <= '9')) {
7417 temp = (double) tmp;
7422 while ((*cur >= '0') && (*cur <= '9')) {
7423 ret = ret * 10 + (*cur - '0');
7431 double fraction = 0;
7434 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
7435 return(xmlXPathNAN);
7437 while (((*cur >= '0') && (*cur <= '9')) && (frac < MAX_FRAC)) {
7439 fraction = fraction * 10 + v;
7443 fraction /= my_pow10[frac];
7444 ret = ret + fraction;
7445 while ((*cur >= '0') && (*cur <= '9'))
7448 if ((*cur == 'e') || (*cur == 'E')) {
7451 is_exponent_negative = 1;
7454 while ((*cur >= '0') && (*cur <= '9')) {
7455 exponent = exponent * 10 + (*cur - '0');
7459 while (IS_BLANK(*cur)) cur++;
7460 if (*cur != 0) return(xmlXPathNAN);
7461 if (isneg) ret = -ret;
7462 if (is_exponent_negative) exponent = -exponent;
7463 ret *= pow(10.0, (double)exponent);
7468 * xmlXPathCompNumber:
7469 * @ctxt: the XPath Parser context
7471 * [30] Number ::= Digits ('.' Digits?)?
7473 * [31] Digits ::= [0-9]+
7475 * Compile a Number, then push it on the stack
7479 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
7485 int is_exponent_negative = 0;
7487 unsigned long tmp = 0;
7492 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
7493 XP_ERROR(XPATH_NUMBER_ERROR);
7497 * tmp/temp is a workaround against a gcc compiler bug
7498 * http://veillard.com/gcc.bug
7501 while ((CUR >= '0') && (CUR <= '9')) {
7506 temp = (double) tmp;
7511 while ((CUR >= '0') && (CUR <= '9')) {
7512 ret = ret * 10 + (CUR - '0');
7519 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
7520 XP_ERROR(XPATH_NUMBER_ERROR);
7522 while ((CUR >= '0') && (CUR <= '9')) {
7524 ret = ret + (CUR - '0') * mult;
7528 if ((CUR == 'e') || (CUR == 'E')) {
7531 is_exponent_negative = 1;
7534 while ((CUR >= '0') && (CUR <= '9')) {
7535 exponent = exponent * 10 + (CUR - '0');
7538 if (is_exponent_negative)
7539 exponent = -exponent;
7540 ret *= pow(10.0, (double) exponent);
7542 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
7543 xmlXPathNewFloat(ret), NULL);
7547 * xmlXPathParseLiteral:
7548 * @ctxt: the XPath Parser context
7552 * [29] Literal ::= '"' [^"]* '"'
7555 * Returns the value found or NULL in case of error
7558 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
7560 xmlChar *ret = NULL;
7565 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
7567 if (!IS_CHAR((unsigned int) CUR)) {
7568 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7570 ret = xmlStrndup(q, CUR_PTR - q);
7573 } else if (CUR == '\'') {
7576 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
7578 if (!IS_CHAR((unsigned int) CUR)) {
7579 XP_ERROR0(XPATH_UNFINISHED_LITERAL_ERROR);
7581 ret = xmlStrndup(q, CUR_PTR - q);
7585 XP_ERROR0(XPATH_START_LITERAL_ERROR);
7591 * xmlXPathCompLiteral:
7592 * @ctxt: the XPath Parser context
7594 * Parse a Literal and push it on the stack.
7596 * [29] Literal ::= '"' [^"]* '"'
7599 * TODO: xmlXPathCompLiteral memory allocation could be improved.
7602 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
7604 xmlChar *ret = NULL;
7609 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '"'))
7611 if (!IS_CHAR((unsigned int) CUR)) {
7612 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7614 ret = xmlStrndup(q, CUR_PTR - q);
7617 } else if (CUR == '\'') {
7620 while ((IS_CHAR((unsigned int) CUR)) && (CUR != '\''))
7622 if (!IS_CHAR((unsigned int) CUR)) {
7623 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
7625 ret = xmlStrndup(q, CUR_PTR - q);
7629 XP_ERROR(XPATH_START_LITERAL_ERROR);
7631 if (ret == NULL) return;
7632 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
7633 xmlXPathNewString(ret), NULL);
7638 * xmlXPathCompVariableReference:
7639 * @ctxt: the XPath Parser context
7641 * Parse a VariableReference, evaluate it and push it on the stack.
7643 * The variable bindings consist of a mapping from variable names
7644 * to variable values. The value of a variable is an object, which
7645 * of any of the types that are possible for the value of an expression,
7646 * and may also be of additional types not specified here.
7648 * Early evaluation is possible since:
7649 * The variable bindings [...] used to evaluate a subexpression are
7650 * always the same as those used to evaluate the containing expression.
7652 * [36] VariableReference ::= '$' QName
7655 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
7661 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7664 name = xmlXPathParseQName(ctxt, &prefix);
7666 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
7668 ctxt->comp->last = -1;
7669 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
7675 * xmlXPathIsNodeType:
7676 * @name: a name string
7678 * Is the name given a NodeType one.
7680 * [38] NodeType ::= 'comment'
7682 * | 'processing-instruction'
7685 * Returns 1 if true 0 otherwise
7688 xmlXPathIsNodeType(const xmlChar *name) {
7692 if (xmlStrEqual(name, BAD_CAST "node"))
7694 if (xmlStrEqual(name, BAD_CAST "text"))
7696 if (xmlStrEqual(name, BAD_CAST "comment"))
7698 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
7704 * xmlXPathCompFunctionCall:
7705 * @ctxt: the XPath Parser context
7707 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
7708 * [17] Argument ::= Expr
7710 * Compile a function call, the evaluation of all arguments are
7711 * pushed on the stack
7714 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
7719 name = xmlXPathParseQName(ctxt, &prefix);
7721 XP_ERROR(XPATH_EXPR_ERROR);
7726 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
7729 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
7734 XP_ERROR(XPATH_EXPR_ERROR);
7739 ctxt->comp->last = -1;
7742 int op1 = ctxt->comp->last;
7743 ctxt->comp->last = -1;
7744 xmlXPathCompileExpr(ctxt);
7746 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
7748 if (CUR == ')') break;
7750 XP_ERROR(XPATH_EXPR_ERROR);
7756 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
7763 * xmlXPathCompPrimaryExpr:
7764 * @ctxt: the XPath Parser context
7766 * [15] PrimaryExpr ::= VariableReference
7772 * Compile a primary expression.
7775 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
7777 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
7778 else if (CUR == '(') {
7781 xmlXPathCompileExpr(ctxt);
7784 XP_ERROR(XPATH_EXPR_ERROR);
7788 } else if (IS_DIGIT(CUR) || (CUR == '.' && IS_DIGIT(NXT(1)))) {
7789 xmlXPathCompNumber(ctxt);
7790 } else if ((CUR == '\'') || (CUR == '"')) {
7791 xmlXPathCompLiteral(ctxt);
7793 xmlXPathCompFunctionCall(ctxt);
7799 * xmlXPathCompFilterExpr:
7800 * @ctxt: the XPath Parser context
7802 * [20] FilterExpr ::= PrimaryExpr
7803 * | FilterExpr Predicate
7805 * Compile a filter expression.
7806 * Square brackets are used to filter expressions in the same way that
7807 * they are used in location paths. It is an error if the expression to
7808 * be filtered does not evaluate to a node-set. The context node list
7809 * used for evaluating the expression in square brackets is the node-set
7810 * to be filtered listed in document order.
7814 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
7815 xmlXPathCompPrimaryExpr(ctxt);
7819 while (CUR == '[') {
7820 xmlXPathCompPredicate(ctxt, 1);
7829 * @ctxt: the XPath Parser context
7831 * Trickery: parse an XML name but without consuming the input flow
7832 * Needed to avoid insanity in the parser state.
7834 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
7835 * CombiningChar | Extender
7837 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
7839 * [6] Names ::= Name (S Name)*
7841 * Returns the Name parsed or NULL
7845 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
7846 xmlChar buf[XML_MAX_NAMELEN];
7850 if (!IS_LETTER(CUR) && (CUR != '_') &&
7855 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7856 (NXT(len) == '.') || (NXT(len) == '-') ||
7857 (NXT(len) == '_') || (NXT(len) == ':') ||
7858 (IS_COMBINING(NXT(len))) ||
7859 (IS_EXTENDER(NXT(len)))) {
7860 buf[len] = NXT(len);
7862 if (len >= XML_MAX_NAMELEN) {
7863 xmlGenericError(xmlGenericErrorContext,
7864 "xmlScanName: reached XML_MAX_NAMELEN limit\n");
7865 while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
7866 (NXT(len) == '.') || (NXT(len) == '-') ||
7867 (NXT(len) == '_') || (NXT(len) == ':') ||
7868 (IS_COMBINING(NXT(len))) ||
7869 (IS_EXTENDER(NXT(len))))
7874 return(xmlStrndup(buf, len));
7878 * xmlXPathCompPathExpr:
7879 * @ctxt: the XPath Parser context
7881 * [19] PathExpr ::= LocationPath
7883 * | FilterExpr '/' RelativeLocationPath
7884 * | FilterExpr '//' RelativeLocationPath
7886 * Compile a path expression.
7887 * The / operator and // operators combine an arbitrary expression
7888 * and a relative location path. It is an error if the expression
7889 * does not evaluate to a node-set.
7890 * The / operator does composition in the same way as when / is
7891 * used in a location path. As in location paths, // is short for
7892 * /descendant-or-self::node()/.
7896 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
7897 int lc = 1; /* Should we branch to LocationPath ? */
7898 xmlChar *name = NULL; /* we may have to preparse a name to find out */
7901 if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
7902 (CUR == '\'') || (CUR == '"') || (CUR == '.' && IS_DIGIT(NXT(1)))) {
7904 } else if (CUR == '*') {
7905 /* relative or absolute location path */
7907 } else if (CUR == '/') {
7908 /* relative or absolute location path */
7910 } else if (CUR == '@') {
7911 /* relative abbreviated attribute location path */
7913 } else if (CUR == '.') {
7914 /* relative abbreviated attribute location path */
7918 * Problem is finding if we have a name here whether it's:
7920 * - a function call in which case it's followed by '('
7921 * - an axis in which case it's followed by ':'
7923 * We do an a priori analysis here rather than having to
7924 * maintain parsed token content through the recursive function
7925 * calls. This looks uglier but makes the code quite easier to
7929 name = xmlXPathScanName(ctxt);
7930 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
7932 xmlGenericError(xmlGenericErrorContext,
7933 "PathExpr: Axis\n");
7937 } else if (name != NULL) {
7938 int len =xmlStrlen(name);
7941 while (NXT(len) != 0) {
7942 if (NXT(len) == '/') {
7945 xmlGenericError(xmlGenericErrorContext,
7946 "PathExpr: AbbrRelLocation\n");
7950 } else if (IS_BLANK(NXT(len))) {
7953 } else if (NXT(len) == ':') {
7955 xmlGenericError(xmlGenericErrorContext,
7956 "PathExpr: AbbrRelLocation\n");
7960 } else if ((NXT(len) == '(')) {
7961 /* Note Type or Function */
7962 if (xmlXPathIsNodeType(name)) {
7964 xmlGenericError(xmlGenericErrorContext,
7965 "PathExpr: Type search\n");
7970 xmlGenericError(xmlGenericErrorContext,
7971 "PathExpr: function call\n");
7976 } else if ((NXT(len) == '[')) {
7979 xmlGenericError(xmlGenericErrorContext,
7980 "PathExpr: AbbrRelLocation\n");
7984 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
7985 (NXT(len) == '=')) {
7994 if (NXT(len) == 0) {
7996 xmlGenericError(xmlGenericErrorContext,
7997 "PathExpr: AbbrRelLocation\n");
8004 /* make sure all cases are covered explicitely */
8005 XP_ERROR(XPATH_EXPR_ERROR);
8011 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
8013 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8015 xmlXPathCompLocationPath(ctxt);
8017 xmlXPathCompFilterExpr(ctxt);
8019 if ((CUR == '/') && (NXT(1) == '/')) {
8023 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8024 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8025 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
8027 xmlXPathCompRelativeLocationPath(ctxt);
8028 } else if (CUR == '/') {
8029 xmlXPathCompRelativeLocationPath(ctxt);
8036 * xmlXPathCompUnionExpr:
8037 * @ctxt: the XPath Parser context
8039 * [18] UnionExpr ::= PathExpr
8040 * | UnionExpr '|' PathExpr
8042 * Compile an union expression.
8046 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
8047 xmlXPathCompPathExpr(ctxt);
8050 while (CUR == '|') {
8051 int op1 = ctxt->comp->last;
8052 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
8056 xmlXPathCompPathExpr(ctxt);
8058 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
8065 * xmlXPathCompUnaryExpr:
8066 * @ctxt: the XPath Parser context
8068 * [27] UnaryExpr ::= UnionExpr
8071 * Compile an unary expression.
8075 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
8080 while (CUR == '-') {
8087 xmlXPathCompUnionExpr(ctxt);
8091 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
8093 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
8098 * xmlXPathCompMultiplicativeExpr:
8099 * @ctxt: the XPath Parser context
8101 * [26] MultiplicativeExpr ::= UnaryExpr
8102 * | MultiplicativeExpr MultiplyOperator UnaryExpr
8103 * | MultiplicativeExpr 'div' UnaryExpr
8104 * | MultiplicativeExpr 'mod' UnaryExpr
8105 * [34] MultiplyOperator ::= '*'
8107 * Compile an Additive expression.
8111 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
8112 xmlXPathCompUnaryExpr(ctxt);
8115 while ((CUR == '*') ||
8116 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
8117 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
8119 int op1 = ctxt->comp->last;
8124 } else if (CUR == 'd') {
8127 } else if (CUR == 'm') {
8132 xmlXPathCompUnaryExpr(ctxt);
8134 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
8140 * xmlXPathCompAdditiveExpr:
8141 * @ctxt: the XPath Parser context
8143 * [25] AdditiveExpr ::= MultiplicativeExpr
8144 * | AdditiveExpr '+' MultiplicativeExpr
8145 * | AdditiveExpr '-' MultiplicativeExpr
8147 * Compile an Additive expression.
8151 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
8153 xmlXPathCompMultiplicativeExpr(ctxt);
8156 while ((CUR == '+') || (CUR == '-')) {
8158 int op1 = ctxt->comp->last;
8160 if (CUR == '+') plus = 1;
8164 xmlXPathCompMultiplicativeExpr(ctxt);
8166 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
8172 * xmlXPathCompRelationalExpr:
8173 * @ctxt: the XPath Parser context
8175 * [24] RelationalExpr ::= AdditiveExpr
8176 * | RelationalExpr '<' AdditiveExpr
8177 * | RelationalExpr '>' AdditiveExpr
8178 * | RelationalExpr '<=' AdditiveExpr
8179 * | RelationalExpr '>=' AdditiveExpr
8181 * A <= B > C is allowed ? Answer from James, yes with
8182 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
8183 * which is basically what got implemented.
8185 * Compile a Relational expression, then push the result
8190 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
8191 xmlXPathCompAdditiveExpr(ctxt);
8194 while ((CUR == '<') ||
8196 ((CUR == '<') && (NXT(1) == '=')) ||
8197 ((CUR == '>') && (NXT(1) == '='))) {
8199 int op1 = ctxt->comp->last;
8201 if (CUR == '<') inf = 1;
8203 if (NXT(1) == '=') strict = 0;
8208 xmlXPathCompAdditiveExpr(ctxt);
8210 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
8216 * xmlXPathCompEqualityExpr:
8217 * @ctxt: the XPath Parser context
8219 * [23] EqualityExpr ::= RelationalExpr
8220 * | EqualityExpr '=' RelationalExpr
8221 * | EqualityExpr '!=' RelationalExpr
8223 * A != B != C is allowed ? Answer from James, yes with
8224 * (RelationalExpr = RelationalExpr) = RelationalExpr
8225 * (RelationalExpr != RelationalExpr) != RelationalExpr
8226 * which is basically what got implemented.
8228 * Compile an Equality expression.
8232 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
8233 xmlXPathCompRelationalExpr(ctxt);
8236 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
8238 int op1 = ctxt->comp->last;
8240 if (CUR == '=') eq = 1;
8245 xmlXPathCompRelationalExpr(ctxt);
8247 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
8253 * xmlXPathCompAndExpr:
8254 * @ctxt: the XPath Parser context
8256 * [22] AndExpr ::= EqualityExpr
8257 * | AndExpr 'and' EqualityExpr
8259 * Compile an AND expression.
8263 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
8264 xmlXPathCompEqualityExpr(ctxt);
8267 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
8268 int op1 = ctxt->comp->last;
8271 xmlXPathCompEqualityExpr(ctxt);
8273 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
8279 * xmlXPathCompileExpr:
8280 * @ctxt: the XPath Parser context
8282 * [14] Expr ::= OrExpr
8283 * [21] OrExpr ::= AndExpr
8284 * | OrExpr 'or' AndExpr
8286 * Parse and compile an expression
8289 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt) {
8290 xmlXPathCompAndExpr(ctxt);
8293 while ((CUR == 'o') && (NXT(1) == 'r')) {
8294 int op1 = ctxt->comp->last;
8297 xmlXPathCompAndExpr(ctxt);
8299 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
8300 op1 = ctxt->comp->nbStep;
8303 if (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE) {
8304 /* more ops could be optimized too */
8305 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
8310 * xmlXPathCompPredicate:
8311 * @ctxt: the XPath Parser context
8312 * @filter: act as a filter
8314 * [8] Predicate ::= '[' PredicateExpr ']'
8315 * [9] PredicateExpr ::= Expr
8317 * Compile a predicate expression
8320 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
8321 int op1 = ctxt->comp->last;
8325 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8330 ctxt->comp->last = -1;
8331 xmlXPathCompileExpr(ctxt);
8335 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
8339 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
8341 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
8348 * xmlXPathCompNodeTest:
8349 * @ctxt: the XPath Parser context
8350 * @test: pointer to a xmlXPathTestVal
8351 * @type: pointer to a xmlXPathTypeVal
8352 * @prefix: placeholder for a possible name prefix
8354 * [7] NodeTest ::= NameTest
8355 * | NodeType '(' ')'
8356 * | 'processing-instruction' '(' Literal ')'
8358 * [37] NameTest ::= '*'
8361 * [38] NodeType ::= 'comment'
8363 * | 'processing-instruction'
8366 * Returns the name found and update @test, @type and @prefix appropriately
8369 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
8370 xmlXPathTypeVal *type, const xmlChar **prefix,
8374 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
8378 *type = (xmlXPathTypeVal) 0;
8379 *test = (xmlXPathTestVal) 0;
8383 if ((name == NULL) && (CUR == '*')) {
8388 *test = NODE_TEST_ALL;
8393 name = xmlXPathParseNCName(ctxt);
8395 XP_ERROR0(XPATH_EXPR_ERROR);
8398 blanks = IS_BLANK(CUR);
8403 * NodeType or PI search
8405 if (xmlStrEqual(name, BAD_CAST "comment"))
8406 *type = NODE_TYPE_COMMENT;
8407 else if (xmlStrEqual(name, BAD_CAST "node"))
8408 *type = NODE_TYPE_NODE;
8409 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
8410 *type = NODE_TYPE_PI;
8411 else if (xmlStrEqual(name, BAD_CAST "text"))
8412 *type = NODE_TYPE_TEXT;
8416 XP_ERROR0(XPATH_EXPR_ERROR);
8419 *test = NODE_TEST_TYPE;
8422 if (*type == NODE_TYPE_PI) {
8424 * Specific case: search a PI by name.
8430 name = xmlXPathParseLiteral(ctxt);
8432 *test = NODE_TEST_PI;
8439 XP_ERROR0(XPATH_UNCLOSED_ERROR);
8444 *test = NODE_TEST_NAME;
8445 if ((!blanks) && (CUR == ':')) {
8449 * Since currently the parser context don't have a
8450 * namespace list associated:
8451 * The namespace name for this prefix can be computed
8452 * only at evaluation time. The compilation is done
8453 * outside of any context.
8456 *prefix = xmlXPathNsLookup(ctxt->context, name);
8459 if (*prefix == NULL) {
8460 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8471 *test = NODE_TEST_ALL;
8475 name = xmlXPathParseNCName(ctxt);
8477 XP_ERROR0(XPATH_EXPR_ERROR);
8484 * xmlXPathIsAxisName:
8485 * @name: a preparsed name token
8487 * [6] AxisName ::= 'ancestor'
8488 * | 'ancestor-or-self'
8492 * | 'descendant-or-self'
8494 * | 'following-sibling'
8498 * | 'preceding-sibling'
8501 * Returns the axis or 0
8503 static xmlXPathAxisVal
8504 xmlXPathIsAxisName(const xmlChar *name) {
8505 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
8508 if (xmlStrEqual(name, BAD_CAST "ancestor"))
8509 ret = AXIS_ANCESTOR;
8510 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
8511 ret = AXIS_ANCESTOR_OR_SELF;
8512 if (xmlStrEqual(name, BAD_CAST "attribute"))
8513 ret = AXIS_ATTRIBUTE;
8516 if (xmlStrEqual(name, BAD_CAST "child"))
8520 if (xmlStrEqual(name, BAD_CAST "descendant"))
8521 ret = AXIS_DESCENDANT;
8522 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
8523 ret = AXIS_DESCENDANT_OR_SELF;
8526 if (xmlStrEqual(name, BAD_CAST "following"))
8527 ret = AXIS_FOLLOWING;
8528 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
8529 ret = AXIS_FOLLOWING_SIBLING;
8532 if (xmlStrEqual(name, BAD_CAST "namespace"))
8533 ret = AXIS_NAMESPACE;
8536 if (xmlStrEqual(name, BAD_CAST "parent"))
8538 if (xmlStrEqual(name, BAD_CAST "preceding"))
8539 ret = AXIS_PRECEDING;
8540 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
8541 ret = AXIS_PRECEDING_SIBLING;
8544 if (xmlStrEqual(name, BAD_CAST "self"))
8553 * @ctxt: the XPath Parser context
8555 * [4] Step ::= AxisSpecifier NodeTest Predicate*
8558 * [12] AbbreviatedStep ::= '.' | '..'
8560 * [5] AxisSpecifier ::= AxisName '::'
8561 * | AbbreviatedAxisSpecifier
8563 * [13] AbbreviatedAxisSpecifier ::= '@'?
8565 * Modified for XPtr range support as:
8567 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
8569 * | 'range-to' '(' Expr ')' Predicate*
8571 * Compile one step in a Location Path
8572 * A location step of . is short for self::node(). This is
8573 * particularly useful in conjunction with //. For example, the
8574 * location path .//para is short for
8575 * self::node()/descendant-or-self::node()/child::para
8576 * and so will select all para descendant elements of the context
8578 * Similarly, a location step of .. is short for parent::node().
8579 * For example, ../title is short for parent::node()/child::title
8580 * and so will select the title children of the parent of the context
8584 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
8585 #ifdef LIBXML_XPTR_ENABLED
8591 if ((CUR == '.') && (NXT(1) == '.')) {
8594 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
8595 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8596 } else if (CUR == '.') {
8600 xmlChar *name = NULL;
8601 const xmlChar *prefix = NULL;
8602 xmlXPathTestVal test;
8603 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
8604 xmlXPathTypeVal type;
8608 * The modification needed for XPointer change to the production
8610 #ifdef LIBXML_XPTR_ENABLED
8612 name = xmlXPathParseNCName(ctxt);
8613 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
8614 op2 = ctxt->comp->last;
8618 XP_ERROR(XPATH_EXPR_ERROR);
8623 xmlXPathCompileExpr(ctxt);
8624 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
8629 XP_ERROR(XPATH_EXPR_ERROR);
8633 goto eval_predicates;
8641 name = xmlXPathParseNCName(ctxt);
8643 axis = xmlXPathIsAxisName(name);
8646 if ((CUR == ':') && (NXT(1) == ':')) {
8651 /* an element name can conflict with an axis one :-\ */
8657 } else if (CUR == '@') {
8659 axis = AXIS_ATTRIBUTE;
8667 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
8672 xmlGenericError(xmlGenericErrorContext,
8673 "Basis : computing new set\n");
8677 xmlGenericError(xmlGenericErrorContext, "Basis : ");
8678 if (ctxt->value == NULL)
8679 xmlGenericError(xmlGenericErrorContext, "no value\n");
8680 else if (ctxt->value->nodesetval == NULL)
8681 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8683 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
8687 op1 = ctxt->comp->last;
8688 ctxt->comp->last = -1;
8691 while (CUR == '[') {
8692 xmlXPathCompPredicate(ctxt, 0);
8695 #ifdef LIBXML_XPTR_ENABLED
8697 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
8700 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
8701 test, type, (void *)prefix, (void *)name);
8705 xmlGenericError(xmlGenericErrorContext, "Step : ");
8706 if (ctxt->value == NULL)
8707 xmlGenericError(xmlGenericErrorContext, "no value\n");
8708 else if (ctxt->value->nodesetval == NULL)
8709 xmlGenericError(xmlGenericErrorContext, "Empty\n");
8711 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
8712 ctxt->value->nodesetval);
8717 * xmlXPathCompRelativeLocationPath:
8718 * @ctxt: the XPath Parser context
8720 * [3] RelativeLocationPath ::= Step
8721 * | RelativeLocationPath '/' Step
8722 * | AbbreviatedRelativeLocationPath
8723 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
8725 * Compile a relative location path.
8728 xmlXPathCompRelativeLocationPath
8729 (xmlXPathParserContextPtr ctxt) {
8731 if ((CUR == '/') && (NXT(1) == '/')) {
8734 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8735 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8736 } else if (CUR == '/') {
8740 xmlXPathCompStep(ctxt);
8742 while (CUR == '/') {
8743 if ((CUR == '/') && (NXT(1) == '/')) {
8746 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8747 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8748 xmlXPathCompStep(ctxt);
8749 } else if (CUR == '/') {
8752 xmlXPathCompStep(ctxt);
8759 * xmlXPathCompLocationPath:
8760 * @ctxt: the XPath Parser context
8762 * [1] LocationPath ::= RelativeLocationPath
8763 * | AbsoluteLocationPath
8764 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
8765 * | AbbreviatedAbsoluteLocationPath
8766 * [10] AbbreviatedAbsoluteLocationPath ::=
8767 * '//' RelativeLocationPath
8769 * Compile a location path
8771 * // is short for /descendant-or-self::node()/. For example,
8772 * //para is short for /descendant-or-self::node()/child::para and
8773 * so will select any para element in the document (even a para element
8774 * that is a document element will be selected by //para since the
8775 * document element node is a child of the root node); div//para is
8776 * short for div/descendant-or-self::node()/child::para and so will
8777 * select all para descendants of div children.
8780 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
8783 xmlXPathCompRelativeLocationPath(ctxt);
8785 while (CUR == '/') {
8786 if ((CUR == '/') && (NXT(1) == '/')) {
8789 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
8790 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
8791 xmlXPathCompRelativeLocationPath(ctxt);
8792 } else if (CUR == '/') {
8796 ((IS_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
8797 (CUR == '@') || (CUR == '*')))
8798 xmlXPathCompRelativeLocationPath(ctxt);
8804 /************************************************************************
8806 * XPath precompiled expression evaluation *
8808 ************************************************************************/
8811 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
8814 * xmlXPathNodeCollectAndTest:
8815 * @ctxt: the XPath Parser context
8816 * @op: the XPath precompiled step operation
8817 * @first: pointer to the first element in document order
8818 * @last: pointer to the last element in document order
8820 * This is the function implementing a step: based on the current list
8821 * of nodes, it builds up a new list, looking at all nodes under that
8822 * axis and selecting them it also do the predicate filtering
8824 * Pushes the new NodeSet resulting from the search.
8826 * Returns the number of node traversed
8829 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
8830 xmlXPathStepOpPtr op,
8831 xmlNodePtr * first, xmlNodePtr * last)
8833 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
8834 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
8835 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
8836 const xmlChar *prefix = op->value4;
8837 const xmlChar *name = op->value5;
8838 const xmlChar *URI = NULL;
8844 xmlNodeSetPtr ret, list;
8845 xmlXPathTraversalFunction next = NULL;
8846 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
8847 xmlNodeSetPtr (*mergeNodeSet) (xmlNodeSetPtr, xmlNodeSetPtr);
8848 xmlNodePtr cur = NULL;
8849 xmlXPathObjectPtr obj;
8850 xmlNodeSetPtr nodelist;
8853 CHECK_TYPE0(XPATH_NODESET);
8854 obj = valuePop(ctxt);
8855 addNode = xmlXPathNodeSetAdd;
8856 mergeNodeSet = xmlXPathNodeSetMerge;
8857 if (prefix != NULL) {
8858 URI = xmlXPathNsLookup(ctxt->context, prefix);
8860 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
8863 xmlGenericError(xmlGenericErrorContext, "new step : ");
8868 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
8871 next = xmlXPathNextAncestor;
8873 case AXIS_ANCESTOR_OR_SELF:
8875 xmlGenericError(xmlGenericErrorContext,
8876 "axis 'ancestors-or-self' ");
8879 next = xmlXPathNextAncestorOrSelf;
8881 case AXIS_ATTRIBUTE:
8883 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
8887 next = xmlXPathNextAttribute;
8888 mergeNodeSet = xmlXPathNodeSetMergeUnique;
8892 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
8895 next = xmlXPathNextChild;
8896 mergeNodeSet = xmlXPathNodeSetMergeUnique;
8898 case AXIS_DESCENDANT:
8900 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
8903 next = xmlXPathNextDescendant;
8905 case AXIS_DESCENDANT_OR_SELF:
8907 xmlGenericError(xmlGenericErrorContext,
8908 "axis 'descendant-or-self' ");
8911 next = xmlXPathNextDescendantOrSelf;
8913 case AXIS_FOLLOWING:
8915 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
8918 next = xmlXPathNextFollowing;
8920 case AXIS_FOLLOWING_SIBLING:
8922 xmlGenericError(xmlGenericErrorContext,
8923 "axis 'following-siblings' ");
8926 next = xmlXPathNextFollowingSibling;
8928 case AXIS_NAMESPACE:
8930 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
8934 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
8935 mergeNodeSet = xmlXPathNodeSetMergeUnique;
8939 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
8942 next = xmlXPathNextParent;
8944 case AXIS_PRECEDING:
8946 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
8949 next = xmlXPathNextPrecedingInternal;
8951 case AXIS_PRECEDING_SIBLING:
8953 xmlGenericError(xmlGenericErrorContext,
8954 "axis 'preceding-sibling' ");
8957 next = xmlXPathNextPrecedingSibling;
8961 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
8965 next = xmlXPathNextSelf;
8966 mergeNodeSet = xmlXPathNodeSetMergeUnique;
8972 nodelist = obj->nodesetval;
8973 if (nodelist == NULL) {
8974 xmlXPathFreeObject(obj);
8975 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
8978 addNode = xmlXPathNodeSetAddUnique;
8981 xmlGenericError(xmlGenericErrorContext,
8982 " context contains %d nodes\n", nodelist->nodeNr);
8984 case NODE_TEST_NONE:
8985 xmlGenericError(xmlGenericErrorContext,
8986 " searching for none !!!\n");
8988 case NODE_TEST_TYPE:
8989 xmlGenericError(xmlGenericErrorContext,
8990 " searching for type %d\n", type);
8993 xmlGenericError(xmlGenericErrorContext,
8994 " searching for PI !!!\n");
8997 xmlGenericError(xmlGenericErrorContext,
8998 " searching for *\n");
9001 xmlGenericError(xmlGenericErrorContext,
9002 " searching for namespace %s\n",
9005 case NODE_TEST_NAME:
9006 xmlGenericError(xmlGenericErrorContext,
9007 " searching for name %s\n", name);
9009 xmlGenericError(xmlGenericErrorContext,
9010 " with namespace %s\n", prefix);
9013 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9017 * - For the attribute axis, the principal node type is attribute.
9018 * - For the namespace axis, the principal node type is namespace.
9019 * - For other axes, the principal node type is element.
9021 * A node test * is true for any node of the
9022 * principal node type. For example, child::* will
9023 * select all element children of the context node
9025 tmp = ctxt->context->node;
9026 for (i = 0; i < nodelist->nodeNr; i++) {
9027 ctxt->context->node = nodelist->nodeTab[i];
9030 list = xmlXPathNodeSetCreate(NULL);
9032 cur = next(ctxt, cur);
9035 if ((first != NULL) && (*first == cur))
9037 if (((t % 256) == 0) &&
9038 (first != NULL) && (*first != NULL) &&
9039 (xmlXPathCmpNodes(*first, cur) >= 0))
9041 if ((last != NULL) && (*last == cur))
9043 if (((t % 256) == 0) &&
9044 (last != NULL) && (*last != NULL) &&
9045 (xmlXPathCmpNodes(cur, *last) >= 0))
9049 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
9052 case NODE_TEST_NONE:
9053 ctxt->context->node = tmp;
9055 case NODE_TEST_TYPE:
9056 if ((cur->type == type) ||
9057 ((type == NODE_TYPE_NODE) &&
9058 ((cur->type == XML_DOCUMENT_NODE) ||
9059 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9060 (cur->type == XML_ELEMENT_NODE) ||
9061 (cur->type == XML_NAMESPACE_DECL) ||
9062 (cur->type == XML_ATTRIBUTE_NODE) ||
9063 (cur->type == XML_PI_NODE) ||
9064 (cur->type == XML_COMMENT_NODE) ||
9065 (cur->type == XML_CDATA_SECTION_NODE) ||
9066 (cur->type == XML_TEXT_NODE))) ||
9067 ((type == NODE_TYPE_TEXT) &&
9068 (cur->type == XML_CDATA_SECTION_NODE))) {
9076 if (cur->type == XML_PI_NODE) {
9077 if ((name != NULL) &&
9078 (!xmlStrEqual(name, cur->name)))
9087 if (axis == AXIS_ATTRIBUTE) {
9088 if (cur->type == XML_ATTRIBUTE_NODE) {
9094 } else if (axis == AXIS_NAMESPACE) {
9095 if (cur->type == XML_NAMESPACE_DECL) {
9099 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9103 if (cur->type == XML_ELEMENT_NODE) {
9104 if (prefix == NULL) {
9109 } else if ((cur->ns != NULL) &&
9110 (xmlStrEqual(URI, cur->ns->href))) {
9123 case NODE_TEST_NAME:
9124 switch (cur->type) {
9125 case XML_ELEMENT_NODE:
9126 if (xmlStrEqual(name, cur->name)) {
9127 if (prefix == NULL) {
9128 if (cur->ns == NULL) {
9135 if ((cur->ns != NULL) &&
9146 case XML_ATTRIBUTE_NODE:{
9147 xmlAttrPtr attr = (xmlAttrPtr) cur;
9149 if (xmlStrEqual(name, attr->name)) {
9150 if (prefix == NULL) {
9151 if ((attr->ns == NULL) ||
9152 (attr->ns->prefix == NULL)) {
9160 if ((attr->ns != NULL) &&
9174 case XML_NAMESPACE_DECL:
9175 if (cur->type == XML_NAMESPACE_DECL) {
9176 xmlNsPtr ns = (xmlNsPtr) cur;
9178 if ((ns->prefix != NULL) && (name != NULL)
9179 && (xmlStrEqual(ns->prefix, name))) {
9183 xmlXPathNodeSetAddNs(list,
9184 ctxt->context->node, (xmlNsPtr) cur);
9194 } while (cur != NULL);
9197 * If there is some predicate filtering do it now
9199 if ((op->ch2 != -1) && (list != NULL) && (list->nodeNr > 0)) {
9200 xmlXPathObjectPtr obj2;
9202 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9203 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch2]);
9204 CHECK_TYPE0(XPATH_NODESET);
9205 obj2 = valuePop(ctxt);
9206 list = obj2->nodesetval;
9207 obj2->nodesetval = NULL;
9208 xmlXPathFreeObject(obj2);
9213 ret = mergeNodeSet(ret, list);
9214 xmlXPathFreeNodeSet(list);
9217 ctxt->context->node = tmp;
9219 xmlGenericError(xmlGenericErrorContext,
9220 "\nExamined %d nodes, found %d nodes at that step\n",
9223 valuePush(ctxt, xmlXPathWrapNodeSet(ret));
9224 if ((obj->boolval) && (obj->user != NULL)) {
9225 ctxt->value->boolval = 1;
9226 ctxt->value->user = obj->user;
9230 xmlXPathFreeObject(obj);
9235 * xmlXPathNodeCollectAndTestNth:
9236 * @ctxt: the XPath Parser context
9237 * @op: the XPath precompiled step operation
9238 * @indx: the index to collect
9239 * @first: pointer to the first element in document order
9240 * @last: pointer to the last element in document order
9242 * This is the function implementing a step: based on the current list
9243 * of nodes, it builds up a new list, looking at all nodes under that
9244 * axis and selecting them it also do the predicate filtering
9246 * Pushes the new NodeSet resulting from the search.
9247 * Returns the number of node traversed
9250 xmlXPathNodeCollectAndTestNth(xmlXPathParserContextPtr ctxt,
9251 xmlXPathStepOpPtr op, int indx,
9252 xmlNodePtr * first, xmlNodePtr * last)
9254 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
9255 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
9256 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
9257 const xmlChar *prefix = op->value4;
9258 const xmlChar *name = op->value5;
9259 const xmlChar *URI = NULL;
9264 xmlXPathTraversalFunction next = NULL;
9265 void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
9266 xmlNodePtr cur = NULL;
9267 xmlXPathObjectPtr obj;
9268 xmlNodeSetPtr nodelist;
9271 CHECK_TYPE0(XPATH_NODESET);
9272 obj = valuePop(ctxt);
9273 addNode = xmlXPathNodeSetAdd;
9274 if (prefix != NULL) {
9275 URI = xmlXPathNsLookup(ctxt->context, prefix);
9277 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
9279 #ifdef DEBUG_STEP_NTH
9280 xmlGenericError(xmlGenericErrorContext, "new step : ");
9281 if (first != NULL) {
9283 xmlGenericError(xmlGenericErrorContext, "first = %s ",
9286 xmlGenericError(xmlGenericErrorContext, "first = NULL ");
9290 xmlGenericError(xmlGenericErrorContext, "last = %s ",
9293 xmlGenericError(xmlGenericErrorContext, "last = NULL ");
9298 #ifdef DEBUG_STEP_NTH
9299 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
9302 next = xmlXPathNextAncestor;
9304 case AXIS_ANCESTOR_OR_SELF:
9305 #ifdef DEBUG_STEP_NTH
9306 xmlGenericError(xmlGenericErrorContext,
9307 "axis 'ancestors-or-self' ");
9310 next = xmlXPathNextAncestorOrSelf;
9312 case AXIS_ATTRIBUTE:
9313 #ifdef DEBUG_STEP_NTH
9314 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
9318 next = xmlXPathNextAttribute;
9321 #ifdef DEBUG_STEP_NTH
9322 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
9325 next = xmlXPathNextChild;
9327 case AXIS_DESCENDANT:
9328 #ifdef DEBUG_STEP_NTH
9329 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
9332 next = xmlXPathNextDescendant;
9334 case AXIS_DESCENDANT_OR_SELF:
9335 #ifdef DEBUG_STEP_NTH
9336 xmlGenericError(xmlGenericErrorContext,
9337 "axis 'descendant-or-self' ");
9340 next = xmlXPathNextDescendantOrSelf;
9342 case AXIS_FOLLOWING:
9343 #ifdef DEBUG_STEP_NTH
9344 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
9347 next = xmlXPathNextFollowing;
9349 case AXIS_FOLLOWING_SIBLING:
9350 #ifdef DEBUG_STEP_NTH
9351 xmlGenericError(xmlGenericErrorContext,
9352 "axis 'following-siblings' ");
9355 next = xmlXPathNextFollowingSibling;
9357 case AXIS_NAMESPACE:
9358 #ifdef DEBUG_STEP_NTH
9359 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
9363 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
9366 #ifdef DEBUG_STEP_NTH
9367 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
9370 next = xmlXPathNextParent;
9372 case AXIS_PRECEDING:
9373 #ifdef DEBUG_STEP_NTH
9374 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
9377 next = xmlXPathNextPrecedingInternal;
9379 case AXIS_PRECEDING_SIBLING:
9380 #ifdef DEBUG_STEP_NTH
9381 xmlGenericError(xmlGenericErrorContext,
9382 "axis 'preceding-sibling' ");
9385 next = xmlXPathNextPrecedingSibling;
9388 #ifdef DEBUG_STEP_NTH
9389 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
9393 next = xmlXPathNextSelf;
9399 nodelist = obj->nodesetval;
9400 if (nodelist == NULL) {
9401 xmlXPathFreeObject(obj);
9402 valuePush(ctxt, xmlXPathWrapNodeSet(NULL));
9405 addNode = xmlXPathNodeSetAddUnique;
9406 #ifdef DEBUG_STEP_NTH
9407 xmlGenericError(xmlGenericErrorContext,
9408 " context contains %d nodes\n", nodelist->nodeNr);
9410 case NODE_TEST_NONE:
9411 xmlGenericError(xmlGenericErrorContext,
9412 " searching for none !!!\n");
9414 case NODE_TEST_TYPE:
9415 xmlGenericError(xmlGenericErrorContext,
9416 " searching for type %d\n", type);
9419 xmlGenericError(xmlGenericErrorContext,
9420 " searching for PI !!!\n");
9423 xmlGenericError(xmlGenericErrorContext,
9424 " searching for *\n");
9427 xmlGenericError(xmlGenericErrorContext,
9428 " searching for namespace %s\n",
9431 case NODE_TEST_NAME:
9432 xmlGenericError(xmlGenericErrorContext,
9433 " searching for name %s\n", name);
9435 xmlGenericError(xmlGenericErrorContext,
9436 " with namespace %s\n", prefix);
9439 xmlGenericError(xmlGenericErrorContext, "Testing : ");
9443 * - For the attribute axis, the principal node type is attribute.
9444 * - For the namespace axis, the principal node type is namespace.
9445 * - For other axes, the principal node type is element.
9447 * A node test * is true for any node of the
9448 * principal node type. For example, child::* will
9449 * select all element children of the context node
9451 tmp = ctxt->context->node;
9452 list = xmlXPathNodeSetCreate(NULL);
9453 for (i = 0; i < nodelist->nodeNr; i++) {
9454 ctxt->context->node = nodelist->nodeTab[i];
9459 cur = next(ctxt, cur);
9462 if ((first != NULL) && (*first == cur))
9464 if (((t % 256) == 0) &&
9465 (first != NULL) && (*first != NULL) &&
9466 (xmlXPathCmpNodes(*first, cur) >= 0))
9468 if ((last != NULL) && (*last == cur))
9470 if (((t % 256) == 0) &&
9471 (last != NULL) && (*last != NULL) &&
9472 (xmlXPathCmpNodes(cur, *last) >= 0))
9476 case NODE_TEST_NONE:
9477 ctxt->context->node = tmp;
9479 case NODE_TEST_TYPE:
9480 if ((cur->type == type) ||
9481 ((type == NODE_TYPE_NODE) &&
9482 ((cur->type == XML_DOCUMENT_NODE) ||
9483 (cur->type == XML_HTML_DOCUMENT_NODE) ||
9484 (cur->type == XML_ELEMENT_NODE) ||
9485 (cur->type == XML_PI_NODE) ||
9486 (cur->type == XML_COMMENT_NODE) ||
9487 (cur->type == XML_CDATA_SECTION_NODE) ||
9488 (cur->type == XML_TEXT_NODE))) ||
9489 ((type == NODE_TYPE_TEXT) &&
9490 (cur->type == XML_CDATA_SECTION_NODE))) {
9497 if (cur->type == XML_PI_NODE) {
9498 if ((name != NULL) &&
9499 (!xmlStrEqual(name, cur->name)))
9507 if (axis == AXIS_ATTRIBUTE) {
9508 if (cur->type == XML_ATTRIBUTE_NODE) {
9513 } else if (axis == AXIS_NAMESPACE) {
9514 if (cur->type == XML_NAMESPACE_DECL) {
9517 xmlXPathNodeSetAddNs(list, ctxt->context->node,
9521 if (cur->type == XML_ELEMENT_NODE) {
9522 if (prefix == NULL) {
9526 } else if ((cur->ns != NULL) &&
9527 (xmlStrEqual(URI, cur->ns->href))) {
9539 case NODE_TEST_NAME:
9540 switch (cur->type) {
9541 case XML_ELEMENT_NODE:
9542 if (xmlStrEqual(name, cur->name)) {
9543 if (prefix == NULL) {
9544 if (cur->ns == NULL) {
9550 if ((cur->ns != NULL) &&
9560 case XML_ATTRIBUTE_NODE:{
9561 xmlAttrPtr attr = (xmlAttrPtr) cur;
9563 if (xmlStrEqual(name, attr->name)) {
9564 if (prefix == NULL) {
9565 if ((attr->ns == NULL) ||
9566 (attr->ns->prefix == NULL)) {
9572 if ((attr->ns != NULL) &&
9584 case XML_NAMESPACE_DECL:
9585 if (cur->type == XML_NAMESPACE_DECL) {
9586 xmlNsPtr ns = (xmlNsPtr) cur;
9588 if ((ns->prefix != NULL) && (name != NULL)
9589 && (xmlStrEqual(ns->prefix, name))) {
9592 xmlXPathNodeSetAddNs(list,
9593 ctxt->context->node, (xmlNsPtr) cur);
9605 ctxt->context->node = tmp;
9606 #ifdef DEBUG_STEP_NTH
9607 xmlGenericError(xmlGenericErrorContext,
9608 "\nExamined %d nodes, found %d nodes at that step\n",
9611 valuePush(ctxt, xmlXPathWrapNodeSet(list));
9612 if ((obj->boolval) && (obj->user != NULL)) {
9613 ctxt->value->boolval = 1;
9614 ctxt->value->user = obj->user;
9618 xmlXPathFreeObject(obj);
9623 * xmlXPathCompOpEvalFirst:
9624 * @ctxt: the XPath parser context with the compiled expression
9625 * @op: an XPath compiled operation
9626 * @first: the first elem found so far
9628 * Evaluate the Precompiled XPath operation searching only the first
9629 * element in document order
9631 * Returns the number of examined objects.
9634 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
9635 xmlXPathStepOpPtr op, xmlNodePtr * first)
9638 xmlXPathCompExprPtr comp;
9639 xmlXPathObjectPtr arg1, arg2;
9646 case XPATH_OP_UNION:
9648 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9651 if ((ctxt->value != NULL)
9652 && (ctxt->value->type == XPATH_NODESET)
9653 && (ctxt->value->nodesetval != NULL)
9654 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9656 * limit tree traversing to first node in the result
9658 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9659 *first = ctxt->value->nodesetval->nodeTab[0];
9662 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
9665 CHECK_TYPE0(XPATH_NODESET);
9666 arg2 = valuePop(ctxt);
9668 CHECK_TYPE0(XPATH_NODESET);
9669 arg1 = valuePop(ctxt);
9671 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9673 valuePush(ctxt, arg1);
9674 xmlXPathFreeObject(arg2);
9677 xmlXPathCompSwap(op);
9678 return (total + cur);
9684 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9687 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9689 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9691 case XPATH_OP_RESET:
9693 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9696 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9698 ctxt->context->node = NULL;
9700 case XPATH_OP_COLLECT:{
9704 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9708 * Optimization for [n] selection where n is a number
9710 if ((op->ch2 != -1) &&
9711 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9712 (comp->steps[op->ch2].ch1 == -1) &&
9713 (comp->steps[op->ch2].ch2 != -1) &&
9714 (comp->steps[comp->steps[op->ch2].ch2].op ==
9716 xmlXPathObjectPtr val;
9718 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9719 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9720 int indx = (int) val->floatval;
9722 if (val->floatval == (float) indx) {
9723 xmlXPathNodeCollectAndTestNth(ctxt, op, indx,
9729 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL);
9732 case XPATH_OP_VALUE:
9734 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9739 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
9742 if ((ctxt->value != NULL)
9743 && (ctxt->value->type == XPATH_NODESET)
9744 && (ctxt->value->nodesetval != NULL))
9745 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9748 return (xmlXPathCompOpEval(ctxt, op));
9753 * xmlXPathCompOpEvalLast:
9754 * @ctxt: the XPath parser context with the compiled expression
9755 * @op: an XPath compiled operation
9756 * @last: the last elem found so far
9758 * Evaluate the Precompiled XPath operation searching only the last
9759 * element in document order
9761 * Returns the number of node traversed
9764 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
9768 xmlXPathCompExprPtr comp;
9769 xmlXPathObjectPtr arg1, arg2;
9776 case XPATH_OP_UNION:
9778 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
9780 if ((ctxt->value != NULL)
9781 && (ctxt->value->type == XPATH_NODESET)
9782 && (ctxt->value->nodesetval != NULL)
9783 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9785 * limit tree traversing to first node in the result
9787 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9789 ctxt->value->nodesetval->nodeTab[ctxt->value->
9790 nodesetval->nodeNr -
9794 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
9796 if ((ctxt->value != NULL)
9797 && (ctxt->value->type == XPATH_NODESET)
9798 && (ctxt->value->nodesetval != NULL)
9799 && (ctxt->value->nodesetval->nodeNr >= 1)) {
9801 CHECK_TYPE0(XPATH_NODESET);
9802 arg2 = valuePop(ctxt);
9804 CHECK_TYPE0(XPATH_NODESET);
9805 arg1 = valuePop(ctxt);
9807 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
9809 valuePush(ctxt, arg1);
9810 xmlXPathFreeObject(arg2);
9813 xmlXPathCompSwap(op);
9814 return (total + cur);
9820 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9823 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9825 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
9827 case XPATH_OP_RESET:
9829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9832 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9834 ctxt->context->node = NULL;
9836 case XPATH_OP_COLLECT:{
9840 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9844 * Optimization for [n] selection where n is a number
9846 if ((op->ch2 != -1) &&
9847 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
9848 (comp->steps[op->ch2].ch1 == -1) &&
9849 (comp->steps[op->ch2].ch2 != -1) &&
9850 (comp->steps[comp->steps[op->ch2].ch2].op ==
9852 xmlXPathObjectPtr val;
9854 val = comp->steps[comp->steps[op->ch2].ch2].value4;
9855 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
9856 int indx = (int) val->floatval;
9858 if (val->floatval == (float) indx) {
9860 xmlXPathNodeCollectAndTestNth(ctxt, op,
9867 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last);
9870 case XPATH_OP_VALUE:
9872 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
9877 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
9880 if ((ctxt->value != NULL)
9881 && (ctxt->value->type == XPATH_NODESET)
9882 && (ctxt->value->nodesetval != NULL))
9883 xmlXPathNodeSetSort(ctxt->value->nodesetval);
9886 return (xmlXPathCompOpEval(ctxt, op));
9891 * xmlXPathCompOpEval:
9892 * @ctxt: the XPath parser context with the compiled expression
9893 * @op: an XPath compiled operation
9895 * Evaluate the Precompiled XPath operation
9896 * Returns the number of node traversed
9899 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
9903 xmlXPathCompExprPtr comp;
9904 xmlXPathObjectPtr arg1, arg2;
9916 bakd = ctxt->context->doc;
9917 bak = ctxt->context->node;
9918 pp = ctxt->context->proximityPosition;
9919 cs = ctxt->context->contextSize;
9920 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9922 xmlXPathBooleanFunction(ctxt, 1);
9923 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
9925 arg2 = valuePop(ctxt);
9926 ctxt->context->doc = bakd;
9927 ctxt->context->node = bak;
9928 ctxt->context->proximityPosition = pp;
9929 ctxt->context->contextSize = cs;
9930 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9932 xmlXPathFreeObject(arg2);
9935 xmlXPathBooleanFunction(ctxt, 1);
9936 arg1 = valuePop(ctxt);
9937 arg1->boolval &= arg2->boolval;
9938 valuePush(ctxt, arg1);
9939 xmlXPathFreeObject(arg2);
9942 bakd = ctxt->context->doc;
9943 bak = ctxt->context->node;
9944 pp = ctxt->context->proximityPosition;
9945 cs = ctxt->context->contextSize;
9946 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9948 xmlXPathBooleanFunction(ctxt, 1);
9949 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
9951 arg2 = valuePop(ctxt);
9952 ctxt->context->doc = bakd;
9953 ctxt->context->node = bak;
9954 ctxt->context->proximityPosition = pp;
9955 ctxt->context->contextSize = cs;
9956 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9958 xmlXPathFreeObject(arg2);
9961 xmlXPathBooleanFunction(ctxt, 1);
9962 arg1 = valuePop(ctxt);
9963 arg1->boolval |= arg2->boolval;
9964 valuePush(ctxt, arg1);
9965 xmlXPathFreeObject(arg2);
9967 case XPATH_OP_EQUAL:
9968 bakd = ctxt->context->doc;
9969 bak = ctxt->context->node;
9970 pp = ctxt->context->proximityPosition;
9971 cs = ctxt->context->contextSize;
9972 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9974 ctxt->context->doc = bakd;
9975 ctxt->context->node = bak;
9976 ctxt->context->proximityPosition = pp;
9977 ctxt->context->contextSize = cs;
9978 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9981 equal = xmlXPathEqualValues(ctxt);
9983 equal = xmlXPathNotEqualValues(ctxt);
9984 valuePush(ctxt, xmlXPathNewBoolean(equal));
9987 bakd = ctxt->context->doc;
9988 bak = ctxt->context->node;
9989 pp = ctxt->context->proximityPosition;
9990 cs = ctxt->context->contextSize;
9991 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
9993 ctxt->context->doc = bakd;
9994 ctxt->context->node = bak;
9995 ctxt->context->proximityPosition = pp;
9996 ctxt->context->contextSize = cs;
9997 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
9999 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
10000 valuePush(ctxt, xmlXPathNewBoolean(ret));
10002 case XPATH_OP_PLUS:
10003 bakd = ctxt->context->doc;
10004 bak = ctxt->context->node;
10005 pp = ctxt->context->proximityPosition;
10006 cs = ctxt->context->contextSize;
10007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10009 if (op->ch2 != -1) {
10010 ctxt->context->doc = bakd;
10011 ctxt->context->node = bak;
10012 ctxt->context->proximityPosition = pp;
10013 ctxt->context->contextSize = cs;
10014 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10017 if (op->value == 0)
10018 xmlXPathSubValues(ctxt);
10019 else if (op->value == 1)
10020 xmlXPathAddValues(ctxt);
10021 else if (op->value == 2)
10022 xmlXPathValueFlipSign(ctxt);
10023 else if (op->value == 3) {
10025 CHECK_TYPE0(XPATH_NUMBER);
10028 case XPATH_OP_MULT:
10029 bakd = ctxt->context->doc;
10030 bak = ctxt->context->node;
10031 pp = ctxt->context->proximityPosition;
10032 cs = ctxt->context->contextSize;
10033 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10035 ctxt->context->doc = bakd;
10036 ctxt->context->node = bak;
10037 ctxt->context->proximityPosition = pp;
10038 ctxt->context->contextSize = cs;
10039 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10041 if (op->value == 0)
10042 xmlXPathMultValues(ctxt);
10043 else if (op->value == 1)
10044 xmlXPathDivValues(ctxt);
10045 else if (op->value == 2)
10046 xmlXPathModValues(ctxt);
10048 case XPATH_OP_UNION:
10049 bakd = ctxt->context->doc;
10050 bak = ctxt->context->node;
10051 pp = ctxt->context->proximityPosition;
10052 cs = ctxt->context->contextSize;
10053 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10055 ctxt->context->doc = bakd;
10056 ctxt->context->node = bak;
10057 ctxt->context->proximityPosition = pp;
10058 ctxt->context->contextSize = cs;
10059 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10061 CHECK_TYPE0(XPATH_NODESET);
10062 arg2 = valuePop(ctxt);
10064 CHECK_TYPE0(XPATH_NODESET);
10065 arg1 = valuePop(ctxt);
10067 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
10069 valuePush(ctxt, arg1);
10070 xmlXPathFreeObject(arg2);
10072 case XPATH_OP_ROOT:
10073 xmlXPathRoot(ctxt);
10075 case XPATH_OP_NODE:
10077 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10080 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10082 valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
10084 case XPATH_OP_RESET:
10086 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10089 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10091 ctxt->context->node = NULL;
10093 case XPATH_OP_COLLECT:{
10097 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10101 * Optimization for [n] selection where n is a number
10103 if ((op->ch2 != -1) &&
10104 (comp->steps[op->ch2].op == XPATH_OP_PREDICATE) &&
10105 (comp->steps[op->ch2].ch1 == -1) &&
10106 (comp->steps[op->ch2].ch2 != -1) &&
10107 (comp->steps[comp->steps[op->ch2].ch2].op ==
10109 xmlXPathObjectPtr val;
10111 val = comp->steps[comp->steps[op->ch2].ch2].value4;
10112 if ((val != NULL) && (val->type == XPATH_NUMBER)) {
10113 int indx = (int) val->floatval;
10115 if (val->floatval == (float) indx) {
10117 xmlXPathNodeCollectAndTestNth(ctxt, op,
10124 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL);
10127 case XPATH_OP_VALUE:
10129 xmlXPathObjectCopy((xmlXPathObjectPtr) op->value4));
10131 case XPATH_OP_VARIABLE:{
10132 xmlXPathObjectPtr val;
10136 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10137 if (op->value5 == NULL) {
10138 val = xmlXPathVariableLookup(ctxt->context, op->value4);
10140 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10143 valuePush(ctxt, val);
10145 const xmlChar *URI;
10147 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10149 xmlGenericError(xmlGenericErrorContext,
10150 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
10151 op->value4, op->value5);
10154 val = xmlXPathVariableLookupNS(ctxt->context,
10157 ctxt->error = XPATH_UNDEF_VARIABLE_ERROR;
10160 valuePush(ctxt, val);
10164 case XPATH_OP_FUNCTION:{
10165 xmlXPathFunction func;
10166 const xmlChar *oldFunc, *oldFuncURI;
10171 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10172 if (ctxt->valueNr < op->value) {
10173 xmlGenericError(xmlGenericErrorContext,
10174 "xmlXPathCompOpEval: parameter error\n");
10175 ctxt->error = XPATH_INVALID_OPERAND;
10178 for (i = 0; i < op->value; i++)
10179 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
10180 xmlGenericError(xmlGenericErrorContext,
10181 "xmlXPathCompOpEval: parameter error\n");
10182 ctxt->error = XPATH_INVALID_OPERAND;
10185 if (op->cache != NULL)
10186 func = (xmlXPathFunction) op->cache;
10188 const xmlChar *URI = NULL;
10190 if (op->value5 == NULL)
10192 xmlXPathFunctionLookup(ctxt->context,
10195 URI = xmlXPathNsLookup(ctxt->context, op->value5);
10197 xmlGenericError(xmlGenericErrorContext,
10198 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
10199 op->value4, op->value5);
10202 func = xmlXPathFunctionLookupNS(ctxt->context,
10205 if (func == NULL) {
10206 xmlGenericError(xmlGenericErrorContext,
10207 "xmlXPathCompOpEval: function %s not found\n",
10209 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
10211 op->cache = (void *) func;
10212 op->cacheURI = (void *) URI;
10214 oldFunc = ctxt->context->function;
10215 oldFuncURI = ctxt->context->functionURI;
10216 ctxt->context->function = op->value4;
10217 ctxt->context->functionURI = op->cacheURI;
10218 func(ctxt, op->value);
10219 ctxt->context->function = oldFunc;
10220 ctxt->context->functionURI = oldFuncURI;
10224 bakd = ctxt->context->doc;
10225 bak = ctxt->context->node;
10227 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10228 ctxt->context->doc = bakd;
10229 ctxt->context->node = bak;
10232 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
10233 ctxt->context->doc = bakd;
10234 ctxt->context->node = bak;
10237 case XPATH_OP_PREDICATE:
10238 case XPATH_OP_FILTER:{
10239 xmlXPathObjectPtr res;
10240 xmlXPathObjectPtr obj, tmp;
10241 xmlNodeSetPtr newset = NULL;
10242 xmlNodeSetPtr oldset;
10243 xmlNodePtr oldnode;
10247 * Optimization for ()[1] selection i.e. the first elem
10249 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10250 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10251 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
10252 xmlXPathObjectPtr val;
10254 val = comp->steps[op->ch2].value4;
10255 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
10256 (val->floatval == 1.0)) {
10257 xmlNodePtr first = NULL;
10260 xmlXPathCompOpEvalFirst(ctxt,
10261 &comp->steps[op->ch1],
10265 * The nodeset should be in document order,
10266 * Keep only the first value
10268 if ((ctxt->value != NULL) &&
10269 (ctxt->value->type == XPATH_NODESET) &&
10270 (ctxt->value->nodesetval != NULL) &&
10271 (ctxt->value->nodesetval->nodeNr > 1))
10272 ctxt->value->nodesetval->nodeNr = 1;
10277 * Optimization for ()[last()] selection i.e. the last elem
10279 if ((op->ch1 != -1) && (op->ch2 != -1) &&
10280 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
10281 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
10282 int f = comp->steps[op->ch2].ch1;
10285 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
10286 (comp->steps[f].value5 == NULL) &&
10287 (comp->steps[f].value == 0) &&
10288 (comp->steps[f].value4 != NULL) &&
10290 (comp->steps[f].value4, BAD_CAST "last"))) {
10291 xmlNodePtr last = NULL;
10294 xmlXPathCompOpEvalLast(ctxt,
10295 &comp->steps[op->ch1],
10299 * The nodeset should be in document order,
10300 * Keep only the last value
10302 if ((ctxt->value != NULL) &&
10303 (ctxt->value->type == XPATH_NODESET) &&
10304 (ctxt->value->nodesetval != NULL) &&
10305 (ctxt->value->nodesetval->nodeTab != NULL) &&
10306 (ctxt->value->nodesetval->nodeNr > 1)) {
10307 ctxt->value->nodesetval->nodeTab[0] =
10308 ctxt->value->nodesetval->nodeTab[ctxt->
10313 ctxt->value->nodesetval->nodeNr = 1;
10321 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10325 if (ctxt->value == NULL)
10328 oldnode = ctxt->context->node;
10330 #ifdef LIBXML_XPTR_ENABLED
10332 * Hum are we filtering the result of an XPointer expression
10334 if (ctxt->value->type == XPATH_LOCATIONSET) {
10335 xmlLocationSetPtr newlocset = NULL;
10336 xmlLocationSetPtr oldlocset;
10339 * Extract the old locset, and then evaluate the result of the
10340 * expression for all the element in the locset. use it to grow
10343 CHECK_TYPE0(XPATH_LOCATIONSET);
10344 obj = valuePop(ctxt);
10345 oldlocset = obj->user;
10346 ctxt->context->node = NULL;
10348 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
10349 ctxt->context->contextSize = 0;
10350 ctxt->context->proximityPosition = 0;
10353 xmlXPathCompOpEval(ctxt,
10354 &comp->steps[op->ch2]);
10355 res = valuePop(ctxt);
10357 xmlXPathFreeObject(res);
10358 valuePush(ctxt, obj);
10362 newlocset = xmlXPtrLocationSetCreate(NULL);
10364 for (i = 0; i < oldlocset->locNr; i++) {
10366 * Run the evaluation with a node list made of a
10367 * single item in the nodelocset.
10369 ctxt->context->node = oldlocset->locTab[i]->user;
10370 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10371 valuePush(ctxt, tmp);
10372 ctxt->context->contextSize = oldlocset->locNr;
10373 ctxt->context->proximityPosition = i + 1;
10377 xmlXPathCompOpEval(ctxt,
10378 &comp->steps[op->ch2]);
10382 * The result of the evaluation need to be tested to
10383 * decided whether the filter succeeded or not
10385 res = valuePop(ctxt);
10386 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10387 xmlXPtrLocationSetAdd(newlocset,
10389 (oldlocset->locTab[i]));
10396 xmlXPathFreeObject(res);
10397 if (ctxt->value == tmp) {
10398 res = valuePop(ctxt);
10399 xmlXPathFreeObject(res);
10402 ctxt->context->node = NULL;
10406 * The result is used as the new evaluation locset.
10408 xmlXPathFreeObject(obj);
10409 ctxt->context->node = NULL;
10410 ctxt->context->contextSize = -1;
10411 ctxt->context->proximityPosition = -1;
10412 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
10413 ctxt->context->node = oldnode;
10416 #endif /* LIBXML_XPTR_ENABLED */
10419 * Extract the old set, and then evaluate the result of the
10420 * expression for all the element in the set. use it to grow
10423 CHECK_TYPE0(XPATH_NODESET);
10424 obj = valuePop(ctxt);
10425 oldset = obj->nodesetval;
10427 oldnode = ctxt->context->node;
10428 ctxt->context->node = NULL;
10430 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
10431 ctxt->context->contextSize = 0;
10432 ctxt->context->proximityPosition = 0;
10435 xmlXPathCompOpEval(ctxt,
10436 &comp->steps[op->ch2]);
10438 res = valuePop(ctxt);
10440 xmlXPathFreeObject(res);
10441 valuePush(ctxt, obj);
10442 ctxt->context->node = oldnode;
10446 * Initialize the new set.
10448 newset = xmlXPathNodeSetCreate(NULL);
10450 for (i = 0; i < oldset->nodeNr; i++) {
10452 * Run the evaluation with a node list made of
10453 * a single item in the nodeset.
10455 ctxt->context->node = oldset->nodeTab[i];
10456 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10457 valuePush(ctxt, tmp);
10458 ctxt->context->contextSize = oldset->nodeNr;
10459 ctxt->context->proximityPosition = i + 1;
10463 xmlXPathCompOpEval(ctxt,
10464 &comp->steps[op->ch2]);
10468 * The result of the evaluation need to be tested to
10469 * decided whether the filter succeeded or not
10471 res = valuePop(ctxt);
10472 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
10473 xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
10480 xmlXPathFreeObject(res);
10481 if (ctxt->value == tmp) {
10482 res = valuePop(ctxt);
10483 xmlXPathFreeObject(res);
10486 ctxt->context->node = NULL;
10490 * The result is used as the new evaluation set.
10492 xmlXPathFreeObject(obj);
10493 ctxt->context->node = NULL;
10494 ctxt->context->contextSize = -1;
10495 ctxt->context->proximityPosition = -1;
10496 valuePush(ctxt, xmlXPathWrapNodeSet(newset));
10498 ctxt->context->node = oldnode;
10501 case XPATH_OP_SORT:
10503 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10505 if ((ctxt->value != NULL) &&
10506 (ctxt->value->type == XPATH_NODESET) &&
10507 (ctxt->value->nodesetval != NULL))
10508 xmlXPathNodeSetSort(ctxt->value->nodesetval);
10510 #ifdef LIBXML_XPTR_ENABLED
10511 case XPATH_OP_RANGETO:{
10512 xmlXPathObjectPtr range;
10513 xmlXPathObjectPtr res, obj;
10514 xmlXPathObjectPtr tmp;
10515 xmlLocationSetPtr newset = NULL;
10516 xmlNodeSetPtr oldset;
10521 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
10525 CHECK_TYPE0(XPATH_NODESET);
10526 obj = valuePop(ctxt);
10527 oldset = obj->nodesetval;
10528 ctxt->context->node = NULL;
10530 newset = xmlXPtrLocationSetCreate(NULL);
10532 if (oldset != NULL) {
10533 for (i = 0; i < oldset->nodeNr; i++) {
10535 * Run the evaluation with a node list made of a single item
10538 ctxt->context->node = oldset->nodeTab[i];
10539 tmp = xmlXPathNewNodeSet(ctxt->context->node);
10540 valuePush(ctxt, tmp);
10544 xmlXPathCompOpEval(ctxt,
10545 &comp->steps[op->ch2]);
10549 * The result of the evaluation need to be tested to
10550 * decided whether the filter succeeded or not
10552 res = valuePop(ctxt);
10554 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
10556 if (range != NULL) {
10557 xmlXPtrLocationSetAdd(newset, range);
10564 xmlXPathFreeObject(res);
10565 if (ctxt->value == tmp) {
10566 res = valuePop(ctxt);
10567 xmlXPathFreeObject(res);
10570 ctxt->context->node = NULL;
10575 * The result is used as the new evaluation set.
10577 xmlXPathFreeObject(obj);
10578 ctxt->context->node = NULL;
10579 ctxt->context->contextSize = -1;
10580 ctxt->context->proximityPosition = -1;
10581 valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
10584 #endif /* LIBXML_XPTR_ENABLED */
10586 xmlGenericError(xmlGenericErrorContext,
10587 "XPath: unknown precompiled operation %d\n", op->op);
10593 * @ctxt: the XPath parser context with the compiled expression
10595 * Evaluate the Precompiled XPath expression in the given context.
10598 xmlXPathRunEval(xmlXPathParserContextPtr ctxt) {
10599 xmlXPathCompExprPtr comp;
10601 if ((ctxt == NULL) || (ctxt->comp == NULL))
10604 if (ctxt->valueTab == NULL) {
10605 /* Allocate the value stack */
10606 ctxt->valueTab = (xmlXPathObjectPtr *)
10607 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
10608 if (ctxt->valueTab == NULL) {
10612 ctxt->valueMax = 10;
10613 ctxt->value = NULL;
10616 if(comp->last < 0) {
10617 xmlGenericError(xmlGenericErrorContext,
10618 "xmlXPathRunEval: last is less than zero\n");
10621 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
10624 /************************************************************************
10626 * Public interfaces *
10628 ************************************************************************/
10631 * xmlXPathEvalPredicate:
10632 * @ctxt: the XPath context
10633 * @res: the Predicate Expression evaluation result
10635 * Evaluate a predicate result for the current node.
10636 * A PredicateExpr is evaluated by evaluating the Expr and converting
10637 * the result to a boolean. If the result is a number, the result will
10638 * be converted to true if the number is equal to the position of the
10639 * context node in the context node list (as returned by the position
10640 * function) and will be converted to false otherwise; if the result
10641 * is not a number, then the result will be converted as if by a call
10642 * to the boolean function.
10644 * Returns 1 if predicate is true, 0 otherwise
10647 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
10648 if (res == NULL) return(0);
10649 switch (res->type) {
10650 case XPATH_BOOLEAN:
10651 return(res->boolval);
10653 return(res->floatval == ctxt->proximityPosition);
10654 case XPATH_NODESET:
10655 case XPATH_XSLT_TREE:
10656 if (res->nodesetval == NULL)
10658 return(res->nodesetval->nodeNr != 0);
10660 return((res->stringval != NULL) &&
10661 (xmlStrlen(res->stringval) != 0));
10669 * xmlXPathEvaluatePredicateResult:
10670 * @ctxt: the XPath Parser context
10671 * @res: the Predicate Expression evaluation result
10673 * Evaluate a predicate result for the current node.
10674 * A PredicateExpr is evaluated by evaluating the Expr and converting
10675 * the result to a boolean. If the result is a number, the result will
10676 * be converted to true if the number is equal to the position of the
10677 * context node in the context node list (as returned by the position
10678 * function) and will be converted to false otherwise; if the result
10679 * is not a number, then the result will be converted as if by a call
10680 * to the boolean function.
10682 * Returns 1 if predicate is true, 0 otherwise
10685 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
10686 xmlXPathObjectPtr res) {
10687 if (res == NULL) return(0);
10688 switch (res->type) {
10689 case XPATH_BOOLEAN:
10690 return(res->boolval);
10692 return(res->floatval == ctxt->context->proximityPosition);
10693 case XPATH_NODESET:
10694 case XPATH_XSLT_TREE:
10695 if (res->nodesetval == NULL)
10697 return(res->nodesetval->nodeNr != 0);
10699 return((res->stringval != NULL) &&
10700 (xmlStrlen(res->stringval) != 0));
10709 * @str: the XPath expression
10711 * Compile an XPath expression
10713 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
10714 * the caller has to free the object.
10716 xmlXPathCompExprPtr
10717 xmlXPathCompile(const xmlChar *str) {
10718 xmlXPathParserContextPtr ctxt;
10719 xmlXPathCompExprPtr comp;
10723 ctxt = xmlXPathNewParserContext(str, NULL);
10724 xmlXPathCompileExpr(ctxt);
10726 if (*ctxt->cur != 0) {
10728 * aleksey: in some cases this line prints *second* error message
10729 * (see bug #78858) and probably this should be fixed.
10730 * However, we are not sure that all error messages are printed
10731 * out in other places. It's not critical so we leave it as-is for now
10733 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10739 xmlXPathFreeParserContext(ctxt);
10740 if (comp != NULL) {
10741 comp->expr = xmlStrdup(str);
10742 #ifdef DEBUG_EVAL_COUNTS
10743 comp->string = xmlStrdup(str);
10751 * xmlXPathCompiledEval:
10752 * @comp: the compiled XPath expression
10753 * @ctx: the XPath context
10755 * Evaluate the Precompiled XPath expression in the given context.
10757 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10758 * the caller has to free the object.
10761 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx) {
10762 xmlXPathParserContextPtr ctxt;
10763 xmlXPathObjectPtr res, tmp, init = NULL;
10765 #ifndef LIBXML_THREAD_ENABLED
10766 static int reentance = 0;
10769 if ((comp == NULL) || (ctx == NULL))
10775 #ifndef LIBXML_THREAD_ENABLED
10778 xmlXPathDisableOptimizer = 1;
10781 #ifdef DEBUG_EVAL_COUNTS
10783 if ((comp->string != NULL) && (comp->nb > 100)) {
10784 fprintf(stderr, "100 x %s\n", comp->string);
10788 ctxt = xmlXPathCompParserContext(comp, ctx);
10789 xmlXPathRunEval(ctxt);
10791 if (ctxt->value == NULL) {
10792 xmlGenericError(xmlGenericErrorContext,
10793 "xmlXPathCompiledEval: evaluation failed\n");
10796 res = valuePop(ctxt);
10801 tmp = valuePop(ctxt);
10805 xmlXPathFreeObject(tmp);
10807 } while (tmp != NULL);
10808 if ((stack != 0) && (res != NULL)) {
10809 xmlGenericError(xmlGenericErrorContext,
10810 "xmlXPathCompiledEval: %d object left on the stack\n",
10813 if (ctxt->error != XPATH_EXPRESSION_OK) {
10814 xmlXPathFreeObject(res);
10820 xmlXPathFreeParserContext(ctxt);
10821 #ifndef LIBXML_THREAD_ENABLED
10828 * xmlXPathEvalExpr:
10829 * @ctxt: the XPath Parser context
10831 * Parse and evaluate an XPath expression in the given context,
10832 * then push the result on the context stack
10835 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
10836 xmlXPathCompileExpr(ctxt);
10838 xmlXPathRunEval(ctxt);
10843 * @str: the XPath expression
10844 * @ctx: the XPath context
10846 * Evaluate the XPath Location Path in the given context.
10848 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10849 * the caller has to free the object.
10852 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
10853 xmlXPathParserContextPtr ctxt;
10854 xmlXPathObjectPtr res, tmp, init = NULL;
10861 ctxt = xmlXPathNewParserContext(str, ctx);
10862 xmlXPathEvalExpr(ctxt);
10864 if (ctxt->value == NULL) {
10865 xmlGenericError(xmlGenericErrorContext,
10866 "xmlXPathEval: evaluation failed\n");
10868 } else if (*ctxt->cur != 0) {
10869 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10872 res = valuePop(ctxt);
10876 tmp = valuePop(ctxt);
10880 xmlXPathFreeObject(tmp);
10882 } while (tmp != NULL);
10883 if ((stack != 0) && (res != NULL)) {
10884 xmlGenericError(xmlGenericErrorContext,
10885 "xmlXPathEval: %d object left on the stack\n",
10888 if (ctxt->error != XPATH_EXPRESSION_OK) {
10889 xmlXPathFreeObject(res);
10893 xmlXPathFreeParserContext(ctxt);
10898 * xmlXPathEvalExpression:
10899 * @str: the XPath expression
10900 * @ctxt: the XPath context
10902 * Evaluate the XPath expression in the given context.
10904 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
10905 * the caller has to free the object.
10908 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
10909 xmlXPathParserContextPtr pctxt;
10910 xmlXPathObjectPtr res, tmp;
10915 CHECK_CONTEXT(ctxt)
10917 pctxt = xmlXPathNewParserContext(str, ctxt);
10918 xmlXPathEvalExpr(pctxt);
10920 if (*pctxt->cur != 0) {
10921 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
10924 res = valuePop(pctxt);
10927 tmp = valuePop(pctxt);
10929 xmlXPathFreeObject(tmp);
10932 } while (tmp != NULL);
10933 if ((stack != 0) && (res != NULL)) {
10934 xmlGenericError(xmlGenericErrorContext,
10935 "xmlXPathEvalExpression: %d object left on the stack\n",
10938 xmlXPathFreeParserContext(pctxt);
10942 /************************************************************************
10944 * Extra functions not pertaining to the XPath spec *
10946 ************************************************************************/
10948 * xmlXPathEscapeUriFunction:
10949 * @ctxt: the XPath Parser context
10950 * @nargs: the number of arguments
10952 * Implement the escape-uri() XPath function
10953 * string escape-uri(string $str, bool $escape-reserved)
10955 * This function applies the URI escaping rules defined in section 2 of [RFC
10956 * 2396] to the string supplied as $uri-part, which typically represents all
10957 * or part of a URI. The effect of the function is to replace any special
10958 * character in the string by an escape sequence of the form %xx%yy...,
10959 * where xxyy... is the hexadecimal representation of the octets used to
10960 * represent the character in UTF-8.
10962 * The set of characters that are escaped depends on the setting of the
10963 * boolean argument $escape-reserved.
10965 * If $escape-reserved is true, all characters are escaped other than lower
10966 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
10967 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
10968 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
10969 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
10972 * If $escape-reserved is false, the behavior differs in that characters
10973 * referred to in [RFC 2396] as reserved characters are not escaped. These
10974 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
10976 * [RFC 2396] does not define whether escaped URIs should use lower case or
10977 * upper case for hexadecimal digits. To ensure that escaped URIs can be
10978 * compared using string comparison functions, this function must always use
10979 * the upper-case letters A-F.
10981 * Generally, $escape-reserved should be set to true when escaping a string
10982 * that is to form a single part of a URI, and to false when escaping an
10983 * entire URI or URI reference.
10985 * In the case of non-ascii characters, the string is encoded according to
10986 * utf-8 and then converted according to RFC 2396.
10989 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
10990 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
10991 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
10992 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
10996 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
10997 xmlXPathObjectPtr str;
10998 int escape_reserved;
10999 xmlBufferPtr target;
11005 escape_reserved = xmlXPathPopBoolean(ctxt);
11008 str = valuePop(ctxt);
11010 target = xmlBufferCreate();
11016 for (cptr = str->stringval; *cptr; cptr++) {
11017 if ((*cptr >= 'A' && *cptr <= 'Z') ||
11018 (*cptr >= 'a' && *cptr <= 'z') ||
11019 (*cptr >= '0' && *cptr <= '9') ||
11020 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
11021 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
11022 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
11024 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
11025 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
11026 (cptr[1] >= '0' && cptr[1] <= '9')) &&
11027 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
11028 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
11029 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
11030 (!escape_reserved &&
11031 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
11032 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
11033 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
11035 xmlBufferAdd(target, cptr, 1);
11037 if ((*cptr >> 4) < 10)
11038 escape[1] = '0' + (*cptr >> 4);
11040 escape[1] = 'A' - 10 + (*cptr >> 4);
11041 if ((*cptr & 0xF) < 10)
11042 escape[2] = '0' + (*cptr & 0xF);
11044 escape[2] = 'A' - 10 + (*cptr & 0xF);
11046 xmlBufferAdd(target, &escape[0], 3);
11050 valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
11051 xmlBufferFree(target);
11052 xmlXPathFreeObject(str);
11056 * xmlXPathRegisterAllFunctions:
11057 * @ctxt: the XPath context
11059 * Registers all default XPath functions in this context
11062 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
11064 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
11065 xmlXPathBooleanFunction);
11066 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
11067 xmlXPathCeilingFunction);
11068 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
11069 xmlXPathCountFunction);
11070 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
11071 xmlXPathConcatFunction);
11072 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
11073 xmlXPathContainsFunction);
11074 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
11075 xmlXPathIdFunction);
11076 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
11077 xmlXPathFalseFunction);
11078 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
11079 xmlXPathFloorFunction);
11080 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
11081 xmlXPathLastFunction);
11082 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
11083 xmlXPathLangFunction);
11084 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
11085 xmlXPathLocalNameFunction);
11086 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
11087 xmlXPathNotFunction);
11088 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
11089 xmlXPathNameFunction);
11090 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
11091 xmlXPathNamespaceURIFunction);
11092 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
11093 xmlXPathNormalizeFunction);
11094 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
11095 xmlXPathNumberFunction);
11096 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
11097 xmlXPathPositionFunction);
11098 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
11099 xmlXPathRoundFunction);
11100 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
11101 xmlXPathStringFunction);
11102 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
11103 xmlXPathStringLengthFunction);
11104 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
11105 xmlXPathStartsWithFunction);
11106 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
11107 xmlXPathSubstringFunction);
11108 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
11109 xmlXPathSubstringBeforeFunction);
11110 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
11111 xmlXPathSubstringAfterFunction);
11112 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
11113 xmlXPathSumFunction);
11114 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
11115 xmlXPathTrueFunction);
11116 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
11117 xmlXPathTranslateFunction);
11119 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
11120 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
11121 xmlXPathEscapeUriFunction);
11124 #endif /* LIBXML_XPATH_ENABLED */