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
17 /* To avoid EBCDIC trouble when parsing on zOS */
19 #pragma convert("ISO8859-1")
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
44 #include <libxml/xmlmemory.h>
45 #include <libxml/tree.h>
46 #include <libxml/valid.h>
47 #include <libxml/xpath.h>
48 #include <libxml/xpathInternals.h>
49 #include <libxml/parserInternals.h>
50 #include <libxml/hash.h>
51 #ifdef LIBXML_XPTR_ENABLED
52 #include <libxml/xpointer.h>
54 #ifdef LIBXML_DEBUG_ENABLED
55 #include <libxml/debugXML.h>
57 #include <libxml/xmlerror.h>
58 #include <libxml/threads.h>
59 #include <libxml/globals.h>
60 #ifdef LIBXML_PATTERN_ENABLED
61 #include <libxml/pattern.h>
66 #ifdef LIBXML_PATTERN_ENABLED
67 #define XPATH_STREAMING
71 xmlGenericError(xmlGenericErrorContext, \
72 "Unimplemented block at %s:%d\n", \
78 * Use the Timsort algorithm provided in timsort.h to sort
79 * nodeset as this is a great improvement over the old Shell sort
80 * used in xmlXPathNodeSetSort()
85 * XP_OPTIMIZED_NON_ELEM_COMPARISON:
86 * If defined, this will use xmlXPathCmpNodesExt() instead of
87 * xmlXPathCmpNodes(). The new function is optimized comparison of
88 * non-element nodes; actually it will speed up comparison only if
89 * xmlXPathOrderDocElems() was called in order to index the elements of
90 * a tree in document order; Libxslt does such an indexing, thus it will
91 * benefit from this optimization.
93 #define XP_OPTIMIZED_NON_ELEM_COMPARISON
96 * XP_OPTIMIZED_FILTER_FIRST:
97 * If defined, this will optimize expressions like "key('foo', 'val')[b][1]"
98 * in a way, that it stop evaluation at the first node.
100 #define XP_OPTIMIZED_FILTER_FIRST
103 * XP_DEBUG_OBJ_USAGE:
104 * Internal flag to enable tracking of how much XPath objects have been
107 /* #define XP_DEBUG_OBJ_USAGE */
111 * when compiling an XPath expression we arbitrary limit the maximum
112 * number of step operation in the compiled expression. 1000000 is
113 * an insanely large value which should never be reached under normal
116 #define XPATH_MAX_STEPS 1000000
119 * XPATH_MAX_STACK_DEPTH:
120 * when evaluating an XPath expression we arbitrary limit the maximum
121 * number of object allowed to be pushed on the stack. 1000000 is
122 * an insanely large value which should never be reached under normal
125 #define XPATH_MAX_STACK_DEPTH 1000000
128 * XPATH_MAX_NODESET_LENGTH:
129 * when evaluating an XPath expression nodesets are created and we
130 * arbitrary limit the maximum length of those node set. 10000000 is
131 * an insanely large value which should never be reached under normal
132 * circumstances, one would first need to construct an in memory tree
133 * with more than 10 millions nodes.
135 #define XPATH_MAX_NODESET_LENGTH 10000000
139 * There are a few spots where some tests are done which depend upon ascii
140 * data. These should be enhanced for full UTF8 support (see particularly
141 * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
144 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
146 * xmlXPathCmpNodesExt:
147 * @node1: the first node
148 * @node2: the second node
150 * Compare two nodes w.r.t document order.
151 * This one is optimized for handling of non-element nodes.
153 * Returns -2 in case of error 1 if first point < second point, 0 if
154 * it's the same node, -1 otherwise
157 xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
159 int misc = 0, precedence1 = 0, precedence2 = 0;
160 xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
161 xmlNodePtr cur, root;
164 if ((node1 == NULL) || (node2 == NULL))
171 * a couple of optimizations which will avoid computations in most cases
173 switch (node1->type) {
174 case XML_ELEMENT_NODE:
175 if (node2->type == XML_ELEMENT_NODE) {
176 if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
177 (0 > (long) node2->content) &&
178 (node1->doc == node2->doc))
180 l1 = -((long) node1->content);
181 l2 = -((long) node2->content);
187 goto turtle_comparison;
190 case XML_ATTRIBUTE_NODE:
191 precedence1 = 1; /* element is owner */
193 node1 = node1->parent;
197 case XML_CDATA_SECTION_NODE:
198 case XML_COMMENT_NODE:
202 * Find nearest element node.
204 if (node1->prev != NULL) {
207 if (node1->type == XML_ELEMENT_NODE) {
208 precedence1 = 3; /* element in prev-sibl axis */
211 if (node1->prev == NULL) {
212 precedence1 = 2; /* element is parent */
214 * URGENT TODO: Are there any cases, where the
215 * parent of such a node is not an element node?
217 node1 = node1->parent;
222 precedence1 = 2; /* element is parent */
223 node1 = node1->parent;
225 if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
226 (0 <= (long) node1->content)) {
228 * Fallback for whatever case.
236 case XML_NAMESPACE_DECL:
238 * TODO: why do we return 1 for namespace nodes?
244 switch (node2->type) {
245 case XML_ELEMENT_NODE:
247 case XML_ATTRIBUTE_NODE:
248 precedence2 = 1; /* element is owner */
250 node2 = node2->parent;
254 case XML_CDATA_SECTION_NODE:
255 case XML_COMMENT_NODE:
258 if (node2->prev != NULL) {
261 if (node2->type == XML_ELEMENT_NODE) {
262 precedence2 = 3; /* element in prev-sibl axis */
265 if (node2->prev == NULL) {
266 precedence2 = 2; /* element is parent */
267 node2 = node2->parent;
272 precedence2 = 2; /* element is parent */
273 node2 = node2->parent;
275 if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
276 (0 <= (long) node2->content))
284 case XML_NAMESPACE_DECL:
290 if (node1 == node2) {
291 if (precedence1 == precedence2) {
293 * The ugly case; but normally there aren't many
294 * adjacent non-element nodes around.
296 cur = miscNode2->prev;
297 while (cur != NULL) {
298 if (cur == miscNode1)
300 if (cur->type == XML_ELEMENT_NODE)
307 * Evaluate based on higher precedence wrt to the element.
308 * TODO: This assumes attributes are sorted before content.
309 * Is this 100% correct?
311 if (precedence1 < precedence2)
318 * Special case: One of the helper-elements is contained by the other.
321 * <node1>Text-1(precedence1 == 2)</node1>
323 * Text-6(precedence2 == 3)
326 if ((precedence2 == 3) && (precedence1 > 1)) {
334 if ((precedence1 == 3) && (precedence2 > 1)) {
345 * Speedup using document order if availble.
347 if ((node1->type == XML_ELEMENT_NODE) &&
348 (node2->type == XML_ELEMENT_NODE) &&
349 (0 > (long) node1->content) &&
350 (0 > (long) node2->content) &&
351 (node1->doc == node2->doc)) {
353 l1 = -((long) node1->content);
354 l2 = -((long) node2->content);
363 if (node1 == node2->prev)
365 if (node1 == node2->next)
368 * compute depth to root
370 for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
371 if (cur->parent == node1)
376 for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
377 if (cur->parent == node2)
382 * Distinct document (or distinct entities :-( ) case.
388 * get the nearest common ancestor.
390 while (depth1 > depth2) {
392 node1 = node1->parent;
394 while (depth2 > depth1) {
396 node2 = node2->parent;
398 while (node1->parent != node2->parent) {
399 node1 = node1->parent;
400 node2 = node2->parent;
401 /* should not happen but just in case ... */
402 if ((node1 == NULL) || (node2 == NULL))
408 if (node1 == node2->prev)
410 if (node1 == node2->next)
413 * Speedup using document order if availble.
415 if ((node1->type == XML_ELEMENT_NODE) &&
416 (node2->type == XML_ELEMENT_NODE) &&
417 (0 > (long) node1->content) &&
418 (0 > (long) node2->content) &&
419 (node1->doc == node2->doc)) {
421 l1 = -((long) node1->content);
422 l2 = -((long) node2->content);
429 for (cur = node1->next;cur != NULL;cur = cur->next)
432 return(-1); /* assume there is no sibling list corruption */
434 #endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
437 * Wrapper for the Timsort argorithm from timsort.h
440 #define SORT_NAME libxml_domnode
441 #define SORT_TYPE xmlNodePtr
447 * Comparison function for the Timsort implementation
449 * Returns -2 in case of error -1 if first point < second point, 0 if
450 * it's the same node, +1 otherwise
453 int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
454 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
455 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
457 int res = xmlXPathCmpNodesExt(x, y);
458 return res == -2 ? res : -res;
461 static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
463 int res = xmlXPathCmpNodes(x, y);
464 return res == -2 ? res : -res;
467 #define SORT_CMP(x, y) (wrap_cmp(x, y))
469 #endif /* WITH_TIM_SORT */
471 #if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
473 /************************************************************************
475 * Floating point stuff *
477 ************************************************************************/
479 #ifndef TRIO_REPLACE_STDIO
480 #define TRIO_PUBLIC static
485 * The lack of portability of this section of the libc is annoying !
487 double xmlXPathNAN = 0;
488 double xmlXPathPINF = 1;
489 double xmlXPathNINF = -1;
490 static double xmlXPathNZERO = 0; /* not exported from headers */
491 static int xmlXPathInitialized = 0;
496 * Initialize the XPath environment
500 if (xmlXPathInitialized) return;
502 xmlXPathPINF = trio_pinf();
503 xmlXPathNINF = trio_ninf();
504 xmlXPathNAN = trio_nan();
505 xmlXPathNZERO = trio_nzero();
507 xmlXPathInitialized = 1;
512 * @val: a double value
514 * Provides a portable isnan() function to detect whether a double
515 * is a NotaNumber. Based on trio code
516 * http://sourceforge.net/projects/ctrio/
518 * Returns 1 if the value is a NaN, 0 otherwise
521 xmlXPathIsNaN(double val) {
522 return(trio_isnan(val));
527 * @val: a double value
529 * Provides a portable isinf() function to detect whether a double
530 * is a +Infinite or -Infinite. Based on trio code
531 * http://sourceforge.net/projects/ctrio/
533 * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
536 xmlXPathIsInf(double val) {
537 return(trio_isinf(val));
540 #endif /* SCHEMAS or XPATH */
541 #ifdef LIBXML_XPATH_ENABLED
544 * @val: a double value
546 * Provides a portable function to detect the sign of a double
547 * Modified from trio code
548 * http://sourceforge.net/projects/ctrio/
550 * Returns 1 if the value is Negative, 0 if positive
553 xmlXPathGetSign(double val) {
554 return(trio_signbit(val));
559 * TODO: when compatibility allows remove all "fake node libxslt" strings
560 * the test should just be name[0] = ' '
562 #ifdef DEBUG_XPATH_EXPRESSION
565 #define DEBUG_EVAL_COUNTS
568 static xmlNs xmlXPathXMLNamespaceStruct = {
576 static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
577 #ifndef LIBXML_THREAD_ENABLED
579 * Optimizer is disabled only when threaded apps are detected while
580 * the library ain't compiled for thread safety.
582 static int xmlXPathDisableOptimizer = 0;
585 /************************************************************************
587 * Error handling routines *
589 ************************************************************************/
595 * Macro to raise an XPath error and return NULL.
597 #define XP_ERRORNULL(X) \
598 { xmlXPathErr(ctxt, X); return(NULL); }
601 * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
603 static const char *xmlXPathErrorMessages[] = {
606 "Unfinished literal\n",
607 "Start of literal\n",
608 "Expected $ for variable reference\n",
609 "Undefined variable\n",
610 "Invalid predicate\n",
611 "Invalid expression\n",
612 "Missing closing curly brace\n",
613 "Unregistered function\n",
616 "Invalid number of arguments\n",
617 "Invalid context size\n",
618 "Invalid context position\n",
619 "Memory allocation error\n",
622 "Sub resource error\n",
623 "Undefined namespace prefix\n",
625 "Char out of XML range\n",
626 "Invalid or incomplete context\n",
627 "Stack usage error\n",
628 "Forbidden variable\n",
629 "?? Unknown error ??\n" /* Must be last in the list! */
631 #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
632 sizeof(xmlXPathErrorMessages[0])) - 1)
635 * @ctxt: an XPath context
636 * @extra: extra informations
638 * Handle a redefinition of attribute error
641 xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
647 xmlStrPrintf(buf, 200,
648 "Memory allocation failed : %s\n",
650 ctxt->lastError.message = (char *) xmlStrdup(buf);
652 ctxt->lastError.message = (char *)
653 xmlStrdup(BAD_CAST "Memory allocation failed\n");
655 ctxt->lastError.domain = XML_FROM_XPATH;
656 ctxt->lastError.code = XML_ERR_NO_MEMORY;
657 if (ctxt->error != NULL)
658 ctxt->error(ctxt->userData, &ctxt->lastError);
661 __xmlRaiseError(NULL, NULL, NULL,
662 NULL, NULL, XML_FROM_XPATH,
663 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
664 extra, NULL, NULL, 0, 0,
665 "Memory allocation failed : %s\n", extra);
667 __xmlRaiseError(NULL, NULL, NULL,
668 NULL, NULL, XML_FROM_XPATH,
669 XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
670 NULL, NULL, NULL, 0, 0,
671 "Memory allocation failed\n");
676 * xmlXPathPErrMemory:
677 * @ctxt: an XPath parser context
678 * @extra: extra informations
680 * Handle a redefinition of attribute error
683 xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
686 xmlXPathErrMemory(NULL, extra);
688 ctxt->error = XPATH_MEMORY_ERROR;
689 xmlXPathErrMemory(ctxt->context, extra);
695 * @ctxt: a XPath parser context
696 * @error: the error code
698 * Handle an XPath error
701 xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
703 if ((error < 0) || (error > MAXERRNO))
706 __xmlRaiseError(NULL, NULL, NULL,
707 NULL, NULL, XML_FROM_XPATH,
708 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
709 XML_ERR_ERROR, NULL, 0,
710 NULL, NULL, NULL, 0, 0,
711 "%s", xmlXPathErrorMessages[error]);
715 if (ctxt->context == NULL) {
716 __xmlRaiseError(NULL, NULL, NULL,
717 NULL, NULL, XML_FROM_XPATH,
718 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
719 XML_ERR_ERROR, NULL, 0,
720 (const char *) ctxt->base, NULL, NULL,
721 ctxt->cur - ctxt->base, 0,
722 "%s", xmlXPathErrorMessages[error]);
726 /* cleanup current last error */
727 xmlResetError(&ctxt->context->lastError);
729 ctxt->context->lastError.domain = XML_FROM_XPATH;
730 ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
732 ctxt->context->lastError.level = XML_ERR_ERROR;
733 ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
734 ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
735 ctxt->context->lastError.node = ctxt->context->debugNode;
736 if (ctxt->context->error != NULL) {
737 ctxt->context->error(ctxt->context->userData,
738 &ctxt->context->lastError);
740 __xmlRaiseError(NULL, NULL, NULL,
741 NULL, ctxt->context->debugNode, XML_FROM_XPATH,
742 error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
743 XML_ERR_ERROR, NULL, 0,
744 (const char *) ctxt->base, NULL, NULL,
745 ctxt->cur - ctxt->base, 0,
746 "%s", xmlXPathErrorMessages[error]);
753 * @ctxt: the XPath Parser context
754 * @file: the file name
755 * @line: the line number
756 * @no: the error number
758 * Formats an error message.
761 xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
762 int line ATTRIBUTE_UNUSED, int no) {
763 xmlXPathErr(ctxt, no);
766 /************************************************************************
770 ************************************************************************/
775 * Pointer-list for various purposes.
777 typedef struct _xmlPointerList xmlPointerList;
778 typedef xmlPointerList *xmlPointerListPtr;
779 struct _xmlPointerList {
785 * TODO: Since such a list-handling is used in xmlschemas.c and libxslt
786 * and here, we should make the functions public.
789 xmlPointerListAddSize(xmlPointerListPtr list,
793 if (list->items == NULL) {
794 if (initialSize <= 0)
796 list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
797 if (list->items == NULL) {
798 xmlXPathErrMemory(NULL,
799 "xmlPointerListCreate: allocating item\n");
803 list->size = initialSize;
804 } else if (list->size <= list->number) {
805 if (list->size > 50000000) {
806 xmlXPathErrMemory(NULL,
807 "xmlPointerListAddSize: re-allocating item\n");
811 list->items = (void **) xmlRealloc(list->items,
812 list->size * sizeof(void *));
813 if (list->items == NULL) {
814 xmlXPathErrMemory(NULL,
815 "xmlPointerListAddSize: re-allocating item\n");
820 list->items[list->number++] = item;
825 * xsltPointerListCreate:
827 * Creates an xsltPointerList structure.
829 * Returns a xsltPointerList structure or NULL in case of an error.
831 static xmlPointerListPtr
832 xmlPointerListCreate(int initialSize)
834 xmlPointerListPtr ret;
836 ret = xmlMalloc(sizeof(xmlPointerList));
838 xmlXPathErrMemory(NULL,
839 "xmlPointerListCreate: allocating item\n");
842 memset(ret, 0, sizeof(xmlPointerList));
843 if (initialSize > 0) {
844 xmlPointerListAddSize(ret, NULL, initialSize);
851 * xsltPointerListFree:
853 * Frees the xsltPointerList structure. This does not free
854 * the content of the list.
857 xmlPointerListFree(xmlPointerListPtr list)
861 if (list->items != NULL)
862 xmlFree(list->items);
866 /************************************************************************
870 ************************************************************************/
887 XPATH_OP_RESET, /* 10 */
889 XPATH_OP_VALUE, /* 12 */
894 XPATH_OP_FILTER, /* 17 */
895 XPATH_OP_SORT /* 18 */
896 #ifdef LIBXML_XPTR_ENABLED
903 AXIS_ANCESTOR_OR_SELF,
907 AXIS_DESCENDANT_OR_SELF,
909 AXIS_FOLLOWING_SIBLING,
913 AXIS_PRECEDING_SIBLING,
928 NODE_TYPE_COMMENT = XML_COMMENT_NODE,
929 NODE_TYPE_TEXT = XML_TEXT_NODE,
930 NODE_TYPE_PI = XML_PI_NODE
933 typedef struct _xmlXPathStepOp xmlXPathStepOp;
934 typedef xmlXPathStepOp *xmlXPathStepOpPtr;
935 struct _xmlXPathStepOp {
936 xmlXPathOp op; /* The identifier of the operation */
937 int ch1; /* First child */
938 int ch2; /* Second child */
944 xmlXPathFunction cache;
948 struct _xmlXPathCompExpr {
949 int nbStep; /* Number of steps in this expression */
950 int maxStep; /* Maximum number of steps allocated */
951 xmlXPathStepOp *steps; /* ops for computation of this expression */
952 int last; /* index of last step in expression */
953 xmlChar *expr; /* the expression being computed */
954 xmlDictPtr dict; /* the dictionary to use if any */
955 #ifdef DEBUG_EVAL_COUNTS
959 #ifdef XPATH_STREAMING
960 xmlPatternPtr stream;
964 /************************************************************************
966 * Forward declarations *
968 ************************************************************************/
970 xmlXPathFreeValueTree(xmlNodeSetPtr obj);
972 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
974 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
975 xmlXPathStepOpPtr op, xmlNodePtr *first);
977 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
978 xmlXPathStepOpPtr op,
981 /************************************************************************
983 * Parser Type functions *
985 ************************************************************************/
988 * xmlXPathNewCompExpr:
990 * Create a new Xpath component
992 * Returns the newly allocated xmlXPathCompExprPtr or NULL in case of error
994 static xmlXPathCompExprPtr
995 xmlXPathNewCompExpr(void) {
996 xmlXPathCompExprPtr cur;
998 cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
1000 xmlXPathErrMemory(NULL, "allocating component\n");
1003 memset(cur, 0, sizeof(xmlXPathCompExpr));
1006 cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
1007 sizeof(xmlXPathStepOp));
1008 if (cur->steps == NULL) {
1009 xmlXPathErrMemory(NULL, "allocating steps\n");
1013 memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
1015 #ifdef DEBUG_EVAL_COUNTS
1022 * xmlXPathFreeCompExpr:
1023 * @comp: an XPATH comp
1025 * Free up the memory allocated by @comp
1028 xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
1030 xmlXPathStepOpPtr op;
1035 if (comp->dict == NULL) {
1036 for (i = 0; i < comp->nbStep; i++) {
1037 op = &comp->steps[i];
1038 if (op->value4 != NULL) {
1039 if (op->op == XPATH_OP_VALUE)
1040 xmlXPathFreeObject(op->value4);
1042 xmlFree(op->value4);
1044 if (op->value5 != NULL)
1045 xmlFree(op->value5);
1048 for (i = 0; i < comp->nbStep; i++) {
1049 op = &comp->steps[i];
1050 if (op->value4 != NULL) {
1051 if (op->op == XPATH_OP_VALUE)
1052 xmlXPathFreeObject(op->value4);
1055 xmlDictFree(comp->dict);
1057 if (comp->steps != NULL) {
1058 xmlFree(comp->steps);
1060 #ifdef DEBUG_EVAL_COUNTS
1061 if (comp->string != NULL) {
1062 xmlFree(comp->string);
1065 #ifdef XPATH_STREAMING
1066 if (comp->stream != NULL) {
1067 xmlFreePatternList(comp->stream);
1070 if (comp->expr != NULL) {
1071 xmlFree(comp->expr);
1078 * xmlXPathCompExprAdd:
1079 * @comp: the compiled expression
1080 * @ch1: first child index
1081 * @ch2: second child index
1083 * @value: the first int value
1084 * @value2: the second int value
1085 * @value3: the third int value
1086 * @value4: the first string value
1087 * @value5: the second string value
1089 * Add a step to an XPath Compiled Expression
1091 * Returns -1 in case of failure, the index otherwise
1094 xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
1095 xmlXPathOp op, int value,
1096 int value2, int value3, void *value4, void *value5) {
1097 if (comp->nbStep >= comp->maxStep) {
1098 xmlXPathStepOp *real;
1100 if (comp->maxStep >= XPATH_MAX_STEPS) {
1101 xmlXPathErrMemory(NULL, "adding step\n");
1105 real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
1106 comp->maxStep * sizeof(xmlXPathStepOp));
1109 xmlXPathErrMemory(NULL, "adding step\n");
1114 comp->last = comp->nbStep;
1115 comp->steps[comp->nbStep].ch1 = ch1;
1116 comp->steps[comp->nbStep].ch2 = ch2;
1117 comp->steps[comp->nbStep].op = op;
1118 comp->steps[comp->nbStep].value = value;
1119 comp->steps[comp->nbStep].value2 = value2;
1120 comp->steps[comp->nbStep].value3 = value3;
1121 if ((comp->dict != NULL) &&
1122 ((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
1123 (op == XPATH_OP_COLLECT))) {
1124 if (value4 != NULL) {
1125 comp->steps[comp->nbStep].value4 = (xmlChar *)
1126 (void *)xmlDictLookup(comp->dict, value4, -1);
1129 comp->steps[comp->nbStep].value4 = NULL;
1130 if (value5 != NULL) {
1131 comp->steps[comp->nbStep].value5 = (xmlChar *)
1132 (void *)xmlDictLookup(comp->dict, value5, -1);
1135 comp->steps[comp->nbStep].value5 = NULL;
1137 comp->steps[comp->nbStep].value4 = value4;
1138 comp->steps[comp->nbStep].value5 = value5;
1140 comp->steps[comp->nbStep].cache = NULL;
1141 return(comp->nbStep++);
1146 * @comp: the compiled expression
1147 * @op: operation index
1149 * Swaps 2 operations in the compiled expression
1152 xmlXPathCompSwap(xmlXPathStepOpPtr op) {
1155 #ifndef LIBXML_THREAD_ENABLED
1157 * Since this manipulates possibly shared variables, this is
1158 * disabled if one detects that the library is used in a multithreaded
1161 if (xmlXPathDisableOptimizer)
1170 #define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
1171 xmlXPathCompExprAdd(ctxt->comp, (op1), (op2), \
1172 (op), (val), (val2), (val3), (val4), (val5))
1173 #define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
1174 xmlXPathCompExprAdd(ctxt->comp, ctxt->comp->last, -1, \
1175 (op), (val), (val2), (val3), (val4), (val5))
1177 #define PUSH_LEAVE_EXPR(op, val, val2) \
1178 xmlXPathCompExprAdd(ctxt->comp, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
1180 #define PUSH_UNARY_EXPR(op, ch, val, val2) \
1181 xmlXPathCompExprAdd(ctxt->comp, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
1183 #define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
1184 xmlXPathCompExprAdd(ctxt->comp, (ch1), (ch2), (op), \
1185 (val), (val2), 0 ,NULL ,NULL)
1187 /************************************************************************
1189 * XPath object cache structures *
1191 ************************************************************************/
1193 /* #define XP_DEFAULT_CACHE_ON */
1195 #define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
1197 typedef struct _xmlXPathContextCache xmlXPathContextCache;
1198 typedef xmlXPathContextCache *xmlXPathContextCachePtr;
1199 struct _xmlXPathContextCache {
1200 xmlPointerListPtr nodesetObjs; /* contains xmlXPathObjectPtr */
1201 xmlPointerListPtr stringObjs; /* contains xmlXPathObjectPtr */
1202 xmlPointerListPtr booleanObjs; /* contains xmlXPathObjectPtr */
1203 xmlPointerListPtr numberObjs; /* contains xmlXPathObjectPtr */
1204 xmlPointerListPtr miscObjs; /* contains xmlXPathObjectPtr */
1210 #ifdef XP_DEBUG_OBJ_USAGE
1212 int dbgCachedNodeset;
1213 int dbgCachedString;
1215 int dbgCachedNumber;
1218 int dbgCachedLocset;
1220 int dbgCachedXSLTTree;
1221 int dbgCachedUndefined;
1225 int dbgReusedNodeset;
1226 int dbgReusedString;
1228 int dbgReusedNumber;
1231 int dbgReusedLocset;
1233 int dbgReusedXSLTTree;
1234 int dbgReusedUndefined;
1239 /************************************************************************
1241 * Debugging related functions *
1243 ************************************************************************/
1246 xmlGenericError(xmlGenericErrorContext, \
1247 "Internal error at %s:%d\n", \
1248 __FILE__, __LINE__);
1250 #ifdef LIBXML_DEBUG_ENABLED
1252 xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
1256 for (i = 0;((i < depth) && (i < 25));i++)
1257 shift[2 * i] = shift[2 * i + 1] = ' ';
1258 shift[2 * i] = shift[2 * i + 1] = 0;
1260 fprintf(output, "%s", shift);
1261 fprintf(output, "Node is NULL !\n");
1266 if ((cur->type == XML_DOCUMENT_NODE) ||
1267 (cur->type == XML_HTML_DOCUMENT_NODE)) {
1268 fprintf(output, "%s", shift);
1269 fprintf(output, " /\n");
1270 } else if (cur->type == XML_ATTRIBUTE_NODE)
1271 xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
1273 xmlDebugDumpOneNode(output, cur, depth);
1276 xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
1281 for (i = 0;((i < depth) && (i < 25));i++)
1282 shift[2 * i] = shift[2 * i + 1] = ' ';
1283 shift[2 * i] = shift[2 * i + 1] = 0;
1285 fprintf(output, "%s", shift);
1286 fprintf(output, "Node is NULL !\n");
1291 while (cur != NULL) {
1294 xmlDebugDumpOneNode(output, tmp, depth);
1299 xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
1303 for (i = 0;((i < depth) && (i < 25));i++)
1304 shift[2 * i] = shift[2 * i + 1] = ' ';
1305 shift[2 * i] = shift[2 * i + 1] = 0;
1308 fprintf(output, "%s", shift);
1309 fprintf(output, "NodeSet is NULL !\n");
1315 fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
1316 for (i = 0;i < cur->nodeNr;i++) {
1317 fprintf(output, "%s", shift);
1318 fprintf(output, "%d", i + 1);
1319 xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
1325 xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
1329 for (i = 0;((i < depth) && (i < 25));i++)
1330 shift[2 * i] = shift[2 * i + 1] = ' ';
1331 shift[2 * i] = shift[2 * i + 1] = 0;
1333 if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
1334 fprintf(output, "%s", shift);
1335 fprintf(output, "Value Tree is NULL !\n");
1340 fprintf(output, "%s", shift);
1341 fprintf(output, "%d", i + 1);
1342 xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
1344 #if defined(LIBXML_XPTR_ENABLED)
1346 xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
1350 for (i = 0;((i < depth) && (i < 25));i++)
1351 shift[2 * i] = shift[2 * i + 1] = ' ';
1352 shift[2 * i] = shift[2 * i + 1] = 0;
1355 fprintf(output, "%s", shift);
1356 fprintf(output, "LocationSet is NULL !\n");
1361 for (i = 0;i < cur->locNr;i++) {
1362 fprintf(output, "%s", shift);
1363 fprintf(output, "%d : ", i + 1);
1364 xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
1367 #endif /* LIBXML_XPTR_ENABLED */
1370 * xmlXPathDebugDumpObject:
1371 * @output: the FILE * to dump the output
1372 * @cur: the object to inspect
1373 * @depth: indentation level
1375 * Dump the content of the object for debugging purposes
1378 xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
1382 if (output == NULL) return;
1384 for (i = 0;((i < depth) && (i < 25));i++)
1385 shift[2 * i] = shift[2 * i + 1] = ' ';
1386 shift[2 * i] = shift[2 * i + 1] = 0;
1389 fprintf(output, "%s", shift);
1392 fprintf(output, "Object is empty (NULL)\n");
1396 case XPATH_UNDEFINED:
1397 fprintf(output, "Object is uninitialized\n");
1400 fprintf(output, "Object is a Node Set :\n");
1401 xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
1403 case XPATH_XSLT_TREE:
1404 fprintf(output, "Object is an XSLT value tree :\n");
1405 xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
1408 fprintf(output, "Object is a Boolean : ");
1409 if (cur->boolval) fprintf(output, "true\n");
1410 else fprintf(output, "false\n");
1413 switch (xmlXPathIsInf(cur->floatval)) {
1415 fprintf(output, "Object is a number : Infinity\n");
1418 fprintf(output, "Object is a number : -Infinity\n");
1421 if (xmlXPathIsNaN(cur->floatval)) {
1422 fprintf(output, "Object is a number : NaN\n");
1423 } else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
1424 fprintf(output, "Object is a number : 0\n");
1426 fprintf(output, "Object is a number : %0g\n", cur->floatval);
1431 fprintf(output, "Object is a string : ");
1432 xmlDebugDumpString(output, cur->stringval);
1433 fprintf(output, "\n");
1436 fprintf(output, "Object is a point : index %d in node", cur->index);
1437 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
1438 fprintf(output, "\n");
1441 if ((cur->user2 == NULL) ||
1442 ((cur->user2 == cur->user) && (cur->index == cur->index2))) {
1443 fprintf(output, "Object is a collapsed range :\n");
1444 fprintf(output, "%s", shift);
1445 if (cur->index >= 0)
1446 fprintf(output, "index %d in ", cur->index);
1447 fprintf(output, "node\n");
1448 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1451 fprintf(output, "Object is a range :\n");
1452 fprintf(output, "%s", shift);
1453 fprintf(output, "From ");
1454 if (cur->index >= 0)
1455 fprintf(output, "index %d in ", cur->index);
1456 fprintf(output, "node\n");
1457 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
1459 fprintf(output, "%s", shift);
1460 fprintf(output, "To ");
1461 if (cur->index2 >= 0)
1462 fprintf(output, "index %d in ", cur->index2);
1463 fprintf(output, "node\n");
1464 xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
1466 fprintf(output, "\n");
1469 case XPATH_LOCATIONSET:
1470 #if defined(LIBXML_XPTR_ENABLED)
1471 fprintf(output, "Object is a Location Set:\n");
1472 xmlXPathDebugDumpLocationSet(output,
1473 (xmlLocationSetPtr) cur->user, depth);
1477 fprintf(output, "Object is user defined\n");
1483 xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
1484 xmlXPathStepOpPtr op, int depth) {
1488 for (i = 0;((i < depth) && (i < 25));i++)
1489 shift[2 * i] = shift[2 * i + 1] = ' ';
1490 shift[2 * i] = shift[2 * i + 1] = 0;
1492 fprintf(output, "%s", shift);
1494 fprintf(output, "Step is NULL\n");
1499 fprintf(output, "END"); break;
1501 fprintf(output, "AND"); break;
1503 fprintf(output, "OR"); break;
1504 case XPATH_OP_EQUAL:
1506 fprintf(output, "EQUAL =");
1508 fprintf(output, "EQUAL !=");
1512 fprintf(output, "CMP <");
1514 fprintf(output, "CMP >");
1516 fprintf(output, "=");
1520 fprintf(output, "PLUS -");
1521 else if (op->value == 1)
1522 fprintf(output, "PLUS +");
1523 else if (op->value == 2)
1524 fprintf(output, "PLUS unary -");
1525 else if (op->value == 3)
1526 fprintf(output, "PLUS unary - -");
1530 fprintf(output, "MULT *");
1531 else if (op->value == 1)
1532 fprintf(output, "MULT div");
1534 fprintf(output, "MULT mod");
1536 case XPATH_OP_UNION:
1537 fprintf(output, "UNION"); break;
1539 fprintf(output, "ROOT"); break;
1541 fprintf(output, "NODE"); break;
1542 case XPATH_OP_RESET:
1543 fprintf(output, "RESET"); break;
1545 fprintf(output, "SORT"); break;
1546 case XPATH_OP_COLLECT: {
1547 xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
1548 xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
1549 xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
1550 const xmlChar *prefix = op->value4;
1551 const xmlChar *name = op->value5;
1553 fprintf(output, "COLLECT ");
1556 fprintf(output, " 'ancestors' "); break;
1557 case AXIS_ANCESTOR_OR_SELF:
1558 fprintf(output, " 'ancestors-or-self' "); break;
1559 case AXIS_ATTRIBUTE:
1560 fprintf(output, " 'attributes' "); break;
1562 fprintf(output, " 'child' "); break;
1563 case AXIS_DESCENDANT:
1564 fprintf(output, " 'descendant' "); break;
1565 case AXIS_DESCENDANT_OR_SELF:
1566 fprintf(output, " 'descendant-or-self' "); break;
1567 case AXIS_FOLLOWING:
1568 fprintf(output, " 'following' "); break;
1569 case AXIS_FOLLOWING_SIBLING:
1570 fprintf(output, " 'following-siblings' "); break;
1571 case AXIS_NAMESPACE:
1572 fprintf(output, " 'namespace' "); break;
1574 fprintf(output, " 'parent' "); break;
1575 case AXIS_PRECEDING:
1576 fprintf(output, " 'preceding' "); break;
1577 case AXIS_PRECEDING_SIBLING:
1578 fprintf(output, " 'preceding-sibling' "); break;
1580 fprintf(output, " 'self' "); break;
1583 case NODE_TEST_NONE:
1584 fprintf(output, "'none' "); break;
1585 case NODE_TEST_TYPE:
1586 fprintf(output, "'type' "); break;
1588 fprintf(output, "'PI' "); break;
1590 fprintf(output, "'all' "); break;
1592 fprintf(output, "'namespace' "); break;
1593 case NODE_TEST_NAME:
1594 fprintf(output, "'name' "); break;
1597 case NODE_TYPE_NODE:
1598 fprintf(output, "'node' "); break;
1599 case NODE_TYPE_COMMENT:
1600 fprintf(output, "'comment' "); break;
1601 case NODE_TYPE_TEXT:
1602 fprintf(output, "'text' "); break;
1604 fprintf(output, "'PI' "); break;
1607 fprintf(output, "%s:", prefix);
1609 fprintf(output, "%s", (const char *) name);
1613 case XPATH_OP_VALUE: {
1614 xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
1616 fprintf(output, "ELEM ");
1617 xmlXPathDebugDumpObject(output, object, 0);
1620 case XPATH_OP_VARIABLE: {
1621 const xmlChar *prefix = op->value5;
1622 const xmlChar *name = op->value4;
1625 fprintf(output, "VARIABLE %s:%s", prefix, name);
1627 fprintf(output, "VARIABLE %s", name);
1630 case XPATH_OP_FUNCTION: {
1631 int nbargs = op->value;
1632 const xmlChar *prefix = op->value5;
1633 const xmlChar *name = op->value4;
1636 fprintf(output, "FUNCTION %s:%s(%d args)",
1637 prefix, name, nbargs);
1639 fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
1642 case XPATH_OP_ARG: fprintf(output, "ARG"); break;
1643 case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
1644 case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
1645 #ifdef LIBXML_XPTR_ENABLED
1646 case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
1649 fprintf(output, "UNKNOWN %d\n", op->op); return;
1651 fprintf(output, "\n");
1654 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
1656 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
1660 * xmlXPathDebugDumpCompExpr:
1661 * @output: the FILE * for the output
1662 * @comp: the precompiled XPath expression
1663 * @depth: the indentation level.
1665 * Dumps the tree of the compiled XPath expression.
1668 xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
1673 if ((output == NULL) || (comp == NULL)) return;
1675 for (i = 0;((i < depth) && (i < 25));i++)
1676 shift[2 * i] = shift[2 * i + 1] = ' ';
1677 shift[2 * i] = shift[2 * i + 1] = 0;
1679 fprintf(output, "%s", shift);
1681 #ifdef XPATH_STREAMING
1683 fprintf(output, "Streaming Expression\n");
1687 fprintf(output, "Compiled Expression : %d elements\n",
1690 xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
1694 #ifdef XP_DEBUG_OBJ_USAGE
1697 * XPath object usage related debugging variables.
1699 static int xmlXPathDebugObjCounterUndefined = 0;
1700 static int xmlXPathDebugObjCounterNodeset = 0;
1701 static int xmlXPathDebugObjCounterBool = 0;
1702 static int xmlXPathDebugObjCounterNumber = 0;
1703 static int xmlXPathDebugObjCounterString = 0;
1704 static int xmlXPathDebugObjCounterPoint = 0;
1705 static int xmlXPathDebugObjCounterRange = 0;
1706 static int xmlXPathDebugObjCounterLocset = 0;
1707 static int xmlXPathDebugObjCounterUsers = 0;
1708 static int xmlXPathDebugObjCounterXSLTTree = 0;
1709 static int xmlXPathDebugObjCounterAll = 0;
1711 static int xmlXPathDebugObjTotalUndefined = 0;
1712 static int xmlXPathDebugObjTotalNodeset = 0;
1713 static int xmlXPathDebugObjTotalBool = 0;
1714 static int xmlXPathDebugObjTotalNumber = 0;
1715 static int xmlXPathDebugObjTotalString = 0;
1716 static int xmlXPathDebugObjTotalPoint = 0;
1717 static int xmlXPathDebugObjTotalRange = 0;
1718 static int xmlXPathDebugObjTotalLocset = 0;
1719 static int xmlXPathDebugObjTotalUsers = 0;
1720 static int xmlXPathDebugObjTotalXSLTTree = 0;
1721 static int xmlXPathDebugObjTotalAll = 0;
1723 static int xmlXPathDebugObjMaxUndefined = 0;
1724 static int xmlXPathDebugObjMaxNodeset = 0;
1725 static int xmlXPathDebugObjMaxBool = 0;
1726 static int xmlXPathDebugObjMaxNumber = 0;
1727 static int xmlXPathDebugObjMaxString = 0;
1728 static int xmlXPathDebugObjMaxPoint = 0;
1729 static int xmlXPathDebugObjMaxRange = 0;
1730 static int xmlXPathDebugObjMaxLocset = 0;
1731 static int xmlXPathDebugObjMaxUsers = 0;
1732 static int xmlXPathDebugObjMaxXSLTTree = 0;
1733 static int xmlXPathDebugObjMaxAll = 0;
1735 /* REVISIT TODO: Make this static when committing */
1737 xmlXPathDebugObjUsageReset(xmlXPathContextPtr ctxt)
1740 if (ctxt->cache != NULL) {
1741 xmlXPathContextCachePtr cache =
1742 (xmlXPathContextCachePtr) ctxt->cache;
1744 cache->dbgCachedAll = 0;
1745 cache->dbgCachedNodeset = 0;
1746 cache->dbgCachedString = 0;
1747 cache->dbgCachedBool = 0;
1748 cache->dbgCachedNumber = 0;
1749 cache->dbgCachedPoint = 0;
1750 cache->dbgCachedRange = 0;
1751 cache->dbgCachedLocset = 0;
1752 cache->dbgCachedUsers = 0;
1753 cache->dbgCachedXSLTTree = 0;
1754 cache->dbgCachedUndefined = 0;
1756 cache->dbgReusedAll = 0;
1757 cache->dbgReusedNodeset = 0;
1758 cache->dbgReusedString = 0;
1759 cache->dbgReusedBool = 0;
1760 cache->dbgReusedNumber = 0;
1761 cache->dbgReusedPoint = 0;
1762 cache->dbgReusedRange = 0;
1763 cache->dbgReusedLocset = 0;
1764 cache->dbgReusedUsers = 0;
1765 cache->dbgReusedXSLTTree = 0;
1766 cache->dbgReusedUndefined = 0;
1770 xmlXPathDebugObjCounterUndefined = 0;
1771 xmlXPathDebugObjCounterNodeset = 0;
1772 xmlXPathDebugObjCounterBool = 0;
1773 xmlXPathDebugObjCounterNumber = 0;
1774 xmlXPathDebugObjCounterString = 0;
1775 xmlXPathDebugObjCounterPoint = 0;
1776 xmlXPathDebugObjCounterRange = 0;
1777 xmlXPathDebugObjCounterLocset = 0;
1778 xmlXPathDebugObjCounterUsers = 0;
1779 xmlXPathDebugObjCounterXSLTTree = 0;
1780 xmlXPathDebugObjCounterAll = 0;
1782 xmlXPathDebugObjTotalUndefined = 0;
1783 xmlXPathDebugObjTotalNodeset = 0;
1784 xmlXPathDebugObjTotalBool = 0;
1785 xmlXPathDebugObjTotalNumber = 0;
1786 xmlXPathDebugObjTotalString = 0;
1787 xmlXPathDebugObjTotalPoint = 0;
1788 xmlXPathDebugObjTotalRange = 0;
1789 xmlXPathDebugObjTotalLocset = 0;
1790 xmlXPathDebugObjTotalUsers = 0;
1791 xmlXPathDebugObjTotalXSLTTree = 0;
1792 xmlXPathDebugObjTotalAll = 0;
1794 xmlXPathDebugObjMaxUndefined = 0;
1795 xmlXPathDebugObjMaxNodeset = 0;
1796 xmlXPathDebugObjMaxBool = 0;
1797 xmlXPathDebugObjMaxNumber = 0;
1798 xmlXPathDebugObjMaxString = 0;
1799 xmlXPathDebugObjMaxPoint = 0;
1800 xmlXPathDebugObjMaxRange = 0;
1801 xmlXPathDebugObjMaxLocset = 0;
1802 xmlXPathDebugObjMaxUsers = 0;
1803 xmlXPathDebugObjMaxXSLTTree = 0;
1804 xmlXPathDebugObjMaxAll = 0;
1809 xmlXPathDebugObjUsageRequested(xmlXPathContextPtr ctxt,
1810 xmlXPathObjectType objType)
1815 if (ctxt->cache != NULL) {
1816 xmlXPathContextCachePtr cache =
1817 (xmlXPathContextCachePtr) ctxt->cache;
1821 cache->dbgReusedAll++;
1823 case XPATH_UNDEFINED:
1824 cache->dbgReusedUndefined++;
1827 cache->dbgReusedNodeset++;
1830 cache->dbgReusedBool++;
1833 cache->dbgReusedNumber++;
1836 cache->dbgReusedString++;
1839 cache->dbgReusedPoint++;
1842 cache->dbgReusedRange++;
1844 case XPATH_LOCATIONSET:
1845 cache->dbgReusedLocset++;
1848 cache->dbgReusedUsers++;
1850 case XPATH_XSLT_TREE:
1851 cache->dbgReusedXSLTTree++;
1860 case XPATH_UNDEFINED:
1862 xmlXPathDebugObjTotalUndefined++;
1863 xmlXPathDebugObjCounterUndefined++;
1864 if (xmlXPathDebugObjCounterUndefined >
1865 xmlXPathDebugObjMaxUndefined)
1866 xmlXPathDebugObjMaxUndefined =
1867 xmlXPathDebugObjCounterUndefined;
1871 xmlXPathDebugObjTotalNodeset++;
1872 xmlXPathDebugObjCounterNodeset++;
1873 if (xmlXPathDebugObjCounterNodeset >
1874 xmlXPathDebugObjMaxNodeset)
1875 xmlXPathDebugObjMaxNodeset =
1876 xmlXPathDebugObjCounterNodeset;
1880 xmlXPathDebugObjTotalBool++;
1881 xmlXPathDebugObjCounterBool++;
1882 if (xmlXPathDebugObjCounterBool >
1883 xmlXPathDebugObjMaxBool)
1884 xmlXPathDebugObjMaxBool =
1885 xmlXPathDebugObjCounterBool;
1889 xmlXPathDebugObjTotalNumber++;
1890 xmlXPathDebugObjCounterNumber++;
1891 if (xmlXPathDebugObjCounterNumber >
1892 xmlXPathDebugObjMaxNumber)
1893 xmlXPathDebugObjMaxNumber =
1894 xmlXPathDebugObjCounterNumber;
1898 xmlXPathDebugObjTotalString++;
1899 xmlXPathDebugObjCounterString++;
1900 if (xmlXPathDebugObjCounterString >
1901 xmlXPathDebugObjMaxString)
1902 xmlXPathDebugObjMaxString =
1903 xmlXPathDebugObjCounterString;
1907 xmlXPathDebugObjTotalPoint++;
1908 xmlXPathDebugObjCounterPoint++;
1909 if (xmlXPathDebugObjCounterPoint >
1910 xmlXPathDebugObjMaxPoint)
1911 xmlXPathDebugObjMaxPoint =
1912 xmlXPathDebugObjCounterPoint;
1916 xmlXPathDebugObjTotalRange++;
1917 xmlXPathDebugObjCounterRange++;
1918 if (xmlXPathDebugObjCounterRange >
1919 xmlXPathDebugObjMaxRange)
1920 xmlXPathDebugObjMaxRange =
1921 xmlXPathDebugObjCounterRange;
1923 case XPATH_LOCATIONSET:
1925 xmlXPathDebugObjTotalLocset++;
1926 xmlXPathDebugObjCounterLocset++;
1927 if (xmlXPathDebugObjCounterLocset >
1928 xmlXPathDebugObjMaxLocset)
1929 xmlXPathDebugObjMaxLocset =
1930 xmlXPathDebugObjCounterLocset;
1934 xmlXPathDebugObjTotalUsers++;
1935 xmlXPathDebugObjCounterUsers++;
1936 if (xmlXPathDebugObjCounterUsers >
1937 xmlXPathDebugObjMaxUsers)
1938 xmlXPathDebugObjMaxUsers =
1939 xmlXPathDebugObjCounterUsers;
1941 case XPATH_XSLT_TREE:
1943 xmlXPathDebugObjTotalXSLTTree++;
1944 xmlXPathDebugObjCounterXSLTTree++;
1945 if (xmlXPathDebugObjCounterXSLTTree >
1946 xmlXPathDebugObjMaxXSLTTree)
1947 xmlXPathDebugObjMaxXSLTTree =
1948 xmlXPathDebugObjCounterXSLTTree;
1954 xmlXPathDebugObjTotalAll++;
1955 xmlXPathDebugObjCounterAll++;
1956 if (xmlXPathDebugObjCounterAll >
1957 xmlXPathDebugObjMaxAll)
1958 xmlXPathDebugObjMaxAll =
1959 xmlXPathDebugObjCounterAll;
1963 xmlXPathDebugObjUsageReleased(xmlXPathContextPtr ctxt,
1964 xmlXPathObjectType objType)
1969 if (ctxt->cache != NULL) {
1970 xmlXPathContextCachePtr cache =
1971 (xmlXPathContextCachePtr) ctxt->cache;
1975 cache->dbgCachedAll++;
1977 case XPATH_UNDEFINED:
1978 cache->dbgCachedUndefined++;
1981 cache->dbgCachedNodeset++;
1984 cache->dbgCachedBool++;
1987 cache->dbgCachedNumber++;
1990 cache->dbgCachedString++;
1993 cache->dbgCachedPoint++;
1996 cache->dbgCachedRange++;
1998 case XPATH_LOCATIONSET:
1999 cache->dbgCachedLocset++;
2002 cache->dbgCachedUsers++;
2004 case XPATH_XSLT_TREE:
2005 cache->dbgCachedXSLTTree++;
2014 case XPATH_UNDEFINED:
2015 xmlXPathDebugObjCounterUndefined--;
2018 xmlXPathDebugObjCounterNodeset--;
2021 xmlXPathDebugObjCounterBool--;
2024 xmlXPathDebugObjCounterNumber--;
2027 xmlXPathDebugObjCounterString--;
2030 xmlXPathDebugObjCounterPoint--;
2033 xmlXPathDebugObjCounterRange--;
2035 case XPATH_LOCATIONSET:
2036 xmlXPathDebugObjCounterLocset--;
2039 xmlXPathDebugObjCounterUsers--;
2041 case XPATH_XSLT_TREE:
2042 xmlXPathDebugObjCounterXSLTTree--;
2047 xmlXPathDebugObjCounterAll--;
2050 /* REVISIT TODO: Make this static when committing */
2052 xmlXPathDebugObjUsageDisplay(xmlXPathContextPtr ctxt)
2054 int reqAll, reqNodeset, reqString, reqBool, reqNumber,
2055 reqXSLTTree, reqUndefined;
2056 int caAll = 0, caNodeset = 0, caString = 0, caBool = 0,
2057 caNumber = 0, caXSLTTree = 0, caUndefined = 0;
2058 int reAll = 0, reNodeset = 0, reString = 0, reBool = 0,
2059 reNumber = 0, reXSLTTree = 0, reUndefined = 0;
2060 int leftObjs = xmlXPathDebugObjCounterAll;
2062 reqAll = xmlXPathDebugObjTotalAll;
2063 reqNodeset = xmlXPathDebugObjTotalNodeset;
2064 reqString = xmlXPathDebugObjTotalString;
2065 reqBool = xmlXPathDebugObjTotalBool;
2066 reqNumber = xmlXPathDebugObjTotalNumber;
2067 reqXSLTTree = xmlXPathDebugObjTotalXSLTTree;
2068 reqUndefined = xmlXPathDebugObjTotalUndefined;
2070 printf("# XPath object usage:\n");
2073 if (ctxt->cache != NULL) {
2074 xmlXPathContextCachePtr cache =
2075 (xmlXPathContextCachePtr) ctxt->cache;
2077 reAll = cache->dbgReusedAll;
2079 reNodeset = cache->dbgReusedNodeset;
2080 reqNodeset += reNodeset;
2081 reString = cache->dbgReusedString;
2082 reqString += reString;
2083 reBool = cache->dbgReusedBool;
2085 reNumber = cache->dbgReusedNumber;
2086 reqNumber += reNumber;
2087 reXSLTTree = cache->dbgReusedXSLTTree;
2088 reqXSLTTree += reXSLTTree;
2089 reUndefined = cache->dbgReusedUndefined;
2090 reqUndefined += reUndefined;
2092 caAll = cache->dbgCachedAll;
2093 caBool = cache->dbgCachedBool;
2094 caNodeset = cache->dbgCachedNodeset;
2095 caString = cache->dbgCachedString;
2096 caNumber = cache->dbgCachedNumber;
2097 caXSLTTree = cache->dbgCachedXSLTTree;
2098 caUndefined = cache->dbgCachedUndefined;
2100 if (cache->nodesetObjs)
2101 leftObjs -= cache->nodesetObjs->number;
2102 if (cache->stringObjs)
2103 leftObjs -= cache->stringObjs->number;
2104 if (cache->booleanObjs)
2105 leftObjs -= cache->booleanObjs->number;
2106 if (cache->numberObjs)
2107 leftObjs -= cache->numberObjs->number;
2108 if (cache->miscObjs)
2109 leftObjs -= cache->miscObjs->number;
2114 printf("# total : %d\n", reqAll);
2115 printf("# left : %d\n", leftObjs);
2116 printf("# created: %d\n", xmlXPathDebugObjTotalAll);
2117 printf("# reused : %d\n", reAll);
2118 printf("# max : %d\n", xmlXPathDebugObjMaxAll);
2120 printf("# node-sets\n");
2121 printf("# total : %d\n", reqNodeset);
2122 printf("# created: %d\n", xmlXPathDebugObjTotalNodeset);
2123 printf("# reused : %d\n", reNodeset);
2124 printf("# max : %d\n", xmlXPathDebugObjMaxNodeset);
2126 printf("# strings\n");
2127 printf("# total : %d\n", reqString);
2128 printf("# created: %d\n", xmlXPathDebugObjTotalString);
2129 printf("# reused : %d\n", reString);
2130 printf("# max : %d\n", xmlXPathDebugObjMaxString);
2132 printf("# booleans\n");
2133 printf("# total : %d\n", reqBool);
2134 printf("# created: %d\n", xmlXPathDebugObjTotalBool);
2135 printf("# reused : %d\n", reBool);
2136 printf("# max : %d\n", xmlXPathDebugObjMaxBool);
2138 printf("# numbers\n");
2139 printf("# total : %d\n", reqNumber);
2140 printf("# created: %d\n", xmlXPathDebugObjTotalNumber);
2141 printf("# reused : %d\n", reNumber);
2142 printf("# max : %d\n", xmlXPathDebugObjMaxNumber);
2144 printf("# XSLT result tree fragments\n");
2145 printf("# total : %d\n", reqXSLTTree);
2146 printf("# created: %d\n", xmlXPathDebugObjTotalXSLTTree);
2147 printf("# reused : %d\n", reXSLTTree);
2148 printf("# max : %d\n", xmlXPathDebugObjMaxXSLTTree);
2150 printf("# undefined\n");
2151 printf("# total : %d\n", reqUndefined);
2152 printf("# created: %d\n", xmlXPathDebugObjTotalUndefined);
2153 printf("# reused : %d\n", reUndefined);
2154 printf("# max : %d\n", xmlXPathDebugObjMaxUndefined);
2158 #endif /* XP_DEBUG_OBJ_USAGE */
2160 #endif /* LIBXML_DEBUG_ENABLED */
2162 /************************************************************************
2164 * XPath object caching *
2166 ************************************************************************/
2171 * Create a new object cache
2173 * Returns the xmlXPathCache just allocated.
2175 static xmlXPathContextCachePtr
2176 xmlXPathNewCache(void)
2178 xmlXPathContextCachePtr ret;
2180 ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
2182 xmlXPathErrMemory(NULL, "creating object cache\n");
2185 memset(ret, 0 , (size_t) sizeof(xmlXPathContextCache));
2186 ret->maxNodeset = 100;
2187 ret->maxString = 100;
2188 ret->maxBoolean = 100;
2189 ret->maxNumber = 100;
2195 xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
2198 xmlXPathObjectPtr obj;
2203 for (i = 0; i < list->number; i++) {
2204 obj = list->items[i];
2206 * Note that it is already assured that we don't need to
2207 * look out for namespace nodes in the node-set.
2209 if (obj->nodesetval != NULL) {
2210 if (obj->nodesetval->nodeTab != NULL)
2211 xmlFree(obj->nodesetval->nodeTab);
2212 xmlFree(obj->nodesetval);
2215 #ifdef XP_DEBUG_OBJ_USAGE
2216 xmlXPathDebugObjCounterAll--;
2219 xmlPointerListFree(list);
2223 xmlXPathFreeCache(xmlXPathContextCachePtr cache)
2227 if (cache->nodesetObjs)
2228 xmlXPathCacheFreeObjectList(cache->nodesetObjs);
2229 if (cache->stringObjs)
2230 xmlXPathCacheFreeObjectList(cache->stringObjs);
2231 if (cache->booleanObjs)
2232 xmlXPathCacheFreeObjectList(cache->booleanObjs);
2233 if (cache->numberObjs)
2234 xmlXPathCacheFreeObjectList(cache->numberObjs);
2235 if (cache->miscObjs)
2236 xmlXPathCacheFreeObjectList(cache->miscObjs);
2241 * xmlXPathContextSetCache:
2243 * @ctxt: the XPath context
2244 * @active: enables/disables (creates/frees) the cache
2245 * @value: a value with semantics dependant on @options
2246 * @options: options (currently only the value 0 is used)
2248 * Creates/frees an object cache on the XPath context.
2249 * If activates XPath objects (xmlXPathObject) will be cached internally
2252 * 0: This will set the XPath object caching:
2254 * This will set the maximum number of XPath objects
2255 * to be cached per slot
2256 * There are 5 slots for: node-set, string, number, boolean, and
2257 * misc objects. Use <0 for the default number (100).
2258 * Other values for @options have currently no effect.
2260 * Returns 0 if the setting succeeded, and -1 on API or internal errors.
2263 xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
2271 xmlXPathContextCachePtr cache;
2273 if (ctxt->cache == NULL) {
2274 ctxt->cache = xmlXPathNewCache();
2275 if (ctxt->cache == NULL)
2278 cache = (xmlXPathContextCachePtr) ctxt->cache;
2282 cache->maxNodeset = value;
2283 cache->maxString = value;
2284 cache->maxNumber = value;
2285 cache->maxBoolean = value;
2286 cache->maxMisc = value;
2288 } else if (ctxt->cache != NULL) {
2289 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
2296 * xmlXPathCacheWrapNodeSet:
2297 * @ctxt: the XPath context
2298 * @val: the NodePtr value
2300 * This is the cached version of xmlXPathWrapNodeSet().
2301 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
2303 * Returns the created or reused object.
2305 static xmlXPathObjectPtr
2306 xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
2308 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2309 xmlXPathContextCachePtr cache =
2310 (xmlXPathContextCachePtr) ctxt->cache;
2312 if ((cache->miscObjs != NULL) &&
2313 (cache->miscObjs->number != 0))
2315 xmlXPathObjectPtr ret;
2317 ret = (xmlXPathObjectPtr)
2318 cache->miscObjs->items[--cache->miscObjs->number];
2319 ret->type = XPATH_NODESET;
2320 ret->nodesetval = val;
2321 #ifdef XP_DEBUG_OBJ_USAGE
2322 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2328 return(xmlXPathWrapNodeSet(val));
2333 * xmlXPathCacheWrapString:
2334 * @ctxt: the XPath context
2335 * @val: the xmlChar * value
2337 * This is the cached version of xmlXPathWrapString().
2338 * Wraps the @val string into an XPath object.
2340 * Returns the created or reused object.
2342 static xmlXPathObjectPtr
2343 xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
2345 if ((ctxt != NULL) && (ctxt->cache != NULL)) {
2346 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2348 if ((cache->stringObjs != NULL) &&
2349 (cache->stringObjs->number != 0))
2352 xmlXPathObjectPtr ret;
2354 ret = (xmlXPathObjectPtr)
2355 cache->stringObjs->items[--cache->stringObjs->number];
2356 ret->type = XPATH_STRING;
2357 ret->stringval = val;
2358 #ifdef XP_DEBUG_OBJ_USAGE
2359 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2362 } else if ((cache->miscObjs != NULL) &&
2363 (cache->miscObjs->number != 0))
2365 xmlXPathObjectPtr ret;
2367 * Fallback to misc-cache.
2369 ret = (xmlXPathObjectPtr)
2370 cache->miscObjs->items[--cache->miscObjs->number];
2372 ret->type = XPATH_STRING;
2373 ret->stringval = val;
2374 #ifdef XP_DEBUG_OBJ_USAGE
2375 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2380 return(xmlXPathWrapString(val));
2384 * xmlXPathCacheNewNodeSet:
2385 * @ctxt: the XPath context
2386 * @val: the NodePtr value
2388 * This is the cached version of xmlXPathNewNodeSet().
2389 * Acquire an xmlXPathObjectPtr of type NodeSet and initialize
2390 * it with the single Node @val
2392 * Returns the created or reused object.
2394 static xmlXPathObjectPtr
2395 xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
2397 if ((ctxt != NULL) && (ctxt->cache)) {
2398 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2400 if ((cache->nodesetObjs != NULL) &&
2401 (cache->nodesetObjs->number != 0))
2403 xmlXPathObjectPtr ret;
2405 * Use the nodset-cache.
2407 ret = (xmlXPathObjectPtr)
2408 cache->nodesetObjs->items[--cache->nodesetObjs->number];
2409 ret->type = XPATH_NODESET;
2412 if ((ret->nodesetval->nodeMax == 0) ||
2413 (val->type == XML_NAMESPACE_DECL))
2415 xmlXPathNodeSetAddUnique(ret->nodesetval, val);
2417 ret->nodesetval->nodeTab[0] = val;
2418 ret->nodesetval->nodeNr = 1;
2421 #ifdef XP_DEBUG_OBJ_USAGE
2422 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2425 } else if ((cache->miscObjs != NULL) &&
2426 (cache->miscObjs->number != 0))
2428 xmlXPathObjectPtr ret;
2430 * Fallback to misc-cache.
2433 ret = (xmlXPathObjectPtr)
2434 cache->miscObjs->items[--cache->miscObjs->number];
2436 ret->type = XPATH_NODESET;
2438 ret->nodesetval = xmlXPathNodeSetCreate(val);
2439 if (ret->nodesetval == NULL) {
2440 ctxt->lastError.domain = XML_FROM_XPATH;
2441 ctxt->lastError.code = XML_ERR_NO_MEMORY;
2444 #ifdef XP_DEBUG_OBJ_USAGE
2445 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
2450 return(xmlXPathNewNodeSet(val));
2454 * xmlXPathCacheNewCString:
2455 * @ctxt: the XPath context
2456 * @val: the char * value
2458 * This is the cached version of xmlXPathNewCString().
2459 * Acquire an xmlXPathObjectPtr of type string and of value @val
2461 * Returns the created or reused object.
2463 static xmlXPathObjectPtr
2464 xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
2466 if ((ctxt != NULL) && (ctxt->cache)) {
2467 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2469 if ((cache->stringObjs != NULL) &&
2470 (cache->stringObjs->number != 0))
2472 xmlXPathObjectPtr ret;
2474 ret = (xmlXPathObjectPtr)
2475 cache->stringObjs->items[--cache->stringObjs->number];
2477 ret->type = XPATH_STRING;
2478 ret->stringval = xmlStrdup(BAD_CAST val);
2479 #ifdef XP_DEBUG_OBJ_USAGE
2480 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2483 } else if ((cache->miscObjs != NULL) &&
2484 (cache->miscObjs->number != 0))
2486 xmlXPathObjectPtr ret;
2488 ret = (xmlXPathObjectPtr)
2489 cache->miscObjs->items[--cache->miscObjs->number];
2491 ret->type = XPATH_STRING;
2492 ret->stringval = xmlStrdup(BAD_CAST val);
2493 #ifdef XP_DEBUG_OBJ_USAGE
2494 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2499 return(xmlXPathNewCString(val));
2503 * xmlXPathCacheNewString:
2504 * @ctxt: the XPath context
2505 * @val: the xmlChar * value
2507 * This is the cached version of xmlXPathNewString().
2508 * Acquire an xmlXPathObjectPtr of type string and of value @val
2510 * Returns the created or reused object.
2512 static xmlXPathObjectPtr
2513 xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
2515 if ((ctxt != NULL) && (ctxt->cache)) {
2516 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2518 if ((cache->stringObjs != NULL) &&
2519 (cache->stringObjs->number != 0))
2521 xmlXPathObjectPtr ret;
2523 ret = (xmlXPathObjectPtr)
2524 cache->stringObjs->items[--cache->stringObjs->number];
2525 ret->type = XPATH_STRING;
2527 ret->stringval = xmlStrdup(val);
2529 ret->stringval = xmlStrdup((const xmlChar *)"");
2530 #ifdef XP_DEBUG_OBJ_USAGE
2531 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2534 } else if ((cache->miscObjs != NULL) &&
2535 (cache->miscObjs->number != 0))
2537 xmlXPathObjectPtr ret;
2539 ret = (xmlXPathObjectPtr)
2540 cache->miscObjs->items[--cache->miscObjs->number];
2542 ret->type = XPATH_STRING;
2544 ret->stringval = xmlStrdup(val);
2546 ret->stringval = xmlStrdup((const xmlChar *)"");
2547 #ifdef XP_DEBUG_OBJ_USAGE
2548 xmlXPathDebugObjUsageRequested(ctxt, XPATH_STRING);
2553 return(xmlXPathNewString(val));
2557 * xmlXPathCacheNewBoolean:
2558 * @ctxt: the XPath context
2559 * @val: the boolean value
2561 * This is the cached version of xmlXPathNewBoolean().
2562 * Acquires an xmlXPathObjectPtr of type boolean and of value @val
2564 * Returns the created or reused object.
2566 static xmlXPathObjectPtr
2567 xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
2569 if ((ctxt != NULL) && (ctxt->cache)) {
2570 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2572 if ((cache->booleanObjs != NULL) &&
2573 (cache->booleanObjs->number != 0))
2575 xmlXPathObjectPtr ret;
2577 ret = (xmlXPathObjectPtr)
2578 cache->booleanObjs->items[--cache->booleanObjs->number];
2579 ret->type = XPATH_BOOLEAN;
2580 ret->boolval = (val != 0);
2581 #ifdef XP_DEBUG_OBJ_USAGE
2582 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2585 } else if ((cache->miscObjs != NULL) &&
2586 (cache->miscObjs->number != 0))
2588 xmlXPathObjectPtr ret;
2590 ret = (xmlXPathObjectPtr)
2591 cache->miscObjs->items[--cache->miscObjs->number];
2593 ret->type = XPATH_BOOLEAN;
2594 ret->boolval = (val != 0);
2595 #ifdef XP_DEBUG_OBJ_USAGE
2596 xmlXPathDebugObjUsageRequested(ctxt, XPATH_BOOLEAN);
2601 return(xmlXPathNewBoolean(val));
2605 * xmlXPathCacheNewFloat:
2606 * @ctxt: the XPath context
2607 * @val: the double value
2609 * This is the cached version of xmlXPathNewFloat().
2610 * Acquires an xmlXPathObjectPtr of type double and of value @val
2612 * Returns the created or reused object.
2614 static xmlXPathObjectPtr
2615 xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
2617 if ((ctxt != NULL) && (ctxt->cache)) {
2618 xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
2620 if ((cache->numberObjs != NULL) &&
2621 (cache->numberObjs->number != 0))
2623 xmlXPathObjectPtr ret;
2625 ret = (xmlXPathObjectPtr)
2626 cache->numberObjs->items[--cache->numberObjs->number];
2627 ret->type = XPATH_NUMBER;
2628 ret->floatval = val;
2629 #ifdef XP_DEBUG_OBJ_USAGE
2630 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2633 } else if ((cache->miscObjs != NULL) &&
2634 (cache->miscObjs->number != 0))
2636 xmlXPathObjectPtr ret;
2638 ret = (xmlXPathObjectPtr)
2639 cache->miscObjs->items[--cache->miscObjs->number];
2641 ret->type = XPATH_NUMBER;
2642 ret->floatval = val;
2643 #ifdef XP_DEBUG_OBJ_USAGE
2644 xmlXPathDebugObjUsageRequested(ctxt, XPATH_NUMBER);
2649 return(xmlXPathNewFloat(val));
2653 * xmlXPathCacheConvertString:
2654 * @ctxt: the XPath context
2655 * @val: an XPath object
2657 * This is the cached version of xmlXPathConvertString().
2658 * Converts an existing object to its string() equivalent
2660 * Returns a created or reused object, the old one is freed (cached)
2661 * (or the operation is done directly on @val)
2664 static xmlXPathObjectPtr
2665 xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2666 xmlChar *res = NULL;
2669 return(xmlXPathCacheNewCString(ctxt, ""));
2671 switch (val->type) {
2672 case XPATH_UNDEFINED:
2674 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
2678 case XPATH_XSLT_TREE:
2679 res = xmlXPathCastNodeSetToString(val->nodesetval);
2684 res = xmlXPathCastBooleanToString(val->boolval);
2687 res = xmlXPathCastNumberToString(val->floatval);
2692 case XPATH_LOCATIONSET:
2696 xmlXPathReleaseObject(ctxt, val);
2698 return(xmlXPathCacheNewCString(ctxt, ""));
2699 return(xmlXPathCacheWrapString(ctxt, res));
2703 * xmlXPathCacheObjectCopy:
2704 * @ctxt: the XPath context
2705 * @val: the original object
2707 * This is the cached version of xmlXPathObjectCopy().
2708 * Acquire a copy of a given object
2710 * Returns a created or reused created object.
2712 static xmlXPathObjectPtr
2713 xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
2718 if (XP_HAS_CACHE(ctxt)) {
2719 switch (val->type) {
2721 return(xmlXPathCacheWrapNodeSet(ctxt,
2722 xmlXPathNodeSetMerge(NULL, val->nodesetval)));
2724 return(xmlXPathCacheNewString(ctxt, val->stringval));
2726 return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
2728 return(xmlXPathCacheNewFloat(ctxt, val->floatval));
2733 return(xmlXPathObjectCopy(val));
2737 * xmlXPathCacheConvertBoolean:
2738 * @ctxt: the XPath context
2739 * @val: an XPath object
2741 * This is the cached version of xmlXPathConvertBoolean().
2742 * Converts an existing object to its boolean() equivalent
2744 * Returns a created or reused object, the old one is freed (or the operation
2745 * is done directly on @val)
2747 static xmlXPathObjectPtr
2748 xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2749 xmlXPathObjectPtr ret;
2752 return(xmlXPathCacheNewBoolean(ctxt, 0));
2753 if (val->type == XPATH_BOOLEAN)
2755 ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
2756 xmlXPathReleaseObject(ctxt, val);
2761 * xmlXPathCacheConvertNumber:
2762 * @ctxt: the XPath context
2763 * @val: an XPath object
2765 * This is the cached version of xmlXPathConvertNumber().
2766 * Converts an existing object to its number() equivalent
2768 * Returns a created or reused object, the old one is freed (or the operation
2769 * is done directly on @val)
2771 static xmlXPathObjectPtr
2772 xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
2773 xmlXPathObjectPtr ret;
2776 return(xmlXPathCacheNewFloat(ctxt, 0.0));
2777 if (val->type == XPATH_NUMBER)
2779 ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
2780 xmlXPathReleaseObject(ctxt, val);
2784 /************************************************************************
2786 * Parser stacks related functions and macros *
2788 ************************************************************************/
2792 * @ctxt: an XPath parser context
2794 * Set the callee evaluation frame
2796 * Returns the previous frame value to be restored once done
2799 xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
2804 ret = ctxt->valueFrame;
2805 ctxt->valueFrame = ctxt->valueNr;
2811 * @ctxt: an XPath parser context
2812 * @frame: the previous frame value
2814 * Remove the callee evaluation frame
2817 xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
2820 if (ctxt->valueNr < ctxt->valueFrame) {
2821 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2823 ctxt->valueFrame = frame;
2828 * @ctxt: an XPath evaluation context
2830 * Pops the top XPath object from the value stack
2832 * Returns the XPath object just removed
2835 valuePop(xmlXPathParserContextPtr ctxt)
2837 xmlXPathObjectPtr ret;
2839 if ((ctxt == NULL) || (ctxt->valueNr <= 0))
2842 if (ctxt->valueNr <= ctxt->valueFrame) {
2843 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
2848 if (ctxt->valueNr > 0)
2849 ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
2852 ret = ctxt->valueTab[ctxt->valueNr];
2853 ctxt->valueTab[ctxt->valueNr] = NULL;
2858 * @ctxt: an XPath evaluation context
2859 * @value: the XPath object
2861 * Pushes a new XPath object on top of the value stack
2863 * returns the number of items on the value stack
2866 valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
2868 if ((ctxt == NULL) || (value == NULL)) return(-1);
2869 if (ctxt->valueNr >= ctxt->valueMax) {
2870 xmlXPathObjectPtr *tmp;
2872 if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
2873 xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
2874 ctxt->error = XPATH_MEMORY_ERROR;
2877 tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2878 2 * ctxt->valueMax *
2879 sizeof(ctxt->valueTab[0]));
2881 xmlXPathErrMemory(NULL, "pushing value\n");
2882 ctxt->error = XPATH_MEMORY_ERROR;
2885 ctxt->valueMax *= 2;
2886 ctxt->valueTab = tmp;
2888 ctxt->valueTab[ctxt->valueNr] = value;
2889 ctxt->value = value;
2890 return (ctxt->valueNr++);
2894 * xmlXPathPopBoolean:
2895 * @ctxt: an XPath parser context
2897 * Pops a boolean from the stack, handling conversion if needed.
2898 * Check error with #xmlXPathCheckError.
2900 * Returns the boolean
2903 xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
2904 xmlXPathObjectPtr obj;
2907 obj = valuePop(ctxt);
2909 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2912 if (obj->type != XPATH_BOOLEAN)
2913 ret = xmlXPathCastToBoolean(obj);
2916 xmlXPathReleaseObject(ctxt->context, obj);
2921 * xmlXPathPopNumber:
2922 * @ctxt: an XPath parser context
2924 * Pops a number from the stack, handling conversion if needed.
2925 * Check error with #xmlXPathCheckError.
2927 * Returns the number
2930 xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
2931 xmlXPathObjectPtr obj;
2934 obj = valuePop(ctxt);
2936 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2939 if (obj->type != XPATH_NUMBER)
2940 ret = xmlXPathCastToNumber(obj);
2942 ret = obj->floatval;
2943 xmlXPathReleaseObject(ctxt->context, obj);
2948 * xmlXPathPopString:
2949 * @ctxt: an XPath parser context
2951 * Pops a string from the stack, handling conversion if needed.
2952 * Check error with #xmlXPathCheckError.
2954 * Returns the string
2957 xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
2958 xmlXPathObjectPtr obj;
2961 obj = valuePop(ctxt);
2963 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2966 ret = xmlXPathCastToString(obj); /* this does required strdup */
2967 /* TODO: needs refactoring somewhere else */
2968 if (obj->stringval == ret)
2969 obj->stringval = NULL;
2970 xmlXPathReleaseObject(ctxt->context, obj);
2975 * xmlXPathPopNodeSet:
2976 * @ctxt: an XPath parser context
2978 * Pops a node-set from the stack, handling conversion if needed.
2979 * Check error with #xmlXPathCheckError.
2981 * Returns the node-set
2984 xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
2985 xmlXPathObjectPtr obj;
2988 if (ctxt == NULL) return(NULL);
2989 if (ctxt->value == NULL) {
2990 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
2993 if (!xmlXPathStackIsNodeSet(ctxt)) {
2994 xmlXPathSetTypeError(ctxt);
2997 obj = valuePop(ctxt);
2998 ret = obj->nodesetval;
3000 /* to fix memory leak of not clearing obj->user */
3001 if (obj->boolval && obj->user != NULL)
3002 xmlFreeNodeList((xmlNodePtr) obj->user);
3004 obj->nodesetval = NULL;
3005 xmlXPathReleaseObject(ctxt->context, obj);
3010 * xmlXPathPopExternal:
3011 * @ctxt: an XPath parser context
3013 * Pops an external object from the stack, handling conversion if needed.
3014 * Check error with #xmlXPathCheckError.
3016 * Returns the object
3019 xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
3020 xmlXPathObjectPtr obj;
3023 if ((ctxt == NULL) || (ctxt->value == NULL)) {
3024 xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
3027 if (ctxt->value->type != XPATH_USERS) {
3028 xmlXPathSetTypeError(ctxt);
3031 obj = valuePop(ctxt);
3034 xmlXPathReleaseObject(ctxt->context, obj);
3039 * Macros for accessing the content. Those should be used only by the parser,
3042 * Dirty macros, i.e. one need to make assumption on the context to use them
3044 * CUR_PTR return the current pointer to the xmlChar to be parsed.
3045 * CUR returns the current xmlChar value, i.e. a 8 bit value
3046 * in ISO-Latin or UTF-8.
3047 * This should be used internally by the parser
3048 * only to compare to ASCII values otherwise it would break when
3049 * running with UTF-8 encoding.
3050 * NXT(n) returns the n'th next xmlChar. Same as CUR is should be used only
3051 * to compare on ASCII based substring.
3052 * SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
3053 * strings within the parser.
3054 * CURRENT Returns the current char value, with the full decoding of
3055 * UTF-8 if we are using this mode. It returns an int.
3056 * NEXT Skip to the next character, this does the proper decoding
3057 * in UTF-8 mode. It also pop-up unfinished entities on the fly.
3058 * It returns the pointer to the current xmlChar.
3061 #define CUR (*ctxt->cur)
3062 #define SKIP(val) ctxt->cur += (val)
3063 #define NXT(val) ctxt->cur[(val)]
3064 #define CUR_PTR ctxt->cur
3065 #define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
3067 #define COPY_BUF(l,b,i,v) \
3068 if (l == 1) b[i++] = (xmlChar) v; \
3069 else i += xmlCopyChar(l,&b[i],v)
3071 #define NEXTL(l) ctxt->cur += l
3073 #define SKIP_BLANKS \
3074 while (IS_BLANK_CH(*(ctxt->cur))) NEXT
3076 #define CURRENT (*ctxt->cur)
3077 #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
3084 #define DBL_EPSILON 1E-9
3087 #define UPPER_DOUBLE 1E9
3088 #define LOWER_DOUBLE 1E-5
3089 #define LOWER_DOUBLE_EXP 5
3091 #define INTEGER_DIGITS DBL_DIG
3092 #define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
3093 #define EXPONENT_DIGITS (3 + 2)
3096 * xmlXPathFormatNumber:
3097 * @number: number to format
3098 * @buffer: output buffer
3099 * @buffersize: size of output buffer
3101 * Convert the number into a string representation.
3104 xmlXPathFormatNumber(double number, char buffer[], int buffersize)
3106 switch (xmlXPathIsInf(number)) {
3108 if (buffersize > (int)sizeof("Infinity"))
3109 snprintf(buffer, buffersize, "Infinity");
3112 if (buffersize > (int)sizeof("-Infinity"))
3113 snprintf(buffer, buffersize, "-Infinity");
3116 if (xmlXPathIsNaN(number)) {
3117 if (buffersize > (int)sizeof("NaN"))
3118 snprintf(buffer, buffersize, "NaN");
3119 } else if (number == 0 && xmlXPathGetSign(number) != 0) {
3120 snprintf(buffer, buffersize, "0");
3121 } else if ((number > INT_MIN) && (number < INT_MAX) &&
3122 (number == (int) number)) {
3125 int value = (int) number;
3131 snprintf(work, 29, "%d", value);
3133 while ((*cur) && (ptr - buffer < buffersize)) {
3137 if (ptr - buffer < buffersize) {
3139 } else if (buffersize > 0) {
3145 For the dimension of work,
3146 DBL_DIG is number of significant digits
3147 EXPONENT is only needed for "scientific notation"
3148 3 is sign, decimal point, and terminating zero
3149 LOWER_DOUBLE_EXP is max number of leading zeroes in fraction
3150 Note that this dimension is slightly (a few characters)
3151 larger than actually necessary.
3153 char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
3154 int integer_place, fraction_place;
3156 char *after_fraction;
3157 double absolute_value;
3160 absolute_value = fabs(number);
3163 * First choose format - scientific or regular floating point.
3164 * In either case, result is in work, and after_fraction points
3165 * just past the fractional part.
3167 if ( ((absolute_value > UPPER_DOUBLE) ||
3168 (absolute_value < LOWER_DOUBLE)) &&
3169 (absolute_value != 0.0) ) {
3170 /* Use scientific notation */
3171 integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
3172 fraction_place = DBL_DIG - 1;
3173 size = snprintf(work, sizeof(work),"%*.*e",
3174 integer_place, fraction_place, number);
3175 while ((size > 0) && (work[size] != 'e')) size--;
3179 /* Use regular notation */
3180 if (absolute_value > 0.0) {
3181 integer_place = (int)log10(absolute_value);
3182 if (integer_place > 0)
3183 fraction_place = DBL_DIG - integer_place - 1;
3185 fraction_place = DBL_DIG - integer_place;
3189 size = snprintf(work, sizeof(work), "%0.*f",
3190 fraction_place, number);
3193 /* Remove leading spaces sometimes inserted by snprintf */
3194 while (work[0] == ' ') {
3195 for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
3199 /* Remove fractional trailing zeroes */
3200 after_fraction = work + size;
3201 ptr = after_fraction;
3202 while (*(--ptr) == '0')
3206 while ((*ptr++ = *after_fraction++) != 0);
3208 /* Finally copy result back to caller */
3209 size = strlen(work) + 1;
3210 if (size > buffersize) {
3211 work[buffersize - 1] = 0;
3214 memmove(buffer, work, size);
3221 /************************************************************************
3223 * Routines to handle NodeSets *
3225 ************************************************************************/
3228 * xmlXPathOrderDocElems:
3229 * @doc: an input document
3231 * Call this routine to speed up XPath computation on static documents.
3232 * This stamps all the element nodes with the document order
3233 * Like for line information, the order is kept in the element->content
3234 * field, the value stored is actually - the node number (starting at -1)
3235 * to be able to differentiate from line numbers.
3237 * Returns the number of elements found in the document or -1 in case
3241 xmlXPathOrderDocElems(xmlDocPtr doc) {
3247 cur = doc->children;
3248 while (cur != NULL) {
3249 if (cur->type == XML_ELEMENT_NODE) {
3250 cur->content = (void *) (-(++count));
3251 if (cur->children != NULL) {
3252 cur = cur->children;
3256 if (cur->next != NULL) {
3264 if (cur == (xmlNodePtr) doc) {
3268 if (cur->next != NULL) {
3272 } while (cur != NULL);
3279 * @node1: the first node
3280 * @node2: the second node
3282 * Compare two nodes w.r.t document order
3284 * Returns -2 in case of error 1 if first point < second point, 0 if
3285 * it's the same node, -1 otherwise
3288 xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
3290 int attr1 = 0, attr2 = 0;
3291 xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
3292 xmlNodePtr cur, root;
3294 if ((node1 == NULL) || (node2 == NULL))
3297 * a couple of optimizations which will avoid computations in most cases
3299 if (node1 == node2) /* trivial case */
3301 if (node1->type == XML_ATTRIBUTE_NODE) {
3304 node1 = node1->parent;
3306 if (node2->type == XML_ATTRIBUTE_NODE) {
3309 node2 = node2->parent;
3311 if (node1 == node2) {
3312 if (attr1 == attr2) {
3313 /* not required, but we keep attributes in order */
3315 cur = attrNode2->prev;
3316 while (cur != NULL) {
3317 if (cur == attrNode1)
3329 if ((node1->type == XML_NAMESPACE_DECL) ||
3330 (node2->type == XML_NAMESPACE_DECL))
3332 if (node1 == node2->prev)
3334 if (node1 == node2->next)
3338 * Speedup using document order if availble.
3340 if ((node1->type == XML_ELEMENT_NODE) &&
3341 (node2->type == XML_ELEMENT_NODE) &&
3342 (0 > (long) node1->content) &&
3343 (0 > (long) node2->content) &&
3344 (node1->doc == node2->doc)) {
3347 l1 = -((long) node1->content);
3348 l2 = -((long) node2->content);
3356 * compute depth to root
3358 for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
3359 if (cur->parent == node1)
3364 for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
3365 if (cur->parent == node2)
3370 * Distinct document (or distinct entities :-( ) case.
3376 * get the nearest common ancestor.
3378 while (depth1 > depth2) {
3380 node1 = node1->parent;
3382 while (depth2 > depth1) {
3384 node2 = node2->parent;
3386 while (node1->parent != node2->parent) {
3387 node1 = node1->parent;
3388 node2 = node2->parent;
3389 /* should not happen but just in case ... */
3390 if ((node1 == NULL) || (node2 == NULL))
3396 if (node1 == node2->prev)
3398 if (node1 == node2->next)
3401 * Speedup using document order if availble.
3403 if ((node1->type == XML_ELEMENT_NODE) &&
3404 (node2->type == XML_ELEMENT_NODE) &&
3405 (0 > (long) node1->content) &&
3406 (0 > (long) node2->content) &&
3407 (node1->doc == node2->doc)) {
3410 l1 = -((long) node1->content);
3411 l2 = -((long) node2->content);
3418 for (cur = node1->next;cur != NULL;cur = cur->next)
3421 return(-1); /* assume there is no sibling list corruption */
3425 * xmlXPathNodeSetSort:
3426 * @set: the node set
3428 * Sort the node set in document order
3431 xmlXPathNodeSetSort(xmlNodeSetPtr set) {
3432 #ifndef WITH_TIM_SORT
3433 int i, j, incr, len;
3440 #ifndef WITH_TIM_SORT
3442 * Use the old Shell's sort implementation to sort the node-set
3443 * Timsort ought to be quite faster
3446 for (incr = len / 2; incr > 0; incr /= 2) {
3447 for (i = incr; i < len; i++) {
3450 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
3451 if (xmlXPathCmpNodesExt(set->nodeTab[j],
3452 set->nodeTab[j + incr]) == -1)
3454 if (xmlXPathCmpNodes(set->nodeTab[j],
3455 set->nodeTab[j + incr]) == -1)
3458 tmp = set->nodeTab[j];
3459 set->nodeTab[j] = set->nodeTab[j + incr];
3460 set->nodeTab[j + incr] = tmp;
3467 #else /* WITH_TIM_SORT */
3468 libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
3469 #endif /* WITH_TIM_SORT */
3472 #define XML_NODESET_DEFAULT 10
3474 * xmlXPathNodeSetDupNs:
3475 * @node: the parent node of the namespace XPath node
3476 * @ns: the libxml namespace declaration node.
3478 * Namespace node in libxml don't match the XPath semantic. In a node set
3479 * the namespace nodes are duplicated and the next pointer is set to the
3480 * parent node in the XPath semantic.
3482 * Returns the newly created object.
3485 xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
3488 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3490 if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
3491 return((xmlNodePtr) ns);
3494 * Allocate a new Namespace and fill the fields.
3496 cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
3498 xmlXPathErrMemory(NULL, "duplicating namespace\n");
3501 memset(cur, 0, sizeof(xmlNs));
3502 cur->type = XML_NAMESPACE_DECL;
3503 if (ns->href != NULL)
3504 cur->href = xmlStrdup(ns->href);
3505 if (ns->prefix != NULL)
3506 cur->prefix = xmlStrdup(ns->prefix);
3507 cur->next = (xmlNsPtr) node;
3508 return((xmlNodePtr) cur);
3512 * xmlXPathNodeSetFreeNs:
3513 * @ns: the XPath namespace node found in a nodeset.
3515 * Namespace nodes in libxml don't match the XPath semantic. In a node set
3516 * the namespace nodes are duplicated and the next pointer is set to the
3517 * parent node in the XPath semantic. Check if such a node needs to be freed
3520 xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
3521 if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
3524 if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
3525 if (ns->href != NULL)
3526 xmlFree((xmlChar *)ns->href);
3527 if (ns->prefix != NULL)
3528 xmlFree((xmlChar *)ns->prefix);
3534 * xmlXPathNodeSetCreate:
3535 * @val: an initial xmlNodePtr, or NULL
3537 * Create a new xmlNodeSetPtr of type double and of value @val
3539 * Returns the newly created object.
3542 xmlXPathNodeSetCreate(xmlNodePtr val) {
3545 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3547 xmlXPathErrMemory(NULL, "creating nodeset\n");
3550 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3552 ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3553 sizeof(xmlNodePtr));
3554 if (ret->nodeTab == NULL) {
3555 xmlXPathErrMemory(NULL, "creating nodeset\n");
3559 memset(ret->nodeTab, 0 ,
3560 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3561 ret->nodeMax = XML_NODESET_DEFAULT;
3562 if (val->type == XML_NAMESPACE_DECL) {
3563 xmlNsPtr ns = (xmlNsPtr) val;
3565 ret->nodeTab[ret->nodeNr++] =
3566 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3568 ret->nodeTab[ret->nodeNr++] = val;
3574 * xmlXPathNodeSetCreateSize:
3575 * @size: the initial size of the set
3577 * Create a new xmlNodeSetPtr of type double and of value @val
3579 * Returns the newly created object.
3581 static xmlNodeSetPtr
3582 xmlXPathNodeSetCreateSize(int size) {
3585 ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
3587 xmlXPathErrMemory(NULL, "creating nodeset\n");
3590 memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
3591 if (size < XML_NODESET_DEFAULT)
3592 size = XML_NODESET_DEFAULT;
3593 ret->nodeTab = (xmlNodePtr *) xmlMalloc(size * sizeof(xmlNodePtr));
3594 if (ret->nodeTab == NULL) {
3595 xmlXPathErrMemory(NULL, "creating nodeset\n");
3599 memset(ret->nodeTab, 0 , size * (size_t) sizeof(xmlNodePtr));
3600 ret->nodeMax = size;
3605 * xmlXPathNodeSetContains:
3606 * @cur: the node-set
3609 * checks whether @cur contains @val
3611 * Returns true (1) if @cur contains @val, false (0) otherwise
3614 xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
3617 if ((cur == NULL) || (val == NULL)) return(0);
3618 if (val->type == XML_NAMESPACE_DECL) {
3619 for (i = 0; i < cur->nodeNr; i++) {
3620 if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
3623 ns1 = (xmlNsPtr) val;
3624 ns2 = (xmlNsPtr) cur->nodeTab[i];
3627 if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
3628 (xmlStrEqual(ns1->prefix, ns2->prefix)))
3633 for (i = 0; i < cur->nodeNr; i++) {
3634 if (cur->nodeTab[i] == val)
3642 * xmlXPathNodeSetAddNs:
3643 * @cur: the initial node set
3644 * @node: the hosting node
3645 * @ns: a the namespace node
3647 * add a new namespace node to an existing NodeSet
3649 * Returns 0 in case of success and -1 in case of error
3652 xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
3656 if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
3657 (ns->type != XML_NAMESPACE_DECL) ||
3658 (node->type != XML_ELEMENT_NODE))
3661 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3663 * prevent duplicates
3665 for (i = 0;i < cur->nodeNr;i++) {
3666 if ((cur->nodeTab[i] != NULL) &&
3667 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
3668 (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
3669 (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
3674 * grow the nodeTab if needed
3676 if (cur->nodeMax == 0) {
3677 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3678 sizeof(xmlNodePtr));
3679 if (cur->nodeTab == NULL) {
3680 xmlXPathErrMemory(NULL, "growing nodeset\n");
3683 memset(cur->nodeTab, 0 ,
3684 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3685 cur->nodeMax = XML_NODESET_DEFAULT;
3686 } else if (cur->nodeNr == cur->nodeMax) {
3689 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3690 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3693 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3694 sizeof(xmlNodePtr));
3696 xmlXPathErrMemory(NULL, "growing nodeset\n");
3700 cur->nodeTab = temp;
3702 cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
3707 * xmlXPathNodeSetAdd:
3708 * @cur: the initial node set
3709 * @val: a new xmlNodePtr
3711 * add a new xmlNodePtr to an existing NodeSet
3713 * Returns 0 in case of success, and -1 in case of error
3716 xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
3719 if ((cur == NULL) || (val == NULL)) return(-1);
3721 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3723 * prevent duplicates
3725 for (i = 0;i < cur->nodeNr;i++)
3726 if (cur->nodeTab[i] == val) return(0);
3729 * grow the nodeTab if needed
3731 if (cur->nodeMax == 0) {
3732 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3733 sizeof(xmlNodePtr));
3734 if (cur->nodeTab == NULL) {
3735 xmlXPathErrMemory(NULL, "growing nodeset\n");
3738 memset(cur->nodeTab, 0 ,
3739 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3740 cur->nodeMax = XML_NODESET_DEFAULT;
3741 } else if (cur->nodeNr == cur->nodeMax) {
3744 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3745 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3748 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3749 sizeof(xmlNodePtr));
3751 xmlXPathErrMemory(NULL, "growing nodeset\n");
3755 cur->nodeTab = temp;
3757 if (val->type == XML_NAMESPACE_DECL) {
3758 xmlNsPtr ns = (xmlNsPtr) val;
3760 cur->nodeTab[cur->nodeNr++] =
3761 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3763 cur->nodeTab[cur->nodeNr++] = val;
3768 * xmlXPathNodeSetAddUnique:
3769 * @cur: the initial node set
3770 * @val: a new xmlNodePtr
3772 * add a new xmlNodePtr to an existing NodeSet, optimized version
3773 * when we are sure the node is not already in the set.
3775 * Returns 0 in case of success and -1 in case of failure
3778 xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
3779 if ((cur == NULL) || (val == NULL)) return(-1);
3781 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3783 * grow the nodeTab if needed
3785 if (cur->nodeMax == 0) {
3786 cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3787 sizeof(xmlNodePtr));
3788 if (cur->nodeTab == NULL) {
3789 xmlXPathErrMemory(NULL, "growing nodeset\n");
3792 memset(cur->nodeTab, 0 ,
3793 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3794 cur->nodeMax = XML_NODESET_DEFAULT;
3795 } else if (cur->nodeNr == cur->nodeMax) {
3798 if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3799 xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
3802 temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
3803 sizeof(xmlNodePtr));
3805 xmlXPathErrMemory(NULL, "growing nodeset\n");
3808 cur->nodeTab = temp;
3811 if (val->type == XML_NAMESPACE_DECL) {
3812 xmlNsPtr ns = (xmlNsPtr) val;
3814 cur->nodeTab[cur->nodeNr++] =
3815 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3817 cur->nodeTab[cur->nodeNr++] = val;
3822 * xmlXPathNodeSetMerge:
3823 * @val1: the first NodeSet or NULL
3824 * @val2: the second NodeSet
3826 * Merges two nodesets, all nodes from @val2 are added to @val1
3827 * if @val1 is NULL, a new set is created and copied from @val2
3829 * Returns @val1 once extended or NULL in case of error.
3832 xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
3833 int i, j, initNr, skip;
3836 if (val2 == NULL) return(val1);
3838 val1 = xmlXPathNodeSetCreate(NULL);
3843 * TODO: The optimization won't work in every case, since
3844 * those nasty namespace nodes need to be added with
3845 * xmlXPathNodeSetDupNs() to the set; thus a pure
3846 * memcpy is not possible.
3847 * If there was a flag on the nodesetval, indicating that
3848 * some temporary nodes are in, that would be helpfull.
3851 * Optimization: Create an equally sized node-set
3852 * and memcpy the content.
3854 val1 = xmlXPathNodeSetCreateSize(val2->nodeNr);
3857 if (val2->nodeNr != 0) {
3858 if (val2->nodeNr == 1)
3859 *(val1->nodeTab) = *(val2->nodeTab);
3861 memcpy(val1->nodeTab, val2->nodeTab,
3862 val2->nodeNr * sizeof(xmlNodePtr));
3864 val1->nodeNr = val2->nodeNr;
3870 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
3871 initNr = val1->nodeNr;
3873 for (i = 0;i < val2->nodeNr;i++) {
3874 n2 = val2->nodeTab[i];
3876 * check against duplicates
3879 for (j = 0; j < initNr; j++) {
3880 n1 = val1->nodeTab[j];
3884 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3885 (n2->type == XML_NAMESPACE_DECL)) {
3886 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3887 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3888 ((xmlNsPtr) n2)->prefix)))
3899 * grow the nodeTab if needed
3901 if (val1->nodeMax == 0) {
3902 val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
3903 sizeof(xmlNodePtr));
3904 if (val1->nodeTab == NULL) {
3905 xmlXPathErrMemory(NULL, "merging nodeset\n");
3908 memset(val1->nodeTab, 0 ,
3909 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
3910 val1->nodeMax = XML_NODESET_DEFAULT;
3911 } else if (val1->nodeNr == val1->nodeMax) {
3914 if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
3915 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
3918 temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
3919 sizeof(xmlNodePtr));
3921 xmlXPathErrMemory(NULL, "merging nodeset\n");
3924 val1->nodeTab = temp;
3927 if (n2->type == XML_NAMESPACE_DECL) {
3928 xmlNsPtr ns = (xmlNsPtr) n2;
3930 val1->nodeTab[val1->nodeNr++] =
3931 xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
3933 val1->nodeTab[val1->nodeNr++] = n2;
3941 * xmlXPathNodeSetMergeAndClear:
3942 * @set1: the first NodeSet or NULL
3943 * @set2: the second NodeSet
3944 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
3946 * Merges two nodesets, all nodes from @set2 are added to @set1
3947 * if @set1 is NULL, a new set is created and copied from @set2.
3948 * Checks for duplicate nodes. Clears set2.
3950 * Returns @set1 once extended or NULL in case of error.
3952 static xmlNodeSetPtr
3953 xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
3956 if ((set1 == NULL) && (hasNullEntries == 0)) {
3958 * Note that doing a memcpy of the list, namespace nodes are
3959 * just assigned to set1, since set2 is cleared anyway.
3961 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
3964 if (set2->nodeNr != 0) {
3965 memcpy(set1->nodeTab, set2->nodeTab,
3966 set2->nodeNr * sizeof(xmlNodePtr));
3967 set1->nodeNr = set2->nodeNr;
3970 int i, j, initNbSet1;
3974 set1 = xmlXPathNodeSetCreate(NULL);
3978 initNbSet1 = set1->nodeNr;
3979 for (i = 0;i < set2->nodeNr;i++) {
3980 n2 = set2->nodeTab[i];
3982 * Skip NULLed entries.
3989 for (j = 0; j < initNbSet1; j++) {
3990 n1 = set1->nodeTab[j];
3993 } else if ((n1->type == XML_NAMESPACE_DECL) &&
3994 (n2->type == XML_NAMESPACE_DECL))
3996 if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
3997 (xmlStrEqual(((xmlNsPtr) n1)->prefix,
3998 ((xmlNsPtr) n2)->prefix)))
4001 * Free the namespace node.
4003 set2->nodeTab[i] = NULL;
4004 xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
4010 * grow the nodeTab if needed
4012 if (set1->nodeMax == 0) {
4013 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4014 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4015 if (set1->nodeTab == NULL) {
4016 xmlXPathErrMemory(NULL, "merging nodeset\n");
4019 memset(set1->nodeTab, 0,
4020 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4021 set1->nodeMax = XML_NODESET_DEFAULT;
4022 } else if (set1->nodeNr >= set1->nodeMax) {
4025 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4026 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4029 temp = (xmlNodePtr *) xmlRealloc(
4030 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4032 xmlXPathErrMemory(NULL, "merging nodeset\n");
4035 set1->nodeTab = temp;
4038 set1->nodeTab[set1->nodeNr++] = n2;
4048 * xmlXPathNodeSetMergeAndClearNoDupls:
4049 * @set1: the first NodeSet or NULL
4050 * @set2: the second NodeSet
4051 * @hasSet2NsNodes: 1 if set2 contains namespaces nodes
4053 * Merges two nodesets, all nodes from @set2 are added to @set1
4054 * if @set1 is NULL, a new set is created and copied from @set2.
4055 * Doesn't chack for duplicate nodes. Clears set2.
4057 * Returns @set1 once extended or NULL in case of error.
4059 static xmlNodeSetPtr
4060 xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
4065 if ((set1 == NULL) && (hasNullEntries == 0)) {
4067 * Note that doing a memcpy of the list, namespace nodes are
4068 * just assigned to set1, since set2 is cleared anyway.
4070 set1 = xmlXPathNodeSetCreateSize(set2->nodeNr);
4073 if (set2->nodeNr != 0) {
4074 memcpy(set1->nodeTab, set2->nodeTab,
4075 set2->nodeNr * sizeof(xmlNodePtr));
4076 set1->nodeNr = set2->nodeNr;
4083 set1 = xmlXPathNodeSetCreate(NULL);
4087 for (i = 0;i < set2->nodeNr;i++) {
4088 n2 = set2->nodeTab[i];
4090 * Skip NULLed entries.
4094 if (set1->nodeMax == 0) {
4095 set1->nodeTab = (xmlNodePtr *) xmlMalloc(
4096 XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
4097 if (set1->nodeTab == NULL) {
4098 xmlXPathErrMemory(NULL, "merging nodeset\n");
4101 memset(set1->nodeTab, 0,
4102 XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
4103 set1->nodeMax = XML_NODESET_DEFAULT;
4104 } else if (set1->nodeNr >= set1->nodeMax) {
4107 if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
4108 xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
4111 temp = (xmlNodePtr *) xmlRealloc(
4112 set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
4114 xmlXPathErrMemory(NULL, "merging nodeset\n");
4117 set1->nodeTab = temp;
4120 set1->nodeTab[set1->nodeNr++] = n2;
4128 * xmlXPathNodeSetDel:
4129 * @cur: the initial node set
4130 * @val: an xmlNodePtr
4132 * Removes an xmlNodePtr from an existing NodeSet
4135 xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
4138 if (cur == NULL) return;
4139 if (val == NULL) return;
4142 * find node in nodeTab
4144 for (i = 0;i < cur->nodeNr;i++)
4145 if (cur->nodeTab[i] == val) break;
4147 if (i >= cur->nodeNr) { /* not found */
4149 xmlGenericError(xmlGenericErrorContext,
4150 "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
4155 if ((cur->nodeTab[i] != NULL) &&
4156 (cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
4157 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
4159 for (;i < cur->nodeNr;i++)
4160 cur->nodeTab[i] = cur->nodeTab[i + 1];
4161 cur->nodeTab[cur->nodeNr] = NULL;
4165 * xmlXPathNodeSetRemove:
4166 * @cur: the initial node set
4167 * @val: the index to remove
4169 * Removes an entry from an existing NodeSet list.
4172 xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
4173 if (cur == NULL) return;
4174 if (val >= cur->nodeNr) return;
4175 if ((cur->nodeTab[val] != NULL) &&
4176 (cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
4177 xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
4179 for (;val < cur->nodeNr;val++)
4180 cur->nodeTab[val] = cur->nodeTab[val + 1];
4181 cur->nodeTab[cur->nodeNr] = NULL;
4185 * xmlXPathFreeNodeSet:
4186 * @obj: the xmlNodeSetPtr to free
4188 * Free the NodeSet compound (not the actual nodes !).
4191 xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
4192 if (obj == NULL) return;
4193 if (obj->nodeTab != NULL) {
4196 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4197 for (i = 0;i < obj->nodeNr;i++)
4198 if ((obj->nodeTab[i] != NULL) &&
4199 (obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
4200 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4201 xmlFree(obj->nodeTab);
4207 * xmlXPathNodeSetClearFromPos:
4208 * @set: the node set to be cleared
4209 * @pos: the start position to clear from
4211 * Clears the list from temporary XPath objects (e.g. namespace nodes
4212 * are feed) starting with the entry at @pos, but does *not* free the list
4213 * itself. Sets the length of the list to @pos.
4216 xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
4218 if ((set == NULL) || (pos >= set->nodeNr))
4220 else if ((hasNsNodes)) {
4224 for (i = pos; i < set->nodeNr; i++) {
4225 node = set->nodeTab[i];
4226 if ((node != NULL) &&
4227 (node->type == XML_NAMESPACE_DECL))
4228 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4235 * xmlXPathNodeSetClear:
4236 * @set: the node set to clear
4238 * Clears the list from all temporary XPath objects (e.g. namespace nodes
4239 * are feed), but does *not* free the list itself. Sets the length of the
4243 xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
4245 xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
4249 * xmlXPathNodeSetKeepLast:
4250 * @set: the node set to be cleared
4252 * Move the last node to the first position and clear temporary XPath objects
4253 * (e.g. namespace nodes) from all other nodes. Sets the length of the list
4257 xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
4262 if ((set == NULL) || (set->nodeNr <= 1))
4264 for (i = 0; i < set->nodeNr - 1; i++) {
4265 node = set->nodeTab[i];
4266 if ((node != NULL) &&
4267 (node->type == XML_NAMESPACE_DECL))
4268 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
4270 set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
4275 * xmlXPathFreeValueTree:
4276 * @obj: the xmlNodeSetPtr to free
4278 * Free the NodeSet compound and the actual tree, this is different
4279 * from xmlXPathFreeNodeSet()
4282 xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
4285 if (obj == NULL) return;
4287 if (obj->nodeTab != NULL) {
4288 for (i = 0;i < obj->nodeNr;i++) {
4289 if (obj->nodeTab[i] != NULL) {
4290 if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
4291 xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
4293 xmlFreeNodeList(obj->nodeTab[i]);
4297 xmlFree(obj->nodeTab);
4302 #if defined(DEBUG) || defined(DEBUG_STEP)
4304 * xmlGenericErrorContextNodeSet:
4305 * @output: a FILE * for the output
4306 * @obj: the xmlNodeSetPtr to display
4308 * Quick display of a NodeSet
4311 xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
4314 if (output == NULL) output = xmlGenericErrorContext;
4316 fprintf(output, "NodeSet == NULL !\n");
4319 if (obj->nodeNr == 0) {
4320 fprintf(output, "NodeSet is empty\n");
4323 if (obj->nodeTab == NULL) {
4324 fprintf(output, " nodeTab == NULL !\n");
4327 for (i = 0; i < obj->nodeNr; i++) {
4328 if (obj->nodeTab[i] == NULL) {
4329 fprintf(output, " NULL !\n");
4332 if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
4333 (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
4334 fprintf(output, " /");
4335 else if (obj->nodeTab[i]->name == NULL)
4336 fprintf(output, " noname!");
4337 else fprintf(output, " %s", obj->nodeTab[i]->name);
4339 fprintf(output, "\n");
4344 * xmlXPathNewNodeSet:
4345 * @val: the NodePtr value
4347 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4348 * it with the single Node @val
4350 * Returns the newly created object.
4353 xmlXPathNewNodeSet(xmlNodePtr val) {
4354 xmlXPathObjectPtr ret;
4356 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4358 xmlXPathErrMemory(NULL, "creating nodeset\n");
4361 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4362 ret->type = XPATH_NODESET;
4364 ret->nodesetval = xmlXPathNodeSetCreate(val);
4365 /* @@ with_ns to check whether namespace nodes should be looked at @@ */
4366 #ifdef XP_DEBUG_OBJ_USAGE
4367 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4373 * xmlXPathNewValueTree:
4374 * @val: the NodePtr value
4376 * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
4377 * it with the tree root @val
4379 * Returns the newly created object.
4382 xmlXPathNewValueTree(xmlNodePtr val) {
4383 xmlXPathObjectPtr ret;
4385 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4387 xmlXPathErrMemory(NULL, "creating result value tree\n");
4390 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4391 ret->type = XPATH_XSLT_TREE;
4393 ret->user = (void *) val;
4394 ret->nodesetval = xmlXPathNodeSetCreate(val);
4395 #ifdef XP_DEBUG_OBJ_USAGE
4396 xmlXPathDebugObjUsageRequested(NULL, XPATH_XSLT_TREE);
4402 * xmlXPathNewNodeSetList:
4403 * @val: an existing NodeSet
4405 * Create a new xmlXPathObjectPtr of type NodeSet and initialize
4406 * it with the Nodeset @val
4408 * Returns the newly created object.
4411 xmlXPathNewNodeSetList(xmlNodeSetPtr val)
4413 xmlXPathObjectPtr ret;
4418 else if (val->nodeTab == NULL)
4419 ret = xmlXPathNewNodeSet(NULL);
4421 ret = xmlXPathNewNodeSet(val->nodeTab[0]);
4423 for (i = 1; i < val->nodeNr; ++i) {
4424 if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
4434 * xmlXPathWrapNodeSet:
4435 * @val: the NodePtr value
4437 * Wrap the Nodeset @val in a new xmlXPathObjectPtr
4439 * Returns the newly created object.
4442 xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
4443 xmlXPathObjectPtr ret;
4445 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
4447 xmlXPathErrMemory(NULL, "creating node set object\n");
4450 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
4451 ret->type = XPATH_NODESET;
4452 ret->nodesetval = val;
4453 #ifdef XP_DEBUG_OBJ_USAGE
4454 xmlXPathDebugObjUsageRequested(NULL, XPATH_NODESET);
4460 * xmlXPathFreeNodeSetList:
4461 * @obj: an existing NodeSetList object
4463 * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
4464 * the list contrary to xmlXPathFreeObject().
4467 xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
4468 if (obj == NULL) return;
4469 #ifdef XP_DEBUG_OBJ_USAGE
4470 xmlXPathDebugObjUsageReleased(NULL, obj->type);
4476 * xmlXPathDifference:
4477 * @nodes1: a node-set
4478 * @nodes2: a node-set
4480 * Implements the EXSLT - Sets difference() function:
4481 * node-set set:difference (node-set, node-set)
4483 * Returns the difference between the two node sets, or nodes1 if
4487 xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4492 if (xmlXPathNodeSetIsEmpty(nodes2))
4495 ret = xmlXPathNodeSetCreate(NULL);
4496 if (xmlXPathNodeSetIsEmpty(nodes1))
4499 l1 = xmlXPathNodeSetGetLength(nodes1);
4501 for (i = 0; i < l1; i++) {
4502 cur = xmlXPathNodeSetItem(nodes1, i);
4503 if (!xmlXPathNodeSetContains(nodes2, cur)) {
4504 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4512 * xmlXPathIntersection:
4513 * @nodes1: a node-set
4514 * @nodes2: a node-set
4516 * Implements the EXSLT - Sets intersection() function:
4517 * node-set set:intersection (node-set, node-set)
4519 * Returns a node set comprising the nodes that are within both the
4520 * node sets passed as arguments
4523 xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4524 xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
4530 if (xmlXPathNodeSetIsEmpty(nodes1))
4532 if (xmlXPathNodeSetIsEmpty(nodes2))
4535 l1 = xmlXPathNodeSetGetLength(nodes1);
4537 for (i = 0; i < l1; i++) {
4538 cur = xmlXPathNodeSetItem(nodes1, i);
4539 if (xmlXPathNodeSetContains(nodes2, cur)) {
4540 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4548 * xmlXPathDistinctSorted:
4549 * @nodes: a node-set, sorted by document order
4551 * Implements the EXSLT - Sets distinct() function:
4552 * node-set set:distinct (node-set)
4554 * Returns a subset of the nodes contained in @nodes, or @nodes if
4558 xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
4560 xmlHashTablePtr hash;
4565 if (xmlXPathNodeSetIsEmpty(nodes))
4568 ret = xmlXPathNodeSetCreate(NULL);
4571 l = xmlXPathNodeSetGetLength(nodes);
4572 hash = xmlHashCreate (l);
4573 for (i = 0; i < l; i++) {
4574 cur = xmlXPathNodeSetItem(nodes, i);
4575 strval = xmlXPathCastNodeToString(cur);
4576 if (xmlHashLookup(hash, strval) == NULL) {
4577 xmlHashAddEntry(hash, strval, strval);
4578 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4584 xmlHashFree(hash, (xmlHashDeallocator) xmlFree);
4590 * @nodes: a node-set
4592 * Implements the EXSLT - Sets distinct() function:
4593 * node-set set:distinct (node-set)
4594 * @nodes is sorted by document order, then #exslSetsDistinctSorted
4595 * is called with the sorted node-set
4597 * Returns a subset of the nodes contained in @nodes, or @nodes if
4601 xmlXPathDistinct (xmlNodeSetPtr nodes) {
4602 if (xmlXPathNodeSetIsEmpty(nodes))
4605 xmlXPathNodeSetSort(nodes);
4606 return(xmlXPathDistinctSorted(nodes));
4610 * xmlXPathHasSameNodes:
4611 * @nodes1: a node-set
4612 * @nodes2: a node-set
4614 * Implements the EXSLT - Sets has-same-nodes function:
4615 * boolean set:has-same-node(node-set, node-set)
4617 * Returns true (1) if @nodes1 shares any node with @nodes2, false (0)
4621 xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4625 if (xmlXPathNodeSetIsEmpty(nodes1) ||
4626 xmlXPathNodeSetIsEmpty(nodes2))
4629 l = xmlXPathNodeSetGetLength(nodes1);
4630 for (i = 0; i < l; i++) {
4631 cur = xmlXPathNodeSetItem(nodes1, i);
4632 if (xmlXPathNodeSetContains(nodes2, cur))
4639 * xmlXPathNodeLeadingSorted:
4640 * @nodes: a node-set, sorted by document order
4643 * Implements the EXSLT - Sets leading() function:
4644 * node-set set:leading (node-set, node-set)
4646 * Returns the nodes in @nodes that precede @node in document order,
4647 * @nodes if @node is NULL or an empty node-set if @nodes
4648 * doesn't contain @node
4651 xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4659 ret = xmlXPathNodeSetCreate(NULL);
4662 if (xmlXPathNodeSetIsEmpty(nodes) ||
4663 (!xmlXPathNodeSetContains(nodes, node)))
4666 l = xmlXPathNodeSetGetLength(nodes);
4667 for (i = 0; i < l; i++) {
4668 cur = xmlXPathNodeSetItem(nodes, i);
4671 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4678 * xmlXPathNodeLeading:
4679 * @nodes: a node-set
4682 * Implements the EXSLT - Sets leading() function:
4683 * node-set set:leading (node-set, node-set)
4684 * @nodes is sorted by document order, then #exslSetsNodeLeadingSorted
4687 * Returns the nodes in @nodes that precede @node in document order,
4688 * @nodes if @node is NULL or an empty node-set if @nodes
4689 * doesn't contain @node
4692 xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
4693 xmlXPathNodeSetSort(nodes);
4694 return(xmlXPathNodeLeadingSorted(nodes, node));
4698 * xmlXPathLeadingSorted:
4699 * @nodes1: a node-set, sorted by document order
4700 * @nodes2: a node-set, sorted by document order
4702 * Implements the EXSLT - Sets leading() function:
4703 * node-set set:leading (node-set, node-set)
4705 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4706 * in document order, @nodes1 if @nodes2 is NULL or empty or
4707 * an empty node-set if @nodes1 doesn't contain @nodes2
4710 xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4711 if (xmlXPathNodeSetIsEmpty(nodes2))
4713 return(xmlXPathNodeLeadingSorted(nodes1,
4714 xmlXPathNodeSetItem(nodes2, 1)));
4719 * @nodes1: a node-set
4720 * @nodes2: a node-set
4722 * Implements the EXSLT - Sets leading() function:
4723 * node-set set:leading (node-set, node-set)
4724 * @nodes1 and @nodes2 are sorted by document order, then
4725 * #exslSetsLeadingSorted is called.
4727 * Returns the nodes in @nodes1 that precede the first node in @nodes2
4728 * in document order, @nodes1 if @nodes2 is NULL or empty or
4729 * an empty node-set if @nodes1 doesn't contain @nodes2
4732 xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4733 if (xmlXPathNodeSetIsEmpty(nodes2))
4735 if (xmlXPathNodeSetIsEmpty(nodes1))
4736 return(xmlXPathNodeSetCreate(NULL));
4737 xmlXPathNodeSetSort(nodes1);
4738 xmlXPathNodeSetSort(nodes2);
4739 return(xmlXPathNodeLeadingSorted(nodes1,
4740 xmlXPathNodeSetItem(nodes2, 1)));
4744 * xmlXPathNodeTrailingSorted:
4745 * @nodes: a node-set, sorted by document order
4748 * Implements the EXSLT - Sets trailing() function:
4749 * node-set set:trailing (node-set, node-set)
4751 * Returns the nodes in @nodes that follow @node in document order,
4752 * @nodes if @node is NULL or an empty node-set if @nodes
4753 * doesn't contain @node
4756 xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
4764 ret = xmlXPathNodeSetCreate(NULL);
4767 if (xmlXPathNodeSetIsEmpty(nodes) ||
4768 (!xmlXPathNodeSetContains(nodes, node)))
4771 l = xmlXPathNodeSetGetLength(nodes);
4772 for (i = l - 1; i >= 0; i--) {
4773 cur = xmlXPathNodeSetItem(nodes, i);
4776 if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
4779 xmlXPathNodeSetSort(ret); /* bug 413451 */
4784 * xmlXPathNodeTrailing:
4785 * @nodes: a node-set
4788 * Implements the EXSLT - Sets trailing() function:
4789 * node-set set:trailing (node-set, node-set)
4790 * @nodes is sorted by document order, then #xmlXPathNodeTrailingSorted
4793 * Returns the nodes in @nodes that follow @node in document order,
4794 * @nodes if @node is NULL or an empty node-set if @nodes
4795 * doesn't contain @node
4798 xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
4799 xmlXPathNodeSetSort(nodes);
4800 return(xmlXPathNodeTrailingSorted(nodes, node));
4804 * xmlXPathTrailingSorted:
4805 * @nodes1: a node-set, sorted by document order
4806 * @nodes2: a node-set, sorted by document order
4808 * Implements the EXSLT - Sets trailing() function:
4809 * node-set set:trailing (node-set, node-set)
4811 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4812 * in document order, @nodes1 if @nodes2 is NULL or empty or
4813 * an empty node-set if @nodes1 doesn't contain @nodes2
4816 xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4817 if (xmlXPathNodeSetIsEmpty(nodes2))
4819 return(xmlXPathNodeTrailingSorted(nodes1,
4820 xmlXPathNodeSetItem(nodes2, 0)));
4825 * @nodes1: a node-set
4826 * @nodes2: a node-set
4828 * Implements the EXSLT - Sets trailing() function:
4829 * node-set set:trailing (node-set, node-set)
4830 * @nodes1 and @nodes2 are sorted by document order, then
4831 * #xmlXPathTrailingSorted is called.
4833 * Returns the nodes in @nodes1 that follow the first node in @nodes2
4834 * in document order, @nodes1 if @nodes2 is NULL or empty or
4835 * an empty node-set if @nodes1 doesn't contain @nodes2
4838 xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
4839 if (xmlXPathNodeSetIsEmpty(nodes2))
4841 if (xmlXPathNodeSetIsEmpty(nodes1))
4842 return(xmlXPathNodeSetCreate(NULL));
4843 xmlXPathNodeSetSort(nodes1);
4844 xmlXPathNodeSetSort(nodes2);
4845 return(xmlXPathNodeTrailingSorted(nodes1,
4846 xmlXPathNodeSetItem(nodes2, 0)));
4849 /************************************************************************
4851 * Routines to handle extra functions *
4853 ************************************************************************/
4856 * xmlXPathRegisterFunc:
4857 * @ctxt: the XPath context
4858 * @name: the function name
4859 * @f: the function implementation or NULL
4861 * Register a new function. If @f is NULL it unregisters the function
4863 * Returns 0 in case of success, -1 in case of error
4866 xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
4867 xmlXPathFunction f) {
4868 return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
4872 * xmlXPathRegisterFuncNS:
4873 * @ctxt: the XPath context
4874 * @name: the function name
4875 * @ns_uri: the function namespace URI
4876 * @f: the function implementation or NULL
4878 * Register a new function. If @f is NULL it unregisters the function
4880 * Returns 0 in case of success, -1 in case of error
4883 xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4884 const xmlChar *ns_uri, xmlXPathFunction f) {
4890 if (ctxt->funcHash == NULL)
4891 ctxt->funcHash = xmlHashCreate(0);
4892 if (ctxt->funcHash == NULL)
4895 return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
4896 return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, XML_CAST_FPTR(f)));
4900 * xmlXPathRegisterFuncLookup:
4901 * @ctxt: the XPath context
4902 * @f: the lookup function
4903 * @funcCtxt: the lookup data
4905 * Registers an external mechanism to do function lookup.
4908 xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
4909 xmlXPathFuncLookupFunc f,
4913 ctxt->funcLookupFunc = f;
4914 ctxt->funcLookupData = funcCtxt;
4918 * xmlXPathFunctionLookup:
4919 * @ctxt: the XPath context
4920 * @name: the function name
4922 * Search in the Function array of the context for the given
4925 * Returns the xmlXPathFunction or NULL if not found
4928 xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
4932 if (ctxt->funcLookupFunc != NULL) {
4933 xmlXPathFunction ret;
4934 xmlXPathFuncLookupFunc f;
4936 f = ctxt->funcLookupFunc;
4937 ret = f(ctxt->funcLookupData, name, NULL);
4941 return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
4945 * xmlXPathFunctionLookupNS:
4946 * @ctxt: the XPath context
4947 * @name: the function name
4948 * @ns_uri: the function namespace URI
4950 * Search in the Function array of the context for the given
4953 * Returns the xmlXPathFunction or NULL if not found
4956 xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
4957 const xmlChar *ns_uri) {
4958 xmlXPathFunction ret;
4965 if (ctxt->funcLookupFunc != NULL) {
4966 xmlXPathFuncLookupFunc f;
4968 f = ctxt->funcLookupFunc;
4969 ret = f(ctxt->funcLookupData, name, ns_uri);
4974 if (ctxt->funcHash == NULL)
4977 XML_CAST_FPTR(ret) = xmlHashLookup2(ctxt->funcHash, name, ns_uri);
4982 * xmlXPathRegisteredFuncsCleanup:
4983 * @ctxt: the XPath context
4985 * Cleanup the XPath context data associated to registered functions
4988 xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
4992 xmlHashFree(ctxt->funcHash, NULL);
4993 ctxt->funcHash = NULL;
4996 /************************************************************************
4998 * Routines to handle Variables *
5000 ************************************************************************/
5003 * xmlXPathRegisterVariable:
5004 * @ctxt: the XPath context
5005 * @name: the variable name
5006 * @value: the variable value or NULL
5008 * Register a new variable value. If @value is NULL it unregisters
5011 * Returns 0 in case of success, -1 in case of error
5014 xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
5015 xmlXPathObjectPtr value) {
5016 return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
5020 * xmlXPathRegisterVariableNS:
5021 * @ctxt: the XPath context
5022 * @name: the variable name
5023 * @ns_uri: the variable namespace URI
5024 * @value: the variable value or NULL
5026 * Register a new variable value. If @value is NULL it unregisters
5029 * Returns 0 in case of success, -1 in case of error
5032 xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5033 const xmlChar *ns_uri,
5034 xmlXPathObjectPtr value) {
5040 if (ctxt->varHash == NULL)
5041 ctxt->varHash = xmlHashCreate(0);
5042 if (ctxt->varHash == NULL)
5045 return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
5046 (xmlHashDeallocator)xmlXPathFreeObject));
5047 return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
5049 (xmlHashDeallocator)xmlXPathFreeObject));
5053 * xmlXPathRegisterVariableLookup:
5054 * @ctxt: the XPath context
5055 * @f: the lookup function
5056 * @data: the lookup data
5058 * register an external mechanism to do variable lookup
5061 xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
5062 xmlXPathVariableLookupFunc f, void *data) {
5065 ctxt->varLookupFunc = f;
5066 ctxt->varLookupData = data;
5070 * xmlXPathVariableLookup:
5071 * @ctxt: the XPath context
5072 * @name: the variable name
5074 * Search in the Variable array of the context for the given
5077 * Returns a copy of the value or NULL if not found
5080 xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
5084 if (ctxt->varLookupFunc != NULL) {
5085 xmlXPathObjectPtr ret;
5087 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5088 (ctxt->varLookupData, name, NULL);
5091 return(xmlXPathVariableLookupNS(ctxt, name, NULL));
5095 * xmlXPathVariableLookupNS:
5096 * @ctxt: the XPath context
5097 * @name: the variable name
5098 * @ns_uri: the variable namespace URI
5100 * Search in the Variable array of the context for the given
5103 * Returns the a copy of the value or NULL if not found
5106 xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
5107 const xmlChar *ns_uri) {
5111 if (ctxt->varLookupFunc != NULL) {
5112 xmlXPathObjectPtr ret;
5114 ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
5115 (ctxt->varLookupData, name, ns_uri);
5116 if (ret != NULL) return(ret);
5119 if (ctxt->varHash == NULL)
5124 return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
5125 xmlHashLookup2(ctxt->varHash, name, ns_uri)));
5129 * xmlXPathRegisteredVariablesCleanup:
5130 * @ctxt: the XPath context
5132 * Cleanup the XPath context data associated to registered variables
5135 xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
5139 xmlHashFree(ctxt->varHash, (xmlHashDeallocator)xmlXPathFreeObject);
5140 ctxt->varHash = NULL;
5144 * xmlXPathRegisterNs:
5145 * @ctxt: the XPath context
5146 * @prefix: the namespace prefix cannot be NULL or empty string
5147 * @ns_uri: the namespace name
5149 * Register a new namespace. If @ns_uri is NULL it unregisters
5152 * Returns 0 in case of success, -1 in case of error
5155 xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
5156 const xmlChar *ns_uri) {
5164 if (ctxt->nsHash == NULL)
5165 ctxt->nsHash = xmlHashCreate(10);
5166 if (ctxt->nsHash == NULL)
5169 return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
5170 (xmlHashDeallocator)xmlFree));
5171 return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) xmlStrdup(ns_uri),
5172 (xmlHashDeallocator)xmlFree));
5177 * @ctxt: the XPath context
5178 * @prefix: the namespace prefix value
5180 * Search in the namespace declaration array of the context for the given
5181 * namespace name associated to the given prefix
5183 * Returns the value or NULL if not found
5186 xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
5192 #ifdef XML_XML_NAMESPACE
5193 if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
5194 return(XML_XML_NAMESPACE);
5197 if (ctxt->namespaces != NULL) {
5200 for (i = 0;i < ctxt->nsNr;i++) {
5201 if ((ctxt->namespaces[i] != NULL) &&
5202 (xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
5203 return(ctxt->namespaces[i]->href);
5207 return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
5211 * xmlXPathRegisteredNsCleanup:
5212 * @ctxt: the XPath context
5214 * Cleanup the XPath context data associated to registered variables
5217 xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
5221 xmlHashFree(ctxt->nsHash, (xmlHashDeallocator)xmlFree);
5222 ctxt->nsHash = NULL;
5225 /************************************************************************
5227 * Routines to handle Values *
5229 ************************************************************************/
5231 /* Allocations are terrible, one needs to optimize all this !!! */
5235 * @val: the double value
5237 * Create a new xmlXPathObjectPtr of type double and of value @val
5239 * Returns the newly created object.
5242 xmlXPathNewFloat(double val) {
5243 xmlXPathObjectPtr ret;
5245 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5247 xmlXPathErrMemory(NULL, "creating float object\n");
5250 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5251 ret->type = XPATH_NUMBER;
5252 ret->floatval = val;
5253 #ifdef XP_DEBUG_OBJ_USAGE
5254 xmlXPathDebugObjUsageRequested(NULL, XPATH_NUMBER);
5260 * xmlXPathNewBoolean:
5261 * @val: the boolean value
5263 * Create a new xmlXPathObjectPtr of type boolean and of value @val
5265 * Returns the newly created object.
5268 xmlXPathNewBoolean(int val) {
5269 xmlXPathObjectPtr ret;
5271 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5273 xmlXPathErrMemory(NULL, "creating boolean object\n");
5276 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5277 ret->type = XPATH_BOOLEAN;
5278 ret->boolval = (val != 0);
5279 #ifdef XP_DEBUG_OBJ_USAGE
5280 xmlXPathDebugObjUsageRequested(NULL, XPATH_BOOLEAN);
5286 * xmlXPathNewString:
5287 * @val: the xmlChar * value
5289 * Create a new xmlXPathObjectPtr of type string and of value @val
5291 * Returns the newly created object.
5294 xmlXPathNewString(const xmlChar *val) {
5295 xmlXPathObjectPtr ret;
5297 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5299 xmlXPathErrMemory(NULL, "creating string object\n");
5302 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5303 ret->type = XPATH_STRING;
5305 ret->stringval = xmlStrdup(val);
5307 ret->stringval = xmlStrdup((const xmlChar *)"");
5308 #ifdef XP_DEBUG_OBJ_USAGE
5309 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5315 * xmlXPathWrapString:
5316 * @val: the xmlChar * value
5318 * Wraps the @val string into an XPath object.
5320 * Returns the newly created object.
5323 xmlXPathWrapString (xmlChar *val) {
5324 xmlXPathObjectPtr ret;
5326 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5328 xmlXPathErrMemory(NULL, "creating string object\n");
5331 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5332 ret->type = XPATH_STRING;
5333 ret->stringval = val;
5334 #ifdef XP_DEBUG_OBJ_USAGE
5335 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5341 * xmlXPathNewCString:
5342 * @val: the char * value
5344 * Create a new xmlXPathObjectPtr of type string and of value @val
5346 * Returns the newly created object.
5349 xmlXPathNewCString(const char *val) {
5350 xmlXPathObjectPtr ret;
5352 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5354 xmlXPathErrMemory(NULL, "creating string object\n");
5357 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5358 ret->type = XPATH_STRING;
5359 ret->stringval = xmlStrdup(BAD_CAST val);
5360 #ifdef XP_DEBUG_OBJ_USAGE
5361 xmlXPathDebugObjUsageRequested(NULL, XPATH_STRING);
5367 * xmlXPathWrapCString:
5368 * @val: the char * value
5370 * Wraps a string into an XPath object.
5372 * Returns the newly created object.
5375 xmlXPathWrapCString (char * val) {
5376 return(xmlXPathWrapString((xmlChar *)(val)));
5380 * xmlXPathWrapExternal:
5381 * @val: the user data
5383 * Wraps the @val data into an XPath object.
5385 * Returns the newly created object.
5388 xmlXPathWrapExternal (void *val) {
5389 xmlXPathObjectPtr ret;
5391 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5393 xmlXPathErrMemory(NULL, "creating user object\n");
5396 memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
5397 ret->type = XPATH_USERS;
5399 #ifdef XP_DEBUG_OBJ_USAGE
5400 xmlXPathDebugObjUsageRequested(NULL, XPATH_USERS);
5406 * xmlXPathObjectCopy:
5407 * @val: the original object
5409 * allocate a new copy of a given object
5411 * Returns the newly created object.
5414 xmlXPathObjectCopy(xmlXPathObjectPtr val) {
5415 xmlXPathObjectPtr ret;
5420 ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
5422 xmlXPathErrMemory(NULL, "copying object\n");
5425 memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
5426 #ifdef XP_DEBUG_OBJ_USAGE
5427 xmlXPathDebugObjUsageRequested(NULL, val->type);
5429 switch (val->type) {
5436 ret->stringval = xmlStrdup(val->stringval);
5438 case XPATH_XSLT_TREE:
5441 Removed 11 July 2004 - the current handling of xslt tmpRVT nodes means that
5442 this previous handling is no longer correct, and can cause some serious
5443 problems (ref. bug 145547)
5445 if ((val->nodesetval != NULL) &&
5446 (val->nodesetval->nodeTab != NULL)) {
5447 xmlNodePtr cur, tmp;
5451 top = xmlNewDoc(NULL);
5452 top->name = (char *)
5453 xmlStrdup(val->nodesetval->nodeTab[0]->name);
5457 cur = val->nodesetval->nodeTab[0]->children;
5458 while (cur != NULL) {
5459 tmp = xmlDocCopyNode(cur, top, 1);
5460 xmlAddChild((xmlNodePtr) top, tmp);
5465 ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
5467 ret->nodesetval = xmlXPathNodeSetCreate(NULL);
5468 /* Deallocate the copied tree value */
5472 ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
5473 /* Do not deallocate the copied tree value */
5476 case XPATH_LOCATIONSET:
5477 #ifdef LIBXML_XPTR_ENABLED
5479 xmlLocationSetPtr loc = val->user;
5480 ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
5485 ret->user = val->user;
5487 case XPATH_UNDEFINED:
5488 xmlGenericError(xmlGenericErrorContext,
5489 "xmlXPathObjectCopy: unsupported type %d\n",
5497 * xmlXPathFreeObject:
5498 * @obj: the object to free
5500 * Free up an xmlXPathObjectPtr object.
5503 xmlXPathFreeObject(xmlXPathObjectPtr obj) {
5504 if (obj == NULL) return;
5505 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
5508 if (obj->user != NULL) {
5509 xmlXPathFreeNodeSet(obj->nodesetval);
5510 xmlFreeNodeList((xmlNodePtr) obj->user);
5513 obj->type = XPATH_XSLT_TREE; /* TODO: Just for debugging. */
5514 if (obj->nodesetval != NULL)
5515 xmlXPathFreeValueTree(obj->nodesetval);
5517 if (obj->nodesetval != NULL)
5518 xmlXPathFreeNodeSet(obj->nodesetval);
5520 #ifdef LIBXML_XPTR_ENABLED
5521 } else if (obj->type == XPATH_LOCATIONSET) {
5522 if (obj->user != NULL)
5523 xmlXPtrFreeLocationSet(obj->user);
5525 } else if (obj->type == XPATH_STRING) {
5526 if (obj->stringval != NULL)
5527 xmlFree(obj->stringval);
5529 #ifdef XP_DEBUG_OBJ_USAGE
5530 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5536 * xmlXPathReleaseObject:
5537 * @obj: the xmlXPathObjectPtr to free or to cache
5539 * Depending on the state of the cache this frees the given
5540 * XPath object or stores it in the cache.
5543 xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
5545 #define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
5546 sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
5547 if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
5549 #define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
5553 if ((ctxt == NULL) || (ctxt->cache == NULL)) {
5554 xmlXPathFreeObject(obj);
5556 xmlXPathContextCachePtr cache =
5557 (xmlXPathContextCachePtr) ctxt->cache;
5559 switch (obj->type) {
5561 case XPATH_XSLT_TREE:
5562 if (obj->nodesetval != NULL) {
5565 * It looks like the @boolval is used for
5566 * evaluation if this an XSLT Result Tree Fragment.
5567 * TODO: Check if this assumption is correct.
5569 obj->type = XPATH_XSLT_TREE; /* just for debugging */
5570 xmlXPathFreeValueTree(obj->nodesetval);
5571 obj->nodesetval = NULL;
5572 } else if ((obj->nodesetval->nodeMax <= 40) &&
5573 (XP_CACHE_WANTS(cache->nodesetObjs,
5574 cache->maxNodeset)))
5576 XP_CACHE_ADD(cache->nodesetObjs, obj);
5579 xmlXPathFreeNodeSet(obj->nodesetval);
5580 obj->nodesetval = NULL;
5585 if (obj->stringval != NULL)
5586 xmlFree(obj->stringval);
5588 if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
5589 XP_CACHE_ADD(cache->stringObjs, obj);
5594 if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
5595 XP_CACHE_ADD(cache->booleanObjs, obj);
5600 if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
5601 XP_CACHE_ADD(cache->numberObjs, obj);
5605 #ifdef LIBXML_XPTR_ENABLED
5606 case XPATH_LOCATIONSET:
5607 if (obj->user != NULL) {
5608 xmlXPtrFreeLocationSet(obj->user);
5617 * Fallback to adding to the misc-objects slot.
5619 if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
5620 XP_CACHE_ADD(cache->miscObjs, obj);
5626 #ifdef XP_DEBUG_OBJ_USAGE
5627 xmlXPathDebugObjUsageReleased(ctxt, obj->type);
5630 if (obj->nodesetval != NULL) {
5631 xmlNodeSetPtr tmpset = obj->nodesetval;
5634 * TODO: Due to those nasty ns-nodes, we need to traverse
5635 * the list and free the ns-nodes.
5636 * URGENT TODO: Check if it's actually slowing things down.
5637 * Maybe we shouldn't try to preserve the list.
5639 if (tmpset->nodeNr > 1) {
5643 for (i = 0; i < tmpset->nodeNr; i++) {
5644 node = tmpset->nodeTab[i];
5645 if ((node != NULL) &&
5646 (node->type == XML_NAMESPACE_DECL))
5648 xmlXPathNodeSetFreeNs((xmlNsPtr) node);
5651 } else if (tmpset->nodeNr == 1) {
5652 if ((tmpset->nodeTab[0] != NULL) &&
5653 (tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
5654 xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
5657 memset(obj, 0, sizeof(xmlXPathObject));
5658 obj->nodesetval = tmpset;
5660 memset(obj, 0, sizeof(xmlXPathObject));
5666 * Cache is full; free the object.
5668 if (obj->nodesetval != NULL)
5669 xmlXPathFreeNodeSet(obj->nodesetval);
5670 #ifdef XP_DEBUG_OBJ_USAGE
5671 xmlXPathDebugObjUsageReleased(NULL, obj->type);
5679 /************************************************************************
5681 * Type Casting Routines *
5683 ************************************************************************/
5686 * xmlXPathCastBooleanToString:
5689 * Converts a boolean to its string value.
5691 * Returns a newly allocated string.
5694 xmlXPathCastBooleanToString (int val) {
5697 ret = xmlStrdup((const xmlChar *) "true");
5699 ret = xmlStrdup((const xmlChar *) "false");
5704 * xmlXPathCastNumberToString:
5707 * Converts a number to its string value.
5709 * Returns a newly allocated string.
5712 xmlXPathCastNumberToString (double val) {
5714 switch (xmlXPathIsInf(val)) {
5716 ret = xmlStrdup((const xmlChar *) "Infinity");
5719 ret = xmlStrdup((const xmlChar *) "-Infinity");
5722 if (xmlXPathIsNaN(val)) {
5723 ret = xmlStrdup((const xmlChar *) "NaN");
5724 } else if (val == 0 && xmlXPathGetSign(val) != 0) {
5725 ret = xmlStrdup((const xmlChar *) "0");
5727 /* could be improved */
5729 xmlXPathFormatNumber(val, buf, 99);
5731 ret = xmlStrdup((const xmlChar *) buf);
5738 * xmlXPathCastNodeToString:
5741 * Converts a node to its string value.
5743 * Returns a newly allocated string.
5746 xmlXPathCastNodeToString (xmlNodePtr node) {
5748 if ((ret = xmlNodeGetContent(node)) == NULL)
5749 ret = xmlStrdup((const xmlChar *) "");
5754 * xmlXPathCastNodeSetToString:
5757 * Converts a node-set to its string value.
5759 * Returns a newly allocated string.
5762 xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
5763 if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
5764 return(xmlStrdup((const xmlChar *) ""));
5767 xmlXPathNodeSetSort(ns);
5768 return(xmlXPathCastNodeToString(ns->nodeTab[0]));
5772 * xmlXPathCastToString:
5773 * @val: an XPath object
5775 * Converts an existing object to its string() equivalent
5777 * Returns the allocated string value of the object, NULL in case of error.
5778 * It's up to the caller to free the string memory with xmlFree().
5781 xmlXPathCastToString(xmlXPathObjectPtr val) {
5782 xmlChar *ret = NULL;
5785 return(xmlStrdup((const xmlChar *) ""));
5786 switch (val->type) {
5787 case XPATH_UNDEFINED:
5789 xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
5791 ret = xmlStrdup((const xmlChar *) "");
5794 case XPATH_XSLT_TREE:
5795 ret = xmlXPathCastNodeSetToString(val->nodesetval);
5798 return(xmlStrdup(val->stringval));
5800 ret = xmlXPathCastBooleanToString(val->boolval);
5802 case XPATH_NUMBER: {
5803 ret = xmlXPathCastNumberToString(val->floatval);
5809 case XPATH_LOCATIONSET:
5811 ret = xmlStrdup((const xmlChar *) "");
5818 * xmlXPathConvertString:
5819 * @val: an XPath object
5821 * Converts an existing object to its string() equivalent
5823 * Returns the new object, the old one is freed (or the operation
5824 * is done directly on @val)
5827 xmlXPathConvertString(xmlXPathObjectPtr val) {
5828 xmlChar *res = NULL;
5831 return(xmlXPathNewCString(""));
5833 switch (val->type) {
5834 case XPATH_UNDEFINED:
5836 xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
5840 case XPATH_XSLT_TREE:
5841 res = xmlXPathCastNodeSetToString(val->nodesetval);
5846 res = xmlXPathCastBooleanToString(val->boolval);
5849 res = xmlXPathCastNumberToString(val->floatval);
5854 case XPATH_LOCATIONSET:
5858 xmlXPathFreeObject(val);
5860 return(xmlXPathNewCString(""));
5861 return(xmlXPathWrapString(res));
5865 * xmlXPathCastBooleanToNumber:
5868 * Converts a boolean to its number value
5870 * Returns the number value
5873 xmlXPathCastBooleanToNumber(int val) {
5880 * xmlXPathCastStringToNumber:
5883 * Converts a string to its number value
5885 * Returns the number value
5888 xmlXPathCastStringToNumber(const xmlChar * val) {
5889 return(xmlXPathStringEvalNumber(val));
5893 * xmlXPathCastNodeToNumber:
5896 * Converts a node to its number value
5898 * Returns the number value
5901 xmlXPathCastNodeToNumber (xmlNodePtr node) {
5906 return(xmlXPathNAN);
5907 strval = xmlXPathCastNodeToString(node);
5909 return(xmlXPathNAN);
5910 ret = xmlXPathCastStringToNumber(strval);
5917 * xmlXPathCastNodeSetToNumber:
5920 * Converts a node-set to its number value
5922 * Returns the number value
5925 xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
5930 return(xmlXPathNAN);
5931 str = xmlXPathCastNodeSetToString(ns);
5932 ret = xmlXPathCastStringToNumber(str);
5938 * xmlXPathCastToNumber:
5939 * @val: an XPath object
5941 * Converts an XPath object to its number value
5943 * Returns the number value
5946 xmlXPathCastToNumber(xmlXPathObjectPtr val) {
5950 return(xmlXPathNAN);
5951 switch (val->type) {
5952 case XPATH_UNDEFINED:
5954 xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
5959 case XPATH_XSLT_TREE:
5960 ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
5963 ret = xmlXPathCastStringToNumber(val->stringval);
5966 ret = val->floatval;
5969 ret = xmlXPathCastBooleanToNumber(val->boolval);
5974 case XPATH_LOCATIONSET:
5983 * xmlXPathConvertNumber:
5984 * @val: an XPath object
5986 * Converts an existing object to its number() equivalent
5988 * Returns the new object, the old one is freed (or the operation
5989 * is done directly on @val)
5992 xmlXPathConvertNumber(xmlXPathObjectPtr val) {
5993 xmlXPathObjectPtr ret;
5996 return(xmlXPathNewFloat(0.0));
5997 if (val->type == XPATH_NUMBER)
5999 ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
6000 xmlXPathFreeObject(val);
6005 * xmlXPathCastNumberToBoolean:
6008 * Converts a number to its boolean value
6010 * Returns the boolean value
6013 xmlXPathCastNumberToBoolean (double val) {
6014 if (xmlXPathIsNaN(val) || (val == 0.0))
6020 * xmlXPathCastStringToBoolean:
6023 * Converts a string to its boolean value
6025 * Returns the boolean value
6028 xmlXPathCastStringToBoolean (const xmlChar *val) {
6029 if ((val == NULL) || (xmlStrlen(val) == 0))
6035 * xmlXPathCastNodeSetToBoolean:
6038 * Converts a node-set to its boolean value
6040 * Returns the boolean value
6043 xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
6044 if ((ns == NULL) || (ns->nodeNr == 0))
6050 * xmlXPathCastToBoolean:
6051 * @val: an XPath object
6053 * Converts an XPath object to its boolean value
6055 * Returns the boolean value
6058 xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
6063 switch (val->type) {
6064 case XPATH_UNDEFINED:
6066 xmlGenericError(xmlGenericErrorContext, "BOOLEAN: undefined\n");
6071 case XPATH_XSLT_TREE:
6072 ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
6075 ret = xmlXPathCastStringToBoolean(val->stringval);
6078 ret = xmlXPathCastNumberToBoolean(val->floatval);
6086 case XPATH_LOCATIONSET:
6096 * xmlXPathConvertBoolean:
6097 * @val: an XPath object
6099 * Converts an existing object to its boolean() equivalent
6101 * Returns the new object, the old one is freed (or the operation
6102 * is done directly on @val)
6105 xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
6106 xmlXPathObjectPtr ret;
6109 return(xmlXPathNewBoolean(0));
6110 if (val->type == XPATH_BOOLEAN)
6112 ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
6113 xmlXPathFreeObject(val);
6117 /************************************************************************
6119 * Routines to handle XPath contexts *
6121 ************************************************************************/
6124 * xmlXPathNewContext:
6125 * @doc: the XML document
6127 * Create a new xmlXPathContext
6129 * Returns the xmlXPathContext just allocated. The caller will need to free it.
6132 xmlXPathNewContext(xmlDocPtr doc) {
6133 xmlXPathContextPtr ret;
6135 ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
6137 xmlXPathErrMemory(NULL, "creating context\n");
6140 memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
6144 ret->varHash = NULL;
6150 ret->funcHash = xmlHashCreate(0);
6159 ret->contextSize = -1;
6160 ret->proximityPosition = -1;
6162 #ifdef XP_DEFAULT_CACHE_ON
6163 if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
6164 xmlXPathFreeContext(ret);
6169 xmlXPathRegisterAllFunctions(ret);
6175 * xmlXPathFreeContext:
6176 * @ctxt: the context to free
6178 * Free up an xmlXPathContext
6181 xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
6182 if (ctxt == NULL) return;
6184 if (ctxt->cache != NULL)
6185 xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
6186 xmlXPathRegisteredNsCleanup(ctxt);
6187 xmlXPathRegisteredFuncsCleanup(ctxt);
6188 xmlXPathRegisteredVariablesCleanup(ctxt);
6189 xmlResetError(&ctxt->lastError);
6193 /************************************************************************
6195 * Routines to handle XPath parser contexts *
6197 ************************************************************************/
6199 #define CHECK_CTXT(ctxt) \
6200 if (ctxt == NULL) { \
6201 __xmlRaiseError(NULL, NULL, NULL, \
6202 NULL, NULL, XML_FROM_XPATH, \
6203 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6204 __FILE__, __LINE__, \
6205 NULL, NULL, NULL, 0, 0, \
6206 "NULL context pointer\n"); \
6210 #define CHECK_CTXT_NEG(ctxt) \
6211 if (ctxt == NULL) { \
6212 __xmlRaiseError(NULL, NULL, NULL, \
6213 NULL, NULL, XML_FROM_XPATH, \
6214 XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
6215 __FILE__, __LINE__, \
6216 NULL, NULL, NULL, 0, 0, \
6217 "NULL context pointer\n"); \
6222 #define CHECK_CONTEXT(ctxt) \
6223 if ((ctxt == NULL) || (ctxt->doc == NULL) || \
6224 (ctxt->doc->children == NULL)) { \
6225 xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
6231 * xmlXPathNewParserContext:
6232 * @str: the XPath expression
6233 * @ctxt: the XPath context
6235 * Create a new xmlXPathParserContext
6237 * Returns the xmlXPathParserContext just allocated.
6239 xmlXPathParserContextPtr
6240 xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
6241 xmlXPathParserContextPtr ret;
6243 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6245 xmlXPathErrMemory(ctxt, "creating parser context\n");
6248 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6249 ret->cur = ret->base = str;
6250 ret->context = ctxt;
6252 ret->comp = xmlXPathNewCompExpr();
6253 if (ret->comp == NULL) {
6254 xmlFree(ret->valueTab);
6258 if ((ctxt != NULL) && (ctxt->dict != NULL)) {
6259 ret->comp->dict = ctxt->dict;
6260 xmlDictReference(ret->comp->dict);
6267 * xmlXPathCompParserContext:
6268 * @comp: the XPath compiled expression
6269 * @ctxt: the XPath context
6271 * Create a new xmlXPathParserContext when processing a compiled expression
6273 * Returns the xmlXPathParserContext just allocated.
6275 static xmlXPathParserContextPtr
6276 xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
6277 xmlXPathParserContextPtr ret;
6279 ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
6281 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6284 memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
6286 /* Allocate the value stack */
6287 ret->valueTab = (xmlXPathObjectPtr *)
6288 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
6289 if (ret->valueTab == NULL) {
6291 xmlXPathErrMemory(ctxt, "creating evaluation context\n");
6297 ret->valueFrame = 0;
6299 ret->context = ctxt;
6306 * xmlXPathFreeParserContext:
6307 * @ctxt: the context to free
6309 * Free up an xmlXPathParserContext
6312 xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
6315 if (ctxt->valueTab != NULL) {
6316 for (i = 0; i < ctxt->valueNr; i++) {
6318 xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
6320 xmlXPathFreeObject(ctxt->valueTab[i]);
6322 xmlFree(ctxt->valueTab);
6324 if (ctxt->comp != NULL) {
6325 #ifdef XPATH_STREAMING
6326 if (ctxt->comp->stream != NULL) {
6327 xmlFreePatternList(ctxt->comp->stream);
6328 ctxt->comp->stream = NULL;
6331 xmlXPathFreeCompExpr(ctxt->comp);
6336 /************************************************************************
6338 * The implicit core function library *
6340 ************************************************************************/
6343 * xmlXPathNodeValHash:
6344 * @node: a node pointer
6346 * Function computing the beginning of the string value of the node,
6347 * used to speed up comparisons
6349 * Returns an int usable as a hash
6352 xmlXPathNodeValHash(xmlNodePtr node) {
6354 const xmlChar * string = NULL;
6355 xmlNodePtr tmp = NULL;
6356 unsigned int ret = 0;
6361 if (node->type == XML_DOCUMENT_NODE) {
6362 tmp = xmlDocGetRootElement((xmlDocPtr) node);
6364 node = node->children;
6372 switch (node->type) {
6373 case XML_COMMENT_NODE:
6375 case XML_CDATA_SECTION_NODE:
6377 string = node->content;
6382 return(((unsigned int) string[0]) +
6383 (((unsigned int) string[1]) << 8));
6384 case XML_NAMESPACE_DECL:
6385 string = ((xmlNsPtr)node)->href;
6390 return(((unsigned int) string[0]) +
6391 (((unsigned int) string[1]) << 8));
6392 case XML_ATTRIBUTE_NODE:
6393 tmp = ((xmlAttrPtr) node)->children;
6395 case XML_ELEMENT_NODE:
6396 tmp = node->children;
6401 while (tmp != NULL) {
6402 switch (tmp->type) {
6403 case XML_COMMENT_NODE:
6405 case XML_CDATA_SECTION_NODE:
6407 string = tmp->content;
6409 case XML_NAMESPACE_DECL:
6410 string = ((xmlNsPtr)tmp)->href;
6415 if ((string != NULL) && (string[0] != 0)) {
6417 return(ret + (((unsigned int) string[0]) << 8));
6419 if (string[1] == 0) {
6421 ret = (unsigned int) string[0];
6423 return(((unsigned int) string[0]) +
6424 (((unsigned int) string[1]) << 8));
6430 if ((tmp->children != NULL) && (tmp->type != XML_DTD_NODE)) {
6431 if (tmp->children->type != XML_ENTITY_DECL) {
6432 tmp = tmp->children;
6439 if (tmp->next != NULL) {
6452 if (tmp->next != NULL) {
6456 } while (tmp != NULL);
6462 * xmlXPathStringHash:
6465 * Function computing the beginning of the string value of the node,
6466 * used to speed up comparisons
6468 * Returns an int usable as a hash
6471 xmlXPathStringHash(const xmlChar * string) {
6473 return((unsigned int) 0);
6476 return(((unsigned int) string[0]) +
6477 (((unsigned int) string[1]) << 8));
6481 * xmlXPathCompareNodeSetFloat:
6482 * @ctxt: the XPath Parser context
6483 * @inf: less than (1) or greater than (0)
6484 * @strict: is the comparison strict
6485 * @arg: the node set
6488 * Implement the compare operation between a nodeset and a number
6489 * @ns < @val (1, 1, ...
6490 * @ns <= @val (1, 0, ...
6491 * @ns > @val (0, 1, ...
6492 * @ns >= @val (0, 0, ...
6494 * If one object to be compared is a node-set and the other is a number,
6495 * then the comparison will be true if and only if there is a node in the
6496 * node-set such that the result of performing the comparison on the number
6497 * to be compared and on the result of converting the string-value of that
6498 * node to a number using the number function is true.
6500 * Returns 0 or 1 depending on the results of the test.
6503 xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
6504 xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
6509 if ((f == NULL) || (arg == NULL) ||
6510 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6511 xmlXPathReleaseObject(ctxt->context, arg);
6512 xmlXPathReleaseObject(ctxt->context, f);
6515 ns = arg->nodesetval;
6517 for (i = 0;i < ns->nodeNr;i++) {
6518 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6521 xmlXPathCacheNewString(ctxt->context, str2));
6523 xmlXPathNumberFunction(ctxt, 1);
6524 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
6525 ret = xmlXPathCompareValues(ctxt, inf, strict);
6531 xmlXPathReleaseObject(ctxt->context, arg);
6532 xmlXPathReleaseObject(ctxt->context, f);
6537 * xmlXPathCompareNodeSetString:
6538 * @ctxt: the XPath Parser context
6539 * @inf: less than (1) or greater than (0)
6540 * @strict: is the comparison strict
6541 * @arg: the node set
6544 * Implement the compare operation between a nodeset and a string
6545 * @ns < @val (1, 1, ...
6546 * @ns <= @val (1, 0, ...
6547 * @ns > @val (0, 1, ...
6548 * @ns >= @val (0, 0, ...
6550 * If one object to be compared is a node-set and the other is a string,
6551 * then the comparison will be true if and only if there is a node in
6552 * the node-set such that the result of performing the comparison on the
6553 * string-value of the node and the other string is true.
6555 * Returns 0 or 1 depending on the results of the test.
6558 xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
6559 xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
6564 if ((s == NULL) || (arg == NULL) ||
6565 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
6566 xmlXPathReleaseObject(ctxt->context, arg);
6567 xmlXPathReleaseObject(ctxt->context, s);
6570 ns = arg->nodesetval;
6572 for (i = 0;i < ns->nodeNr;i++) {
6573 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6576 xmlXPathCacheNewString(ctxt->context, str2));
6578 valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
6579 ret = xmlXPathCompareValues(ctxt, inf, strict);
6585 xmlXPathReleaseObject(ctxt->context, arg);
6586 xmlXPathReleaseObject(ctxt->context, s);
6591 * xmlXPathCompareNodeSets:
6592 * @inf: less than (1) or greater than (0)
6593 * @strict: is the comparison strict
6594 * @arg1: the first node set object
6595 * @arg2: the second node set object
6597 * Implement the compare operation on nodesets:
6599 * If both objects to be compared are node-sets, then the comparison
6600 * will be true if and only if there is a node in the first node-set
6601 * and a node in the second node-set such that the result of performing
6602 * the comparison on the string-values of the two nodes is true.
6604 * When neither object to be compared is a node-set and the operator
6605 * is <=, <, >= or >, then the objects are compared by converting both
6606 * objects to numbers and comparing the numbers according to IEEE 754.
6608 * The number function converts its argument to a number as follows:
6609 * - a string that consists of optional whitespace followed by an
6610 * optional minus sign followed by a Number followed by whitespace
6611 * is converted to the IEEE 754 number that is nearest (according
6612 * to the IEEE 754 round-to-nearest rule) to the mathematical value
6613 * represented by the string; any other string is converted to NaN
6615 * Conclusion all nodes need to be converted first to their string value
6616 * and then the comparison must be done when possible
6619 xmlXPathCompareNodeSets(int inf, int strict,
6620 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6628 if ((arg1 == NULL) ||
6629 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
6630 xmlXPathFreeObject(arg2);
6633 if ((arg2 == NULL) ||
6634 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
6635 xmlXPathFreeObject(arg1);
6636 xmlXPathFreeObject(arg2);
6640 ns1 = arg1->nodesetval;
6641 ns2 = arg2->nodesetval;
6643 if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
6644 xmlXPathFreeObject(arg1);
6645 xmlXPathFreeObject(arg2);
6648 if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
6649 xmlXPathFreeObject(arg1);
6650 xmlXPathFreeObject(arg2);
6654 values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
6655 if (values2 == NULL) {
6656 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6657 xmlXPathFreeObject(arg1);
6658 xmlXPathFreeObject(arg2);
6661 for (i = 0;i < ns1->nodeNr;i++) {
6662 val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
6663 if (xmlXPathIsNaN(val1))
6665 for (j = 0;j < ns2->nodeNr;j++) {
6667 values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
6669 if (xmlXPathIsNaN(values2[j]))
6672 ret = (val1 < values2[j]);
6673 else if (inf && !strict)
6674 ret = (val1 <= values2[j]);
6675 else if (!inf && strict)
6676 ret = (val1 > values2[j]);
6677 else if (!inf && !strict)
6678 ret = (val1 >= values2[j]);
6687 xmlXPathFreeObject(arg1);
6688 xmlXPathFreeObject(arg2);
6693 * xmlXPathCompareNodeSetValue:
6694 * @ctxt: the XPath Parser context
6695 * @inf: less than (1) or greater than (0)
6696 * @strict: is the comparison strict
6697 * @arg: the node set
6700 * Implement the compare operation between a nodeset and a value
6701 * @ns < @val (1, 1, ...
6702 * @ns <= @val (1, 0, ...
6703 * @ns > @val (0, 1, ...
6704 * @ns >= @val (0, 0, ...
6706 * If one object to be compared is a node-set and the other is a boolean,
6707 * then the comparison will be true if and only if the result of performing
6708 * the comparison on the boolean and on the result of converting
6709 * the node-set to a boolean using the boolean function is true.
6711 * Returns 0 or 1 depending on the results of the test.
6714 xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
6715 xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
6716 if ((val == NULL) || (arg == NULL) ||
6717 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6722 return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
6724 case XPATH_XSLT_TREE:
6725 return(xmlXPathCompareNodeSets(inf, strict, arg, val));
6727 return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
6729 valuePush(ctxt, arg);
6730 xmlXPathBooleanFunction(ctxt, 1);
6731 valuePush(ctxt, val);
6732 return(xmlXPathCompareValues(ctxt, inf, strict));
6734 xmlGenericError(xmlGenericErrorContext,
6735 "xmlXPathCompareNodeSetValue: Can't compare node set "
6736 "and object of type %d\n",
6738 xmlXPathReleaseObject(ctxt->context, arg);
6739 xmlXPathReleaseObject(ctxt->context, val);
6740 XP_ERROR0(XPATH_INVALID_TYPE);
6746 * xmlXPathEqualNodeSetString:
6747 * @arg: the nodeset object argument
6748 * @str: the string to compare to.
6749 * @neq: flag to show whether for '=' (0) or '!=' (1)
6751 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6752 * If one object to be compared is a node-set and the other is a string,
6753 * then the comparison will be true if and only if there is a node in
6754 * the node-set such that the result of performing the comparison on the
6755 * string-value of the node and the other string is true.
6757 * Returns 0 or 1 depending on the results of the test.
6760 xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
6767 if ((str == NULL) || (arg == NULL) ||
6768 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6770 ns = arg->nodesetval;
6772 * A NULL nodeset compared with a string is always false
6773 * (since there is no node equal, and no node not equal)
6775 if ((ns == NULL) || (ns->nodeNr <= 0) )
6777 hash = xmlXPathStringHash(str);
6778 for (i = 0; i < ns->nodeNr; i++) {
6779 if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
6780 str2 = xmlNodeGetContent(ns->nodeTab[i]);
6781 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
6786 } else if ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
6804 * xmlXPathEqualNodeSetFloat:
6805 * @arg: the nodeset object argument
6806 * @f: the float to compare to
6807 * @neq: flag to show whether to compare '=' (0) or '!=' (1)
6809 * Implement the equal operation on XPath objects content: @arg1 == @arg2
6810 * If one object to be compared is a node-set and the other is a number,
6811 * then the comparison will be true if and only if there is a node in
6812 * the node-set such that the result of performing the comparison on the
6813 * number to be compared and on the result of converting the string-value
6814 * of that node to a number using the number function is true.
6816 * Returns 0 or 1 depending on the results of the test.
6819 xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
6820 xmlXPathObjectPtr arg, double f, int neq) {
6824 xmlXPathObjectPtr val;
6827 if ((arg == NULL) ||
6828 ((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
6831 ns = arg->nodesetval;
6833 for (i=0;i<ns->nodeNr;i++) {
6834 str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
6836 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
6838 xmlXPathNumberFunction(ctxt, 1);
6839 val = valuePop(ctxt);
6841 xmlXPathReleaseObject(ctxt->context, val);
6842 if (!xmlXPathIsNaN(v)) {
6843 if ((!neq) && (v==f)) {
6846 } else if ((neq) && (v!=f)) {
6850 } else { /* NaN is unequal to any value */
6863 * xmlXPathEqualNodeSets:
6864 * @arg1: first nodeset object argument
6865 * @arg2: second nodeset object argument
6866 * @neq: flag to show whether to test '=' (0) or '!=' (1)
6868 * Implement the equal / not equal operation on XPath nodesets:
6869 * @arg1 == @arg2 or @arg1 != @arg2
6870 * If both objects to be compared are node-sets, then the comparison
6871 * will be true if and only if there is a node in the first node-set and
6872 * a node in the second node-set such that the result of performing the
6873 * comparison on the string-values of the two nodes is true.
6875 * (needless to say, this is a costly operation)
6877 * Returns 0 or 1 depending on the results of the test.
6880 xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
6882 unsigned int *hashs1;
6883 unsigned int *hashs2;
6890 if ((arg1 == NULL) ||
6891 ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
6893 if ((arg2 == NULL) ||
6894 ((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
6897 ns1 = arg1->nodesetval;
6898 ns2 = arg2->nodesetval;
6900 if ((ns1 == NULL) || (ns1->nodeNr <= 0))
6902 if ((ns2 == NULL) || (ns2->nodeNr <= 0))
6906 * for equal, check if there is a node pertaining to both sets
6909 for (i = 0;i < ns1->nodeNr;i++)
6910 for (j = 0;j < ns2->nodeNr;j++)
6911 if (ns1->nodeTab[i] == ns2->nodeTab[j])
6914 values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
6915 if (values1 == NULL) {
6916 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6919 hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
6920 if (hashs1 == NULL) {
6921 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6925 memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
6926 values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
6927 if (values2 == NULL) {
6928 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6933 hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
6934 if (hashs2 == NULL) {
6935 xmlXPathErrMemory(NULL, "comparing nodesets\n");
6941 memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
6942 for (i = 0;i < ns1->nodeNr;i++) {
6943 hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
6944 for (j = 0;j < ns2->nodeNr;j++) {
6946 hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
6947 if (hashs1[i] != hashs2[j]) {
6954 if (values1[i] == NULL)
6955 values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
6956 if (values2[j] == NULL)
6957 values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
6958 ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
6966 for (i = 0;i < ns1->nodeNr;i++)
6967 if (values1[i] != NULL)
6968 xmlFree(values1[i]);
6969 for (j = 0;j < ns2->nodeNr;j++)
6970 if (values2[j] != NULL)
6971 xmlFree(values2[j]);
6980 xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
6981 xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
6984 *At this point we are assured neither arg1 nor arg2
6985 *is a nodeset, so we can just pick the appropriate routine.
6987 switch (arg1->type) {
6988 case XPATH_UNDEFINED:
6990 xmlGenericError(xmlGenericErrorContext,
6991 "Equal: undefined\n");
6995 switch (arg2->type) {
6996 case XPATH_UNDEFINED:
6998 xmlGenericError(xmlGenericErrorContext,
6999 "Equal: undefined\n");
7004 xmlGenericError(xmlGenericErrorContext,
7005 "Equal: %d boolean %d \n",
7006 arg1->boolval, arg2->boolval);
7008 ret = (arg1->boolval == arg2->boolval);
7011 ret = (arg1->boolval ==
7012 xmlXPathCastNumberToBoolean(arg2->floatval));
7015 if ((arg2->stringval == NULL) ||
7016 (arg2->stringval[0] == 0)) ret = 0;
7019 ret = (arg1->boolval == ret);
7024 case XPATH_LOCATIONSET:
7028 case XPATH_XSLT_TREE:
7033 switch (arg2->type) {
7034 case XPATH_UNDEFINED:
7036 xmlGenericError(xmlGenericErrorContext,
7037 "Equal: undefined\n");
7041 ret = (arg2->boolval==
7042 xmlXPathCastNumberToBoolean(arg1->floatval));
7045 valuePush(ctxt, arg2);
7046 xmlXPathNumberFunction(ctxt, 1);
7047 arg2 = valuePop(ctxt);
7048 /* no break on purpose */
7050 /* Hand check NaN and Infinity equalities */
7051 if (xmlXPathIsNaN(arg1->floatval) ||
7052 xmlXPathIsNaN(arg2->floatval)) {
7054 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7055 if (xmlXPathIsInf(arg2->floatval) == 1)
7059 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7060 if (xmlXPathIsInf(arg2->floatval) == -1)
7064 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7065 if (xmlXPathIsInf(arg1->floatval) == 1)
7069 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7070 if (xmlXPathIsInf(arg1->floatval) == -1)
7075 ret = (arg1->floatval == arg2->floatval);
7081 case XPATH_LOCATIONSET:
7085 case XPATH_XSLT_TREE:
7090 switch (arg2->type) {
7091 case XPATH_UNDEFINED:
7093 xmlGenericError(xmlGenericErrorContext,
7094 "Equal: undefined\n");
7098 if ((arg1->stringval == NULL) ||
7099 (arg1->stringval[0] == 0)) ret = 0;
7102 ret = (arg2->boolval == ret);
7105 ret = xmlStrEqual(arg1->stringval, arg2->stringval);
7108 valuePush(ctxt, arg1);
7109 xmlXPathNumberFunction(ctxt, 1);
7110 arg1 = valuePop(ctxt);
7111 /* Hand check NaN and Infinity equalities */
7112 if (xmlXPathIsNaN(arg1->floatval) ||
7113 xmlXPathIsNaN(arg2->floatval)) {
7115 } else if (xmlXPathIsInf(arg1->floatval) == 1) {
7116 if (xmlXPathIsInf(arg2->floatval) == 1)
7120 } else if (xmlXPathIsInf(arg1->floatval) == -1) {
7121 if (xmlXPathIsInf(arg2->floatval) == -1)
7125 } else if (xmlXPathIsInf(arg2->floatval) == 1) {
7126 if (xmlXPathIsInf(arg1->floatval) == 1)
7130 } else if (xmlXPathIsInf(arg2->floatval) == -1) {
7131 if (xmlXPathIsInf(arg1->floatval) == -1)
7136 ret = (arg1->floatval == arg2->floatval);
7142 case XPATH_LOCATIONSET:
7146 case XPATH_XSLT_TREE:
7153 case XPATH_LOCATIONSET:
7157 case XPATH_XSLT_TREE:
7160 xmlXPathReleaseObject(ctxt->context, arg1);
7161 xmlXPathReleaseObject(ctxt->context, arg2);
7166 * xmlXPathEqualValues:
7167 * @ctxt: the XPath Parser context
7169 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7171 * Returns 0 or 1 depending on the results of the test.
7174 xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
7175 xmlXPathObjectPtr arg1, arg2, argtmp;
7178 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7179 arg2 = valuePop(ctxt);
7180 arg1 = valuePop(ctxt);
7181 if ((arg1 == NULL) || (arg2 == NULL)) {
7183 xmlXPathReleaseObject(ctxt->context, arg1);
7185 xmlXPathReleaseObject(ctxt->context, arg2);
7186 XP_ERROR0(XPATH_INVALID_OPERAND);
7191 xmlGenericError(xmlGenericErrorContext,
7192 "Equal: by pointer\n");
7194 xmlXPathFreeObject(arg1);
7199 *If either argument is a nodeset, it's a 'special case'
7201 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7202 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7204 *Hack it to assure arg1 is the nodeset
7206 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7211 switch (arg2->type) {
7212 case XPATH_UNDEFINED:
7214 xmlGenericError(xmlGenericErrorContext,
7215 "Equal: undefined\n");
7219 case XPATH_XSLT_TREE:
7220 ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
7223 if ((arg1->nodesetval == NULL) ||
7224 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7227 ret = (ret == arg2->boolval);
7230 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
7233 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
7238 case XPATH_LOCATIONSET:
7242 xmlXPathReleaseObject(ctxt->context, arg1);
7243 xmlXPathReleaseObject(ctxt->context, arg2);
7247 return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7251 * xmlXPathNotEqualValues:
7252 * @ctxt: the XPath Parser context
7254 * Implement the equal operation on XPath objects content: @arg1 == @arg2
7256 * Returns 0 or 1 depending on the results of the test.
7259 xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
7260 xmlXPathObjectPtr arg1, arg2, argtmp;
7263 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7264 arg2 = valuePop(ctxt);
7265 arg1 = valuePop(ctxt);
7266 if ((arg1 == NULL) || (arg2 == NULL)) {
7268 xmlXPathReleaseObject(ctxt->context, arg1);
7270 xmlXPathReleaseObject(ctxt->context, arg2);
7271 XP_ERROR0(XPATH_INVALID_OPERAND);
7276 xmlGenericError(xmlGenericErrorContext,
7277 "NotEqual: by pointer\n");
7279 xmlXPathReleaseObject(ctxt->context, arg1);
7284 *If either argument is a nodeset, it's a 'special case'
7286 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7287 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7289 *Hack it to assure arg1 is the nodeset
7291 if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
7296 switch (arg2->type) {
7297 case XPATH_UNDEFINED:
7299 xmlGenericError(xmlGenericErrorContext,
7300 "NotEqual: undefined\n");
7304 case XPATH_XSLT_TREE:
7305 ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
7308 if ((arg1->nodesetval == NULL) ||
7309 (arg1->nodesetval->nodeNr == 0)) ret = 0;
7312 ret = (ret != arg2->boolval);
7315 ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
7318 ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
7323 case XPATH_LOCATIONSET:
7327 xmlXPathReleaseObject(ctxt->context, arg1);
7328 xmlXPathReleaseObject(ctxt->context, arg2);
7332 return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
7336 * xmlXPathCompareValues:
7337 * @ctxt: the XPath Parser context
7338 * @inf: less than (1) or greater than (0)
7339 * @strict: is the comparison strict
7341 * Implement the compare operation on XPath objects:
7342 * @arg1 < @arg2 (1, 1, ...
7343 * @arg1 <= @arg2 (1, 0, ...
7344 * @arg1 > @arg2 (0, 1, ...
7345 * @arg1 >= @arg2 (0, 0, ...
7347 * When neither object to be compared is a node-set and the operator is
7348 * <=, <, >=, >, then the objects are compared by converted both objects
7349 * to numbers and comparing the numbers according to IEEE 754. The <
7350 * comparison will be true if and only if the first number is less than the
7351 * second number. The <= comparison will be true if and only if the first
7352 * number is less than or equal to the second number. The > comparison
7353 * will be true if and only if the first number is greater than the second
7354 * number. The >= comparison will be true if and only if the first number
7355 * is greater than or equal to the second number.
7357 * Returns 1 if the comparison succeeded, 0 if it failed
7360 xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
7361 int ret = 0, arg1i = 0, arg2i = 0;
7362 xmlXPathObjectPtr arg1, arg2;
7364 if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
7365 arg2 = valuePop(ctxt);
7366 arg1 = valuePop(ctxt);
7367 if ((arg1 == NULL) || (arg2 == NULL)) {
7369 xmlXPathReleaseObject(ctxt->context, arg1);
7371 xmlXPathReleaseObject(ctxt->context, arg2);
7372 XP_ERROR0(XPATH_INVALID_OPERAND);
7375 if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
7376 (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7378 * If either argument is a XPATH_NODESET or XPATH_XSLT_TREE the two arguments
7379 * are not freed from within this routine; they will be freed from the
7380 * called routine, e.g. xmlXPathCompareNodeSets or xmlXPathCompareNodeSetValue
7382 if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
7383 ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
7384 ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
7386 if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
7387 ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
7390 ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
7397 if (arg1->type != XPATH_NUMBER) {
7398 valuePush(ctxt, arg1);
7399 xmlXPathNumberFunction(ctxt, 1);
7400 arg1 = valuePop(ctxt);
7402 if (arg1->type != XPATH_NUMBER) {
7403 xmlXPathFreeObject(arg1);
7404 xmlXPathFreeObject(arg2);
7405 XP_ERROR0(XPATH_INVALID_OPERAND);
7407 if (arg2->type != XPATH_NUMBER) {
7408 valuePush(ctxt, arg2);
7409 xmlXPathNumberFunction(ctxt, 1);
7410 arg2 = valuePop(ctxt);
7412 if (arg2->type != XPATH_NUMBER) {
7413 xmlXPathReleaseObject(ctxt->context, arg1);
7414 xmlXPathReleaseObject(ctxt->context, arg2);
7415 XP_ERROR0(XPATH_INVALID_OPERAND);
7418 * Add tests for infinity and nan
7419 * => feedback on 3.4 for Inf and NaN
7421 /* Hand check NaN and Infinity comparisons */
7422 if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
7425 arg1i=xmlXPathIsInf(arg1->floatval);
7426 arg2i=xmlXPathIsInf(arg2->floatval);
7427 if (inf && strict) {
7428 if ((arg1i == -1 && arg2i != -1) ||
7429 (arg2i == 1 && arg1i != 1)) {
7431 } else if (arg1i == 0 && arg2i == 0) {
7432 ret = (arg1->floatval < arg2->floatval);
7437 else if (inf && !strict) {
7438 if (arg1i == -1 || arg2i == 1) {
7440 } else if (arg1i == 0 && arg2i == 0) {
7441 ret = (arg1->floatval <= arg2->floatval);
7446 else if (!inf && strict) {
7447 if ((arg1i == 1 && arg2i != 1) ||
7448 (arg2i == -1 && arg1i != -1)) {
7450 } else if (arg1i == 0 && arg2i == 0) {
7451 ret = (arg1->floatval > arg2->floatval);
7456 else if (!inf && !strict) {
7457 if (arg1i == 1 || arg2i == -1) {
7459 } else if (arg1i == 0 && arg2i == 0) {
7460 ret = (arg1->floatval >= arg2->floatval);
7466 xmlXPathReleaseObject(ctxt->context, arg1);
7467 xmlXPathReleaseObject(ctxt->context, arg2);
7472 * xmlXPathValueFlipSign:
7473 * @ctxt: the XPath Parser context
7475 * Implement the unary - operation on an XPath object
7476 * The numeric operators convert their operands to numbers as if
7477 * by calling the number function.
7480 xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
7481 if ((ctxt == NULL) || (ctxt->context == NULL)) return;
7483 CHECK_TYPE(XPATH_NUMBER);
7484 if (xmlXPathIsNaN(ctxt->value->floatval))
7485 ctxt->value->floatval=xmlXPathNAN;
7486 else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
7487 ctxt->value->floatval=xmlXPathNINF;
7488 else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
7489 ctxt->value->floatval=xmlXPathPINF;
7490 else if (ctxt->value->floatval == 0) {
7491 if (xmlXPathGetSign(ctxt->value->floatval) == 0)
7492 ctxt->value->floatval = xmlXPathNZERO;
7494 ctxt->value->floatval = 0;
7497 ctxt->value->floatval = - ctxt->value->floatval;
7501 * xmlXPathAddValues:
7502 * @ctxt: the XPath Parser context
7504 * Implement the add operation on XPath objects:
7505 * The numeric operators convert their operands to numbers as if
7506 * by calling the number function.
7509 xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
7510 xmlXPathObjectPtr arg;
7513 arg = valuePop(ctxt);
7515 XP_ERROR(XPATH_INVALID_OPERAND);
7516 val = xmlXPathCastToNumber(arg);
7517 xmlXPathReleaseObject(ctxt->context, arg);
7519 CHECK_TYPE(XPATH_NUMBER);
7520 ctxt->value->floatval += val;
7524 * xmlXPathSubValues:
7525 * @ctxt: the XPath Parser context
7527 * Implement the subtraction operation on XPath objects:
7528 * The numeric operators convert their operands to numbers as if
7529 * by calling the number function.
7532 xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
7533 xmlXPathObjectPtr arg;
7536 arg = valuePop(ctxt);
7538 XP_ERROR(XPATH_INVALID_OPERAND);
7539 val = xmlXPathCastToNumber(arg);
7540 xmlXPathReleaseObject(ctxt->context, arg);
7542 CHECK_TYPE(XPATH_NUMBER);
7543 ctxt->value->floatval -= val;
7547 * xmlXPathMultValues:
7548 * @ctxt: the XPath Parser context
7550 * Implement the multiply operation on XPath objects:
7551 * The numeric operators convert their operands to numbers as if
7552 * by calling the number function.
7555 xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
7556 xmlXPathObjectPtr arg;
7559 arg = valuePop(ctxt);
7561 XP_ERROR(XPATH_INVALID_OPERAND);
7562 val = xmlXPathCastToNumber(arg);
7563 xmlXPathReleaseObject(ctxt->context, arg);
7565 CHECK_TYPE(XPATH_NUMBER);
7566 ctxt->value->floatval *= val;
7570 * xmlXPathDivValues:
7571 * @ctxt: the XPath Parser context
7573 * Implement the div operation on XPath objects @arg1 / @arg2:
7574 * The numeric operators convert their operands to numbers as if
7575 * by calling the number function.
7578 xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
7579 xmlXPathObjectPtr arg;
7582 arg = valuePop(ctxt);
7584 XP_ERROR(XPATH_INVALID_OPERAND);
7585 val = xmlXPathCastToNumber(arg);
7586 xmlXPathReleaseObject(ctxt->context, arg);
7588 CHECK_TYPE(XPATH_NUMBER);
7589 if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
7590 ctxt->value->floatval = xmlXPathNAN;
7591 else if (val == 0 && xmlXPathGetSign(val) != 0) {
7592 if (ctxt->value->floatval == 0)
7593 ctxt->value->floatval = xmlXPathNAN;
7594 else if (ctxt->value->floatval > 0)
7595 ctxt->value->floatval = xmlXPathNINF;
7596 else if (ctxt->value->floatval < 0)
7597 ctxt->value->floatval = xmlXPathPINF;
7599 else if (val == 0) {
7600 if (ctxt->value->floatval == 0)
7601 ctxt->value->floatval = xmlXPathNAN;
7602 else if (ctxt->value->floatval > 0)
7603 ctxt->value->floatval = xmlXPathPINF;
7604 else if (ctxt->value->floatval < 0)
7605 ctxt->value->floatval = xmlXPathNINF;
7607 ctxt->value->floatval /= val;
7611 * xmlXPathModValues:
7612 * @ctxt: the XPath Parser context
7614 * Implement the mod operation on XPath objects: @arg1 / @arg2
7615 * The numeric operators convert their operands to numbers as if
7616 * by calling the number function.
7619 xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
7620 xmlXPathObjectPtr arg;
7623 arg = valuePop(ctxt);
7625 XP_ERROR(XPATH_INVALID_OPERAND);
7626 arg2 = xmlXPathCastToNumber(arg);
7627 xmlXPathReleaseObject(ctxt->context, arg);
7629 CHECK_TYPE(XPATH_NUMBER);
7630 arg1 = ctxt->value->floatval;
7632 ctxt->value->floatval = xmlXPathNAN;
7634 ctxt->value->floatval = fmod(arg1, arg2);
7638 /************************************************************************
7640 * The traversal functions *
7642 ************************************************************************/
7645 * A traversal function enumerates nodes along an axis.
7646 * Initially it must be called with NULL, and it indicates
7647 * termination on the axis by returning NULL.
7649 typedef xmlNodePtr (*xmlXPathTraversalFunction)
7650 (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
7653 * xmlXPathTraversalFunctionExt:
7654 * A traversal function enumerates nodes along an axis.
7655 * Initially it must be called with NULL, and it indicates
7656 * termination on the axis by returning NULL.
7657 * The context node of the traversal is specified via @contextNode.
7659 typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
7660 (xmlNodePtr cur, xmlNodePtr contextNode);
7663 * xmlXPathNodeSetMergeFunction:
7664 * Used for merging node sets in xmlXPathCollectAndTest().
7666 typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
7667 (xmlNodeSetPtr, xmlNodeSetPtr, int);
7672 * @ctxt: the XPath Parser context
7673 * @cur: the current node in the traversal
7675 * Traversal function for the "self" direction
7676 * The self axis contains just the context node itself
7678 * Returns the next element following that axis
7681 xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7682 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7684 return(ctxt->context->node);
7689 * xmlXPathNextChild:
7690 * @ctxt: the XPath Parser context
7691 * @cur: the current node in the traversal
7693 * Traversal function for the "child" direction
7694 * The child axis contains the children of the context node in document order.
7696 * Returns the next element following that axis
7699 xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7700 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7702 if (ctxt->context->node == NULL) return(NULL);
7703 switch (ctxt->context->node->type) {
7704 case XML_ELEMENT_NODE:
7706 case XML_CDATA_SECTION_NODE:
7707 case XML_ENTITY_REF_NODE:
7708 case XML_ENTITY_NODE:
7710 case XML_COMMENT_NODE:
7711 case XML_NOTATION_NODE:
7713 return(ctxt->context->node->children);
7714 case XML_DOCUMENT_NODE:
7715 case XML_DOCUMENT_TYPE_NODE:
7716 case XML_DOCUMENT_FRAG_NODE:
7717 case XML_HTML_DOCUMENT_NODE:
7718 #ifdef LIBXML_DOCB_ENABLED
7719 case XML_DOCB_DOCUMENT_NODE:
7721 return(((xmlDocPtr) ctxt->context->node)->children);
7722 case XML_ELEMENT_DECL:
7723 case XML_ATTRIBUTE_DECL:
7724 case XML_ENTITY_DECL:
7725 case XML_ATTRIBUTE_NODE:
7726 case XML_NAMESPACE_DECL:
7727 case XML_XINCLUDE_START:
7728 case XML_XINCLUDE_END:
7733 if ((cur->type == XML_DOCUMENT_NODE) ||
7734 (cur->type == XML_HTML_DOCUMENT_NODE))
7740 * xmlXPathNextChildElement:
7741 * @ctxt: the XPath Parser context
7742 * @cur: the current node in the traversal
7744 * Traversal function for the "child" direction and nodes of type element.
7745 * The child axis contains the children of the context node in document order.
7747 * Returns the next element following that axis
7750 xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7751 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7753 cur = ctxt->context->node;
7754 if (cur == NULL) return(NULL);
7756 * Get the first element child.
7758 switch (cur->type) {
7759 case XML_ELEMENT_NODE:
7760 case XML_DOCUMENT_FRAG_NODE:
7761 case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */
7762 case XML_ENTITY_NODE:
7763 cur = cur->children;
7765 if (cur->type == XML_ELEMENT_NODE)
7769 } while ((cur != NULL) &&
7770 (cur->type != XML_ELEMENT_NODE));
7774 case XML_DOCUMENT_NODE:
7775 case XML_HTML_DOCUMENT_NODE:
7776 #ifdef LIBXML_DOCB_ENABLED
7777 case XML_DOCB_DOCUMENT_NODE:
7779 return(xmlDocGetRootElement((xmlDocPtr) cur));
7786 * Get the next sibling element node.
7788 switch (cur->type) {
7789 case XML_ELEMENT_NODE:
7791 case XML_ENTITY_REF_NODE:
7792 case XML_ENTITY_NODE:
7793 case XML_CDATA_SECTION_NODE:
7795 case XML_COMMENT_NODE:
7796 case XML_XINCLUDE_END:
7798 /* case XML_DTD_NODE: */ /* URGENT TODO: DTD-node as well? */
7802 if (cur->next != NULL) {
7803 if (cur->next->type == XML_ELEMENT_NODE)
7808 } while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
7816 * xmlXPathNextDescendantOrSelfElemParent:
7817 * @ctxt: the XPath Parser context
7818 * @cur: the current node in the traversal
7820 * Traversal function for the "descendant-or-self" axis.
7821 * Additionally it returns only nodes which can be parents of
7825 * Returns the next element following that axis
7828 xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
7829 xmlNodePtr contextNode)
7832 if (contextNode == NULL)
7834 switch (contextNode->type) {
7835 case XML_ELEMENT_NODE:
7836 case XML_XINCLUDE_START:
7837 case XML_DOCUMENT_FRAG_NODE:
7838 case XML_DOCUMENT_NODE:
7839 #ifdef LIBXML_DOCB_ENABLED
7840 case XML_DOCB_DOCUMENT_NODE:
7842 case XML_HTML_DOCUMENT_NODE:
7843 return(contextNode);
7849 xmlNodePtr start = cur;
7851 while (cur != NULL) {
7852 switch (cur->type) {
7853 case XML_ELEMENT_NODE:
7854 /* TODO: OK to have XInclude here? */
7855 case XML_XINCLUDE_START:
7856 case XML_DOCUMENT_FRAG_NODE:
7859 if (cur->children != NULL) {
7860 cur = cur->children;
7864 /* Not sure if we need those here. */
7865 case XML_DOCUMENT_NODE:
7866 #ifdef LIBXML_DOCB_ENABLED
7867 case XML_DOCB_DOCUMENT_NODE:
7869 case XML_HTML_DOCUMENT_NODE:
7872 return(xmlDocGetRootElement((xmlDocPtr) cur));
7878 if ((cur == NULL) || (cur == contextNode))
7880 if (cur->next != NULL) {
7893 * xmlXPathNextDescendant:
7894 * @ctxt: the XPath Parser context
7895 * @cur: the current node in the traversal
7897 * Traversal function for the "descendant" direction
7898 * the descendant axis contains the descendants of the context node in document
7899 * order; a descendant is a child or a child of a child and so on.
7901 * Returns the next element following that axis
7904 xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7905 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7907 if (ctxt->context->node == NULL)
7909 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7910 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7913 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
7914 return(ctxt->context->doc->children);
7915 return(ctxt->context->node->children);
7918 if (cur->type == XML_NAMESPACE_DECL)
7920 if (cur->children != NULL) {
7922 * Do not descend on entities declarations
7924 if (cur->children->type != XML_ENTITY_DECL) {
7925 cur = cur->children;
7929 if (cur->type != XML_DTD_NODE)
7934 if (cur == ctxt->context->node) return(NULL);
7936 while (cur->next != NULL) {
7938 if ((cur->type != XML_ENTITY_DECL) &&
7939 (cur->type != XML_DTD_NODE))
7945 if (cur == NULL) break;
7946 if (cur == ctxt->context->node) return(NULL);
7947 if (cur->next != NULL) {
7951 } while (cur != NULL);
7956 * xmlXPathNextDescendantOrSelf:
7957 * @ctxt: the XPath Parser context
7958 * @cur: the current node in the traversal
7960 * Traversal function for the "descendant-or-self" direction
7961 * the descendant-or-self axis contains the context node and the descendants
7962 * of the context node in document order; thus the context node is the first
7963 * node on the axis, and the first child of the context node is the second node
7966 * Returns the next element following that axis
7969 xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7970 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7972 return(ctxt->context->node);
7974 if (ctxt->context->node == NULL)
7976 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
7977 (ctxt->context->node->type == XML_NAMESPACE_DECL))
7980 return(xmlXPathNextDescendant(ctxt, cur));
7984 * xmlXPathNextParent:
7985 * @ctxt: the XPath Parser context
7986 * @cur: the current node in the traversal
7988 * Traversal function for the "parent" direction
7989 * The parent axis contains the parent of the context node, if there is one.
7991 * Returns the next element following that axis
7994 xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
7995 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
7997 * the parent of an attribute or namespace node is the element
7998 * to which the attribute or namespace node is attached
7999 * Namespace handling !!!
8002 if (ctxt->context->node == NULL) return(NULL);
8003 switch (ctxt->context->node->type) {
8004 case XML_ELEMENT_NODE:
8006 case XML_CDATA_SECTION_NODE:
8007 case XML_ENTITY_REF_NODE:
8008 case XML_ENTITY_NODE:
8010 case XML_COMMENT_NODE:
8011 case XML_NOTATION_NODE:
8013 case XML_ELEMENT_DECL:
8014 case XML_ATTRIBUTE_DECL:
8015 case XML_XINCLUDE_START:
8016 case XML_XINCLUDE_END:
8017 case XML_ENTITY_DECL:
8018 if (ctxt->context->node->parent == NULL)
8019 return((xmlNodePtr) ctxt->context->doc);
8020 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8021 ((ctxt->context->node->parent->name[0] == ' ') ||
8022 (xmlStrEqual(ctxt->context->node->parent->name,
8023 BAD_CAST "fake node libxslt"))))
8025 return(ctxt->context->node->parent);
8026 case XML_ATTRIBUTE_NODE: {
8027 xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
8029 return(att->parent);
8031 case XML_DOCUMENT_NODE:
8032 case XML_DOCUMENT_TYPE_NODE:
8033 case XML_DOCUMENT_FRAG_NODE:
8034 case XML_HTML_DOCUMENT_NODE:
8035 #ifdef LIBXML_DOCB_ENABLED
8036 case XML_DOCB_DOCUMENT_NODE:
8039 case XML_NAMESPACE_DECL: {
8040 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8042 if ((ns->next != NULL) &&
8043 (ns->next->type != XML_NAMESPACE_DECL))
8044 return((xmlNodePtr) ns->next);
8053 * xmlXPathNextAncestor:
8054 * @ctxt: the XPath Parser context
8055 * @cur: the current node in the traversal
8057 * Traversal function for the "ancestor" direction
8058 * the ancestor axis contains the ancestors of the context node; the ancestors
8059 * of the context node consist of the parent of context node and the parent's
8060 * parent and so on; the nodes are ordered in reverse document order; thus the
8061 * parent is the first node on the axis, and the parent's parent is the second
8064 * Returns the next element following that axis
8067 xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8068 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8070 * the parent of an attribute or namespace node is the element
8071 * to which the attribute or namespace node is attached
8075 if (ctxt->context->node == NULL) return(NULL);
8076 switch (ctxt->context->node->type) {
8077 case XML_ELEMENT_NODE:
8079 case XML_CDATA_SECTION_NODE:
8080 case XML_ENTITY_REF_NODE:
8081 case XML_ENTITY_NODE:
8083 case XML_COMMENT_NODE:
8085 case XML_ELEMENT_DECL:
8086 case XML_ATTRIBUTE_DECL:
8087 case XML_ENTITY_DECL:
8088 case XML_NOTATION_NODE:
8089 case XML_XINCLUDE_START:
8090 case XML_XINCLUDE_END:
8091 if (ctxt->context->node->parent == NULL)
8092 return((xmlNodePtr) ctxt->context->doc);
8093 if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
8094 ((ctxt->context->node->parent->name[0] == ' ') ||
8095 (xmlStrEqual(ctxt->context->node->parent->name,
8096 BAD_CAST "fake node libxslt"))))
8098 return(ctxt->context->node->parent);
8099 case XML_ATTRIBUTE_NODE: {
8100 xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
8102 return(tmp->parent);
8104 case XML_DOCUMENT_NODE:
8105 case XML_DOCUMENT_TYPE_NODE:
8106 case XML_DOCUMENT_FRAG_NODE:
8107 case XML_HTML_DOCUMENT_NODE:
8108 #ifdef LIBXML_DOCB_ENABLED
8109 case XML_DOCB_DOCUMENT_NODE:
8112 case XML_NAMESPACE_DECL: {
8113 xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
8115 if ((ns->next != NULL) &&
8116 (ns->next->type != XML_NAMESPACE_DECL))
8117 return((xmlNodePtr) ns->next);
8118 /* Bad, how did that namespace end up here ? */
8124 if (cur == ctxt->context->doc->children)
8125 return((xmlNodePtr) ctxt->context->doc);
8126 if (cur == (xmlNodePtr) ctxt->context->doc)
8128 switch (cur->type) {
8129 case XML_ELEMENT_NODE:
8131 case XML_CDATA_SECTION_NODE:
8132 case XML_ENTITY_REF_NODE:
8133 case XML_ENTITY_NODE:
8135 case XML_COMMENT_NODE:
8136 case XML_NOTATION_NODE:
8138 case XML_ELEMENT_DECL:
8139 case XML_ATTRIBUTE_DECL:
8140 case XML_ENTITY_DECL:
8141 case XML_XINCLUDE_START:
8142 case XML_XINCLUDE_END:
8143 if (cur->parent == NULL)
8145 if ((cur->parent->type == XML_ELEMENT_NODE) &&
8146 ((cur->parent->name[0] == ' ') ||
8147 (xmlStrEqual(cur->parent->name,
8148 BAD_CAST "fake node libxslt"))))
8150 return(cur->parent);
8151 case XML_ATTRIBUTE_NODE: {
8152 xmlAttrPtr att = (xmlAttrPtr) cur;
8154 return(att->parent);
8156 case XML_NAMESPACE_DECL: {
8157 xmlNsPtr ns = (xmlNsPtr) cur;
8159 if ((ns->next != NULL) &&
8160 (ns->next->type != XML_NAMESPACE_DECL))
8161 return((xmlNodePtr) ns->next);
8162 /* Bad, how did that namespace end up here ? */
8165 case XML_DOCUMENT_NODE:
8166 case XML_DOCUMENT_TYPE_NODE:
8167 case XML_DOCUMENT_FRAG_NODE:
8168 case XML_HTML_DOCUMENT_NODE:
8169 #ifdef LIBXML_DOCB_ENABLED
8170 case XML_DOCB_DOCUMENT_NODE:
8178 * xmlXPathNextAncestorOrSelf:
8179 * @ctxt: the XPath Parser context
8180 * @cur: the current node in the traversal
8182 * Traversal function for the "ancestor-or-self" direction
8183 * he ancestor-or-self axis contains the context node and ancestors of
8184 * the context node in reverse document order; thus the context node is
8185 * the first node on the axis, and the context node's parent the second;
8186 * parent here is defined the same as with the parent axis.
8188 * Returns the next element following that axis
8191 xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8192 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8194 return(ctxt->context->node);
8195 return(xmlXPathNextAncestor(ctxt, cur));
8199 * xmlXPathNextFollowingSibling:
8200 * @ctxt: the XPath Parser context
8201 * @cur: the current node in the traversal
8203 * Traversal function for the "following-sibling" direction
8204 * The following-sibling axis contains the following siblings of the context
8205 * node in document order.
8207 * Returns the next element following that axis
8210 xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8211 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8212 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8213 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8215 if (cur == (xmlNodePtr) ctxt->context->doc)
8218 return(ctxt->context->node->next);
8223 * xmlXPathNextPrecedingSibling:
8224 * @ctxt: the XPath Parser context
8225 * @cur: the current node in the traversal
8227 * Traversal function for the "preceding-sibling" direction
8228 * The preceding-sibling axis contains the preceding siblings of the context
8229 * node in reverse document order; the first preceding sibling is first on the
8230 * axis; the sibling preceding that node is the second on the axis and so on.
8232 * Returns the next element following that axis
8235 xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8236 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8237 if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
8238 (ctxt->context->node->type == XML_NAMESPACE_DECL))
8240 if (cur == (xmlNodePtr) ctxt->context->doc)
8243 return(ctxt->context->node->prev);
8244 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
8247 return(ctxt->context->node->prev);
8253 * xmlXPathNextFollowing:
8254 * @ctxt: the XPath Parser context
8255 * @cur: the current node in the traversal
8257 * Traversal function for the "following" direction
8258 * The following axis contains all nodes in the same document as the context
8259 * node that are after the context node in document order, excluding any
8260 * descendants and excluding attribute nodes and namespace nodes; the nodes
8261 * are ordered in document order
8263 * Returns the next element following that axis
8266 xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8267 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8268 if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
8269 (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
8270 return(cur->children);
8273 cur = ctxt->context->node;
8274 if (cur->type == XML_ATTRIBUTE_NODE) {
8276 } else if (cur->type == XML_NAMESPACE_DECL) {
8277 xmlNsPtr ns = (xmlNsPtr) cur;
8279 if ((ns->next == NULL) ||
8280 (ns->next->type == XML_NAMESPACE_DECL))
8282 cur = (xmlNodePtr) ns->next;
8285 if (cur == NULL) return(NULL) ; /* ERROR */
8286 if (cur->next != NULL) return(cur->next) ;
8289 if (cur == NULL) break;
8290 if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
8291 if (cur->next != NULL) return(cur->next);
8292 } while (cur != NULL);
8297 * xmlXPathIsAncestor:
8298 * @ancestor: the ancestor node
8299 * @node: the current node
8301 * Check that @ancestor is a @node's ancestor
8303 * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
8306 xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
8307 if ((ancestor == NULL) || (node == NULL)) return(0);
8308 if (node->type == XML_NAMESPACE_DECL)
8310 if (ancestor->type == XML_NAMESPACE_DECL)
8312 /* nodes need to be in the same document */
8313 if (ancestor->doc != node->doc) return(0);
8314 /* avoid searching if ancestor or node is the root node */
8315 if (ancestor == (xmlNodePtr) node->doc) return(1);
8316 if (node == (xmlNodePtr) ancestor->doc) return(0);
8317 while (node->parent != NULL) {
8318 if (node->parent == ancestor)
8320 node = node->parent;
8326 * xmlXPathNextPreceding:
8327 * @ctxt: the XPath Parser context
8328 * @cur: the current node in the traversal
8330 * Traversal function for the "preceding" direction
8331 * the preceding axis contains all nodes in the same document as the context
8332 * node that are before the context node in document order, excluding any
8333 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8334 * ordered in reverse document order
8336 * Returns the next element following that axis
8339 xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
8341 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8343 cur = ctxt->context->node;
8344 if (cur->type == XML_ATTRIBUTE_NODE) {
8346 } else if (cur->type == XML_NAMESPACE_DECL) {
8347 xmlNsPtr ns = (xmlNsPtr) cur;
8349 if ((ns->next == NULL) ||
8350 (ns->next->type == XML_NAMESPACE_DECL))
8352 cur = (xmlNodePtr) ns->next;
8355 if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
8357 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8360 if (cur->prev != NULL) {
8361 for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
8368 if (cur == ctxt->context->doc->children)
8370 } while (xmlXPathIsAncestor(cur, ctxt->context->node));
8375 * xmlXPathNextPrecedingInternal:
8376 * @ctxt: the XPath Parser context
8377 * @cur: the current node in the traversal
8379 * Traversal function for the "preceding" direction
8380 * the preceding axis contains all nodes in the same document as the context
8381 * node that are before the context node in document order, excluding any
8382 * ancestors and excluding attribute nodes and namespace nodes; the nodes are
8383 * ordered in reverse document order
8384 * This is a faster implementation but internal only since it requires a
8385 * state kept in the parser context: ctxt->ancestor.
8387 * Returns the next element following that axis
8390 xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
8393 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8395 cur = ctxt->context->node;
8398 if (cur->type == XML_ATTRIBUTE_NODE) {
8400 } else if (cur->type == XML_NAMESPACE_DECL) {
8401 xmlNsPtr ns = (xmlNsPtr) cur;
8403 if ((ns->next == NULL) ||
8404 (ns->next->type == XML_NAMESPACE_DECL))
8406 cur = (xmlNodePtr) ns->next;
8408 ctxt->ancestor = cur->parent;
8410 if (cur->type == XML_NAMESPACE_DECL)
8412 if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
8414 while (cur->prev == NULL) {
8418 if (cur == ctxt->context->doc->children)
8420 if (cur != ctxt->ancestor)
8422 ctxt->ancestor = cur->parent;
8425 while (cur->last != NULL)
8431 * xmlXPathNextNamespace:
8432 * @ctxt: the XPath Parser context
8433 * @cur: the current attribute in the traversal
8435 * Traversal function for the "namespace" direction
8436 * the namespace axis contains the namespace nodes of the context node;
8437 * the order of nodes on this axis is implementation-defined; the axis will
8438 * be empty unless the context node is an element
8440 * We keep the XML namespace node at the end of the list.
8442 * Returns the next element following that axis
8445 xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8446 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8447 if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
8449 if (ctxt->context->tmpNsList != NULL)
8450 xmlFree(ctxt->context->tmpNsList);
8451 ctxt->context->tmpNsList =
8452 xmlGetNsList(ctxt->context->doc, ctxt->context->node);
8453 ctxt->context->tmpNsNr = 0;
8454 if (ctxt->context->tmpNsList != NULL) {
8455 while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
8456 ctxt->context->tmpNsNr++;
8459 return((xmlNodePtr) xmlXPathXMLNamespace);
8461 if (ctxt->context->tmpNsNr > 0) {
8462 return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
8464 if (ctxt->context->tmpNsList != NULL)
8465 xmlFree(ctxt->context->tmpNsList);
8466 ctxt->context->tmpNsList = NULL;
8472 * xmlXPathNextAttribute:
8473 * @ctxt: the XPath Parser context
8474 * @cur: the current attribute in the traversal
8476 * Traversal function for the "attribute" direction
8477 * TODO: support DTD inherited default attributes
8479 * Returns the next element following that axis
8482 xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
8483 if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
8484 if (ctxt->context->node == NULL)
8486 if (ctxt->context->node->type != XML_ELEMENT_NODE)
8489 if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
8491 return((xmlNodePtr)ctxt->context->node->properties);
8493 return((xmlNodePtr)cur->next);
8496 /************************************************************************
8498 * NodeTest Functions *
8500 ************************************************************************/
8502 #define IS_FUNCTION 200
8505 /************************************************************************
8507 * Implicit tree core function library *
8509 ************************************************************************/
8513 * @ctxt: the XPath Parser context
8515 * Initialize the context to the root of the document
8518 xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
8519 if ((ctxt == NULL) || (ctxt->context == NULL))
8521 ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
8522 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8523 ctxt->context->node));
8526 /************************************************************************
8528 * The explicit core function library *
8529 *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib *
8531 ************************************************************************/
8535 * xmlXPathLastFunction:
8536 * @ctxt: the XPath Parser context
8537 * @nargs: the number of arguments
8539 * Implement the last() XPath function
8541 * The last function returns the number of nodes in the context node list.
8544 xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8546 if (ctxt->context->contextSize >= 0) {
8548 xmlXPathCacheNewFloat(ctxt->context,
8549 (double) ctxt->context->contextSize));
8551 xmlGenericError(xmlGenericErrorContext,
8552 "last() : %d\n", ctxt->context->contextSize);
8555 XP_ERROR(XPATH_INVALID_CTXT_SIZE);
8560 * xmlXPathPositionFunction:
8561 * @ctxt: the XPath Parser context
8562 * @nargs: the number of arguments
8564 * Implement the position() XPath function
8566 * The position function returns the position of the context node in the
8567 * context node list. The first position is 1, and so the last position
8568 * will be equal to last().
8571 xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8573 if (ctxt->context->proximityPosition >= 0) {
8575 xmlXPathCacheNewFloat(ctxt->context,
8576 (double) ctxt->context->proximityPosition));
8578 xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
8579 ctxt->context->proximityPosition);
8582 XP_ERROR(XPATH_INVALID_CTXT_POSITION);
8587 * xmlXPathCountFunction:
8588 * @ctxt: the XPath Parser context
8589 * @nargs: the number of arguments
8591 * Implement the count() XPath function
8592 * number count(node-set)
8595 xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8596 xmlXPathObjectPtr cur;
8599 if ((ctxt->value == NULL) ||
8600 ((ctxt->value->type != XPATH_NODESET) &&
8601 (ctxt->value->type != XPATH_XSLT_TREE)))
8602 XP_ERROR(XPATH_INVALID_TYPE);
8603 cur = valuePop(ctxt);
8605 if ((cur == NULL) || (cur->nodesetval == NULL))
8606 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8607 else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
8608 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
8609 (double) cur->nodesetval->nodeNr));
8611 if ((cur->nodesetval->nodeNr != 1) ||
8612 (cur->nodesetval->nodeTab == NULL)) {
8613 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
8618 tmp = cur->nodesetval->nodeTab[0];
8619 if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
8620 tmp = tmp->children;
8621 while (tmp != NULL) {
8626 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) i));
8629 xmlXPathReleaseObject(ctxt->context, cur);
8633 * xmlXPathGetElementsByIds:
8634 * @doc: the document
8635 * @ids: a whitespace separated list of IDs
8637 * Selects elements by their unique ID.
8639 * Returns a node-set of selected elements.
8641 static xmlNodeSetPtr
8642 xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
8644 const xmlChar *cur = ids;
8647 xmlNodePtr elem = NULL;
8649 if (ids == NULL) return(NULL);
8651 ret = xmlXPathNodeSetCreate(NULL);
8655 while (IS_BLANK_CH(*cur)) cur++;
8657 while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
8660 ID = xmlStrndup(ids, cur - ids);
8663 * We used to check the fact that the value passed
8664 * was an NCName, but this generated much troubles for
8665 * me and Aleksey Sanin, people blatantly violated that
8666 * constaint, like Visa3D spec.
8667 * if (xmlValidateNCName(ID, 1) == 0)
8669 attr = xmlGetID(doc, ID);
8671 if (attr->type == XML_ATTRIBUTE_NODE)
8672 elem = attr->parent;
8673 else if (attr->type == XML_ELEMENT_NODE)
8674 elem = (xmlNodePtr) attr;
8678 xmlXPathNodeSetAdd(ret, elem);
8683 while (IS_BLANK_CH(*cur)) cur++;
8690 * xmlXPathIdFunction:
8691 * @ctxt: the XPath Parser context
8692 * @nargs: the number of arguments
8694 * Implement the id() XPath function
8695 * node-set id(object)
8696 * The id function selects elements by their unique ID
8697 * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
8698 * then the result is the union of the result of applying id to the
8699 * string value of each of the nodes in the argument node-set. When the
8700 * argument to id is of any other type, the argument is converted to a
8701 * string as if by a call to the string function; the string is split
8702 * into a whitespace-separated list of tokens (whitespace is any sequence
8703 * of characters matching the production S); the result is a node-set
8704 * containing the elements in the same document as the context node that
8705 * have a unique ID equal to any of the tokens in the list.
8708 xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8711 xmlXPathObjectPtr obj;
8714 obj = valuePop(ctxt);
8715 if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8716 if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
8720 ret = xmlXPathNodeSetCreate(NULL);
8722 * FIXME -- in an out-of-memory condition this will behave badly.
8723 * The solution is not clear -- we already popped an item from
8724 * ctxt, so the object is in a corrupt state.
8727 if (obj->nodesetval != NULL) {
8728 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
8730 xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
8731 ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
8732 ret = xmlXPathNodeSetMerge(ret, ns);
8733 xmlXPathFreeNodeSet(ns);
8738 xmlXPathReleaseObject(ctxt->context, obj);
8739 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8742 obj = xmlXPathCacheConvertString(ctxt->context, obj);
8743 ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
8744 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
8745 xmlXPathReleaseObject(ctxt->context, obj);
8750 * xmlXPathLocalNameFunction:
8751 * @ctxt: the XPath Parser context
8752 * @nargs: the number of arguments
8754 * Implement the local-name() XPath function
8755 * string local-name(node-set?)
8756 * The local-name function returns a string containing the local part
8757 * of the name of the node in the argument node-set that is first in
8758 * document order. If the node-set is empty or the first node has no
8759 * name, an empty string is returned. If the argument is omitted it
8760 * defaults to the context node.
8763 xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8764 xmlXPathObjectPtr cur;
8766 if (ctxt == NULL) return;
8769 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8770 ctxt->context->node));
8775 if ((ctxt->value == NULL) ||
8776 ((ctxt->value->type != XPATH_NODESET) &&
8777 (ctxt->value->type != XPATH_XSLT_TREE)))
8778 XP_ERROR(XPATH_INVALID_TYPE);
8779 cur = valuePop(ctxt);
8781 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8782 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8784 int i = 0; /* Should be first in document order !!!!! */
8785 switch (cur->nodesetval->nodeTab[i]->type) {
8786 case XML_ELEMENT_NODE:
8787 case XML_ATTRIBUTE_NODE:
8789 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8790 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8793 xmlXPathCacheNewString(ctxt->context,
8794 cur->nodesetval->nodeTab[i]->name));
8796 case XML_NAMESPACE_DECL:
8797 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8798 ((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
8801 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8804 xmlXPathReleaseObject(ctxt->context, cur);
8808 * xmlXPathNamespaceURIFunction:
8809 * @ctxt: the XPath Parser context
8810 * @nargs: the number of arguments
8812 * Implement the namespace-uri() XPath function
8813 * string namespace-uri(node-set?)
8814 * The namespace-uri function returns a string containing the
8815 * namespace URI of the expanded name of the node in the argument
8816 * node-set that is first in document order. If the node-set is empty,
8817 * the first node has no name, or the expanded name has no namespace
8818 * URI, an empty string is returned. If the argument is omitted it
8819 * defaults to the context node.
8822 xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8823 xmlXPathObjectPtr cur;
8825 if (ctxt == NULL) return;
8828 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8829 ctxt->context->node));
8833 if ((ctxt->value == NULL) ||
8834 ((ctxt->value->type != XPATH_NODESET) &&
8835 (ctxt->value->type != XPATH_XSLT_TREE)))
8836 XP_ERROR(XPATH_INVALID_TYPE);
8837 cur = valuePop(ctxt);
8839 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8840 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8842 int i = 0; /* Should be first in document order !!!!! */
8843 switch (cur->nodesetval->nodeTab[i]->type) {
8844 case XML_ELEMENT_NODE:
8845 case XML_ATTRIBUTE_NODE:
8846 if (cur->nodesetval->nodeTab[i]->ns == NULL)
8847 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8849 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
8850 cur->nodesetval->nodeTab[i]->ns->href));
8853 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8856 xmlXPathReleaseObject(ctxt->context, cur);
8860 * xmlXPathNameFunction:
8861 * @ctxt: the XPath Parser context
8862 * @nargs: the number of arguments
8864 * Implement the name() XPath function
8865 * string name(node-set?)
8866 * The name function returns a string containing a QName representing
8867 * the name of the node in the argument node-set that is first in document
8868 * order. The QName must represent the name with respect to the namespace
8869 * declarations in effect on the node whose name is being represented.
8870 * Typically, this will be the form in which the name occurred in the XML
8871 * source. This need not be the case if there are namespace declarations
8872 * in effect on the node that associate multiple prefixes with the same
8873 * namespace. However, an implementation may include information about
8874 * the original prefix in its representation of nodes; in this case, an
8875 * implementation can ensure that the returned string is always the same
8876 * as the QName used in the XML source. If the argument it omitted it
8877 * defaults to the context node.
8878 * Libxml keep the original prefix so the "real qualified name" used is
8882 xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
8884 xmlXPathObjectPtr cur;
8887 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8888 ctxt->context->node));
8893 if ((ctxt->value == NULL) ||
8894 ((ctxt->value->type != XPATH_NODESET) &&
8895 (ctxt->value->type != XPATH_XSLT_TREE)))
8896 XP_ERROR(XPATH_INVALID_TYPE);
8897 cur = valuePop(ctxt);
8899 if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
8900 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
8902 int i = 0; /* Should be first in document order !!!!! */
8904 switch (cur->nodesetval->nodeTab[i]->type) {
8905 case XML_ELEMENT_NODE:
8906 case XML_ATTRIBUTE_NODE:
8907 if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
8909 xmlXPathCacheNewCString(ctxt->context, ""));
8910 else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
8911 (cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
8913 xmlXPathCacheNewString(ctxt->context,
8914 cur->nodesetval->nodeTab[i]->name));
8918 fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
8919 cur->nodesetval->nodeTab[i]->ns->prefix,
8921 if (fullname == cur->nodesetval->nodeTab[i]->name)
8922 fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
8923 if (fullname == NULL) {
8924 XP_ERROR(XPATH_MEMORY_ERROR);
8926 valuePush(ctxt, xmlXPathCacheWrapString(
8927 ctxt->context, fullname));
8931 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
8932 cur->nodesetval->nodeTab[i]));
8933 xmlXPathLocalNameFunction(ctxt, 1);
8936 xmlXPathReleaseObject(ctxt->context, cur);
8941 * xmlXPathStringFunction:
8942 * @ctxt: the XPath Parser context
8943 * @nargs: the number of arguments
8945 * Implement the string() XPath function
8946 * string string(object?)
8947 * The string function converts an object to a string as follows:
8948 * - A node-set is converted to a string by returning the value of
8949 * the node in the node-set that is first in document order.
8950 * If the node-set is empty, an empty string is returned.
8951 * - A number is converted to a string as follows
8952 * + NaN is converted to the string NaN
8953 * + positive zero is converted to the string 0
8954 * + negative zero is converted to the string 0
8955 * + positive infinity is converted to the string Infinity
8956 * + negative infinity is converted to the string -Infinity
8957 * + if the number is an integer, the number is represented in
8958 * decimal form as a Number with no decimal point and no leading
8959 * zeros, preceded by a minus sign (-) if the number is negative
8960 * + otherwise, the number is represented in decimal form as a
8961 * Number including a decimal point with at least one digit
8962 * before the decimal point and at least one digit after the
8963 * decimal point, preceded by a minus sign (-) if the number
8964 * is negative; there must be no leading zeros before the decimal
8965 * point apart possibly from the one required digit immediately
8966 * before the decimal point; beyond the one required digit
8967 * after the decimal point there must be as many, but only as
8968 * many, more digits as are needed to uniquely distinguish the
8969 * number from all other IEEE 754 numeric values.
8970 * - The boolean false value is converted to the string false.
8971 * The boolean true value is converted to the string true.
8973 * If the argument is omitted, it defaults to a node-set with the
8974 * context node as its only member.
8977 xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
8978 xmlXPathObjectPtr cur;
8980 if (ctxt == NULL) return;
8983 xmlXPathCacheWrapString(ctxt->context,
8984 xmlXPathCastNodeToString(ctxt->context->node)));
8989 cur = valuePop(ctxt);
8990 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
8991 valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
8995 * xmlXPathStringLengthFunction:
8996 * @ctxt: the XPath Parser context
8997 * @nargs: the number of arguments
8999 * Implement the string-length() XPath function
9000 * number string-length(string?)
9001 * The string-length returns the number of characters in the string
9002 * (see [3.6 Strings]). If the argument is omitted, it defaults to
9003 * the context node converted to a string, in other words the value
9004 * of the context node.
9007 xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9008 xmlXPathObjectPtr cur;
9011 if ((ctxt == NULL) || (ctxt->context == NULL))
9013 if (ctxt->context->node == NULL) {
9014 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
9018 content = xmlXPathCastNodeToString(ctxt->context->node);
9019 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9020 xmlUTF8Strlen(content)));
9027 CHECK_TYPE(XPATH_STRING);
9028 cur = valuePop(ctxt);
9029 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
9030 xmlUTF8Strlen(cur->stringval)));
9031 xmlXPathReleaseObject(ctxt->context, cur);
9035 * xmlXPathConcatFunction:
9036 * @ctxt: the XPath Parser context
9037 * @nargs: the number of arguments
9039 * Implement the concat() XPath function
9040 * string concat(string, string, string*)
9041 * The concat function returns the concatenation of its arguments.
9044 xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9045 xmlXPathObjectPtr cur, newobj;
9048 if (ctxt == NULL) return;
9054 cur = valuePop(ctxt);
9055 if ((cur == NULL) || (cur->type != XPATH_STRING)) {
9056 xmlXPathReleaseObject(ctxt->context, cur);
9063 newobj = valuePop(ctxt);
9064 if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
9065 xmlXPathReleaseObject(ctxt->context, newobj);
9066 xmlXPathReleaseObject(ctxt->context, cur);
9067 XP_ERROR(XPATH_INVALID_TYPE);
9069 tmp = xmlStrcat(newobj->stringval, cur->stringval);
9070 newobj->stringval = cur->stringval;
9071 cur->stringval = tmp;
9072 xmlXPathReleaseObject(ctxt->context, newobj);
9075 valuePush(ctxt, cur);
9079 * xmlXPathContainsFunction:
9080 * @ctxt: the XPath Parser context
9081 * @nargs: the number of arguments
9083 * Implement the contains() XPath function
9084 * boolean contains(string, string)
9085 * The contains function returns true if the first argument string
9086 * contains the second argument string, and otherwise returns false.
9089 xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9090 xmlXPathObjectPtr hay, needle;
9094 CHECK_TYPE(XPATH_STRING);
9095 needle = valuePop(ctxt);
9097 hay = valuePop(ctxt);
9099 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9100 xmlXPathReleaseObject(ctxt->context, hay);
9101 xmlXPathReleaseObject(ctxt->context, needle);
9102 XP_ERROR(XPATH_INVALID_TYPE);
9104 if (xmlStrstr(hay->stringval, needle->stringval))
9105 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9107 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9108 xmlXPathReleaseObject(ctxt->context, hay);
9109 xmlXPathReleaseObject(ctxt->context, needle);
9113 * xmlXPathStartsWithFunction:
9114 * @ctxt: the XPath Parser context
9115 * @nargs: the number of arguments
9117 * Implement the starts-with() XPath function
9118 * boolean starts-with(string, string)
9119 * The starts-with function returns true if the first argument string
9120 * starts with the second argument string, and otherwise returns false.
9123 xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9124 xmlXPathObjectPtr hay, needle;
9129 CHECK_TYPE(XPATH_STRING);
9130 needle = valuePop(ctxt);
9132 hay = valuePop(ctxt);
9134 if ((hay == NULL) || (hay->type != XPATH_STRING)) {
9135 xmlXPathReleaseObject(ctxt->context, hay);
9136 xmlXPathReleaseObject(ctxt->context, needle);
9137 XP_ERROR(XPATH_INVALID_TYPE);
9139 n = xmlStrlen(needle->stringval);
9140 if (xmlStrncmp(hay->stringval, needle->stringval, n))
9141 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9143 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9144 xmlXPathReleaseObject(ctxt->context, hay);
9145 xmlXPathReleaseObject(ctxt->context, needle);
9149 * xmlXPathSubstringFunction:
9150 * @ctxt: the XPath Parser context
9151 * @nargs: the number of arguments
9153 * Implement the substring() XPath function
9154 * string substring(string, number, number?)
9155 * The substring function returns the substring of the first argument
9156 * starting at the position specified in the second argument with
9157 * length specified in the third argument. For example,
9158 * substring("12345",2,3) returns "234". If the third argument is not
9159 * specified, it returns the substring starting at the position specified
9160 * in the second argument and continuing to the end of the string. For
9161 * example, substring("12345",2) returns "2345". More precisely, each
9162 * character in the string (see [3.6 Strings]) is considered to have a
9163 * numeric position: the position of the first character is 1, the position
9164 * of the second character is 2 and so on. The returned substring contains
9165 * those characters for which the position of the character is greater than
9166 * or equal to the second argument and, if the third argument is specified,
9167 * less than the sum of the second and third arguments; the comparisons
9168 * and addition used for the above follow the standard IEEE 754 rules. Thus:
9169 * - substring("12345", 1.5, 2.6) returns "234"
9170 * - substring("12345", 0, 3) returns "12"
9171 * - substring("12345", 0 div 0, 3) returns ""
9172 * - substring("12345", 1, 0 div 0) returns ""
9173 * - substring("12345", -42, 1 div 0) returns "12345"
9174 * - substring("12345", -1 div 0, 1 div 0) returns ""
9177 xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9178 xmlXPathObjectPtr str, start, len;
9190 * take care of possible last (position) argument
9194 CHECK_TYPE(XPATH_NUMBER);
9195 len = valuePop(ctxt);
9197 xmlXPathReleaseObject(ctxt->context, len);
9201 CHECK_TYPE(XPATH_NUMBER);
9202 start = valuePop(ctxt);
9203 in = start->floatval;
9204 xmlXPathReleaseObject(ctxt->context, start);
9206 CHECK_TYPE(XPATH_STRING);
9207 str = valuePop(ctxt);
9208 m = xmlUTF8Strlen((const unsigned char *)str->stringval);
9211 * If last pos not present, calculate last position
9219 /* Need to check for the special cases where either
9220 * the index is NaN, the length is NaN, or both
9221 * arguments are infinity (relying on Inf + -Inf = NaN)
9223 if (!xmlXPathIsInf(in) && !xmlXPathIsNaN(in + le)) {
9225 * To meet the requirements of the spec, the arguments
9226 * must be converted to integer format before
9227 * initial index calculations are done
9229 * First we go to integer form, rounding up
9230 * and checking for special cases
9233 if (((double)i)+0.5 <= in) i++;
9235 if (xmlXPathIsInf(le) == 1) {
9240 else if (xmlXPathIsInf(le) == -1 || le < 0.0)
9244 if (((double)l)+0.5 <= le) l++;
9247 /* Now we normalize inidices */
9255 /* number of chars to copy */
9258 ret = xmlUTF8Strsub(str->stringval, i, l);
9264 valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
9266 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
9269 xmlXPathReleaseObject(ctxt->context, str);
9273 * xmlXPathSubstringBeforeFunction:
9274 * @ctxt: the XPath Parser context
9275 * @nargs: the number of arguments
9277 * Implement the substring-before() XPath function
9278 * string substring-before(string, string)
9279 * The substring-before function returns the substring of the first
9280 * argument string that precedes the first occurrence of the second
9281 * argument string in the first argument string, or the empty string
9282 * if the first argument string does not contain the second argument
9283 * string. For example, substring-before("1999/04/01","/") returns 1999.
9286 xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9287 xmlXPathObjectPtr str;
9288 xmlXPathObjectPtr find;
9290 const xmlChar *point;
9295 find = valuePop(ctxt);
9297 str = valuePop(ctxt);
9299 target = xmlBufCreate();
9301 point = xmlStrstr(str->stringval, find->stringval);
9303 offset = (int)(point - str->stringval);
9304 xmlBufAdd(target, str->stringval, offset);
9306 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9307 xmlBufContent(target)));
9310 xmlXPathReleaseObject(ctxt->context, str);
9311 xmlXPathReleaseObject(ctxt->context, find);
9315 * xmlXPathSubstringAfterFunction:
9316 * @ctxt: the XPath Parser context
9317 * @nargs: the number of arguments
9319 * Implement the substring-after() XPath function
9320 * string substring-after(string, string)
9321 * The substring-after function returns the substring of the first
9322 * argument string that follows the first occurrence of the second
9323 * argument string in the first argument string, or the empty stringi
9324 * if the first argument string does not contain the second argument
9325 * string. For example, substring-after("1999/04/01","/") returns 04/01,
9326 * and substring-after("1999/04/01","19") returns 99/04/01.
9329 xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9330 xmlXPathObjectPtr str;
9331 xmlXPathObjectPtr find;
9333 const xmlChar *point;
9338 find = valuePop(ctxt);
9340 str = valuePop(ctxt);
9342 target = xmlBufCreate();
9344 point = xmlStrstr(str->stringval, find->stringval);
9346 offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
9347 xmlBufAdd(target, &str->stringval[offset],
9348 xmlStrlen(str->stringval) - offset);
9350 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9351 xmlBufContent(target)));
9354 xmlXPathReleaseObject(ctxt->context, str);
9355 xmlXPathReleaseObject(ctxt->context, find);
9359 * xmlXPathNormalizeFunction:
9360 * @ctxt: the XPath Parser context
9361 * @nargs: the number of arguments
9363 * Implement the normalize-space() XPath function
9364 * string normalize-space(string?)
9365 * The normalize-space function returns the argument string with white
9366 * space normalized by stripping leading and trailing whitespace
9367 * and replacing sequences of whitespace characters by a single
9368 * space. Whitespace characters are the same allowed by the S production
9369 * in XML. If the argument is omitted, it defaults to the context
9370 * node converted to a string, in other words the value of the context node.
9373 xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9374 xmlXPathObjectPtr obj = NULL;
9375 xmlChar *source = NULL;
9379 if (ctxt == NULL) return;
9381 /* Use current context node */
9383 xmlXPathCacheWrapString(ctxt->context,
9384 xmlXPathCastNodeToString(ctxt->context->node)));
9390 CHECK_TYPE(XPATH_STRING);
9391 obj = valuePop(ctxt);
9392 source = obj->stringval;
9394 target = xmlBufCreate();
9395 if (target && source) {
9397 /* Skip leading whitespaces */
9398 while (IS_BLANK_CH(*source))
9401 /* Collapse intermediate whitespaces, and skip trailing whitespaces */
9404 if (IS_BLANK_CH(*source)) {
9408 xmlBufAdd(target, &blank, 1);
9411 xmlBufAdd(target, source, 1);
9415 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9416 xmlBufContent(target)));
9419 xmlXPathReleaseObject(ctxt->context, obj);
9423 * xmlXPathTranslateFunction:
9424 * @ctxt: the XPath Parser context
9425 * @nargs: the number of arguments
9427 * Implement the translate() XPath function
9428 * string translate(string, string, string)
9429 * The translate function returns the first argument string with
9430 * occurrences of characters in the second argument string replaced
9431 * by the character at the corresponding position in the third argument
9432 * string. For example, translate("bar","abc","ABC") returns the string
9433 * BAr. If there is a character in the second argument string with no
9434 * character at a corresponding position in the third argument string
9435 * (because the second argument string is longer than the third argument
9436 * string), then occurrences of that character in the first argument
9437 * string are removed. For example, translate("--aaa--","abc-","ABC")
9438 * returns "AAA". If a character occurs more than once in second
9439 * argument string, then the first occurrence determines the replacement
9440 * character. If the third argument string is longer than the second
9441 * argument string, then excess characters are ignored.
9444 xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9445 xmlXPathObjectPtr str;
9446 xmlXPathObjectPtr from;
9447 xmlXPathObjectPtr to;
9451 const xmlChar *point;
9457 to = valuePop(ctxt);
9459 from = valuePop(ctxt);
9461 str = valuePop(ctxt);
9463 target = xmlBufCreate();
9465 max = xmlUTF8Strlen(to->stringval);
9466 for (cptr = str->stringval; (ch=*cptr); ) {
9467 offset = xmlUTF8Strloc(from->stringval, cptr);
9470 point = xmlUTF8Strpos(to->stringval, offset);
9472 xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
9475 xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
9477 /* Step to next character in input */
9480 /* if not simple ascii, verify proper format */
9481 if ( (ch & 0xc0) != 0xc0 ) {
9482 xmlGenericError(xmlGenericErrorContext,
9483 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9484 /* not asserting an XPath error is probably better */
9487 /* then skip over remaining bytes for this char */
9488 while ( (ch <<= 1) & 0x80 )
9489 if ( (*cptr++ & 0xc0) != 0x80 ) {
9490 xmlGenericError(xmlGenericErrorContext,
9491 "xmlXPathTranslateFunction: Invalid UTF8 string\n");
9492 /* not asserting an XPath error is probably better */
9495 if (ch & 0x80) /* must have had error encountered */
9500 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
9501 xmlBufContent(target)));
9503 xmlXPathReleaseObject(ctxt->context, str);
9504 xmlXPathReleaseObject(ctxt->context, from);
9505 xmlXPathReleaseObject(ctxt->context, to);
9509 * xmlXPathBooleanFunction:
9510 * @ctxt: the XPath Parser context
9511 * @nargs: the number of arguments
9513 * Implement the boolean() XPath function
9514 * boolean boolean(object)
9515 * The boolean function converts its argument to a boolean as follows:
9516 * - a number is true if and only if it is neither positive or
9517 * negative zero nor NaN
9518 * - a node-set is true if and only if it is non-empty
9519 * - a string is true if and only if its length is non-zero
9522 xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9523 xmlXPathObjectPtr cur;
9526 cur = valuePop(ctxt);
9527 if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
9528 cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
9529 valuePush(ctxt, cur);
9533 * xmlXPathNotFunction:
9534 * @ctxt: the XPath Parser context
9535 * @nargs: the number of arguments
9537 * Implement the not() XPath function
9538 * boolean not(boolean)
9539 * The not function returns true if its argument is false,
9540 * and false otherwise.
9543 xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9546 CHECK_TYPE(XPATH_BOOLEAN);
9547 ctxt->value->boolval = ! ctxt->value->boolval;
9551 * xmlXPathTrueFunction:
9552 * @ctxt: the XPath Parser context
9553 * @nargs: the number of arguments
9555 * Implement the true() XPath function
9559 xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9561 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
9565 * xmlXPathFalseFunction:
9566 * @ctxt: the XPath Parser context
9567 * @nargs: the number of arguments
9569 * Implement the false() XPath function
9573 xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9575 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
9579 * xmlXPathLangFunction:
9580 * @ctxt: the XPath Parser context
9581 * @nargs: the number of arguments
9583 * Implement the lang() XPath function
9584 * boolean lang(string)
9585 * The lang function returns true or false depending on whether the
9586 * language of the context node as specified by xml:lang attributes
9587 * is the same as or is a sublanguage of the language specified by
9588 * the argument string. The language of the context node is determined
9589 * by the value of the xml:lang attribute on the context node, or, if
9590 * the context node has no xml:lang attribute, by the value of the
9591 * xml:lang attribute on the nearest ancestor of the context node that
9592 * has an xml:lang attribute. If there is no such attribute, then lang
9593 * returns false. If there is such an attribute, then lang returns
9594 * true if the attribute value is equal to the argument ignoring case,
9595 * or if there is some suffix starting with - such that the attribute
9596 * value is equal to the argument ignoring that suffix of the attribute
9597 * value and ignoring case.
9600 xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9601 xmlXPathObjectPtr val = NULL;
9602 const xmlChar *theLang = NULL;
9603 const xmlChar *lang;
9609 CHECK_TYPE(XPATH_STRING);
9610 val = valuePop(ctxt);
9611 lang = val->stringval;
9612 theLang = xmlNodeGetLang(ctxt->context->node);
9613 if ((theLang != NULL) && (lang != NULL)) {
9614 for (i = 0;lang[i] != 0;i++)
9615 if (toupper(lang[i]) != toupper(theLang[i]))
9617 if ((theLang[i] == 0) || (theLang[i] == '-'))
9621 if (theLang != NULL)
9622 xmlFree((void *)theLang);
9624 xmlXPathReleaseObject(ctxt->context, val);
9625 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
9629 * xmlXPathNumberFunction:
9630 * @ctxt: the XPath Parser context
9631 * @nargs: the number of arguments
9633 * Implement the number() XPath function
9634 * number number(object?)
9637 xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9638 xmlXPathObjectPtr cur;
9641 if (ctxt == NULL) return;
9643 if (ctxt->context->node == NULL) {
9644 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
9646 xmlChar* content = xmlNodeGetContent(ctxt->context->node);
9648 res = xmlXPathStringEvalNumber(content);
9649 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9656 cur = valuePop(ctxt);
9657 valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
9661 * xmlXPathSumFunction:
9662 * @ctxt: the XPath Parser context
9663 * @nargs: the number of arguments
9665 * Implement the sum() XPath function
9666 * number sum(node-set)
9667 * The sum function returns the sum of the values of the nodes in
9668 * the argument node-set.
9671 xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9672 xmlXPathObjectPtr cur;
9677 if ((ctxt->value == NULL) ||
9678 ((ctxt->value->type != XPATH_NODESET) &&
9679 (ctxt->value->type != XPATH_XSLT_TREE)))
9680 XP_ERROR(XPATH_INVALID_TYPE);
9681 cur = valuePop(ctxt);
9683 if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
9684 for (i = 0; i < cur->nodesetval->nodeNr; i++) {
9685 res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
9688 valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
9689 xmlXPathReleaseObject(ctxt->context, cur);
9693 * xmlXPathFloorFunction:
9694 * @ctxt: the XPath Parser context
9695 * @nargs: the number of arguments
9697 * Implement the floor() XPath function
9698 * number floor(number)
9699 * The floor function returns the largest (closest to positive infinity)
9700 * number that is not greater than the argument and that is an integer.
9703 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9706 CHECK_TYPE(XPATH_NUMBER);
9708 ctxt->value->floatval = floor(ctxt->value->floatval);
9712 * xmlXPathCeilingFunction:
9713 * @ctxt: the XPath Parser context
9714 * @nargs: the number of arguments
9716 * Implement the ceiling() XPath function
9717 * number ceiling(number)
9718 * The ceiling function returns the smallest (closest to negative infinity)
9719 * number that is not less than the argument and that is an integer.
9722 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9725 CHECK_TYPE(XPATH_NUMBER);
9727 ctxt->value->floatval = ceil(ctxt->value->floatval);
9731 * xmlXPathRoundFunction:
9732 * @ctxt: the XPath Parser context
9733 * @nargs: the number of arguments
9735 * Implement the round() XPath function
9736 * number round(number)
9737 * The round function returns the number that is closest to the
9738 * argument and that is an integer. If there are two such numbers,
9739 * then the one that is closest to positive infinity is returned.
9742 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
9747 CHECK_TYPE(XPATH_NUMBER);
9749 f = ctxt->value->floatval;
9751 /* Test for zero to keep negative zero unchanged. */
9752 if ((xmlXPathIsNaN(f)) || (f == 0.0))
9755 if ((f >= -0.5) && (f < 0.0)) {
9756 /* Negative zero. */
9757 ctxt->value->floatval = xmlXPathNZERO;
9760 double rounded = floor(f);
9761 if (f - rounded >= 0.5)
9763 ctxt->value->floatval = rounded;
9767 /************************************************************************
9771 ************************************************************************/
9774 * a few forward declarations since we use a recursive call based
9777 static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
9778 static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
9779 static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
9780 static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
9781 static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
9785 * xmlXPathCurrentChar:
9786 * @ctxt: the XPath parser context
9787 * @cur: pointer to the beginning of the char
9788 * @len: pointer to the length of the char read
9790 * The current char value, if using UTF-8 this may actually span multiple
9791 * bytes in the input buffer.
9793 * Returns the current char value and its length
9797 xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
9807 * We are supposed to handle UTF8, check it's valid
9808 * From rfc2044: encoding of the Unicode values on UTF-8:
9810 * UCS-4 range (hex.) UTF-8 octet sequence (binary)
9811 * 0000 0000-0000 007F 0xxxxxxx
9812 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
9813 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
9815 * Check for the 0x110000 limit too
9819 if ((cur[1] & 0xc0) != 0x80)
9820 goto encoding_error;
9821 if ((c & 0xe0) == 0xe0) {
9823 if ((cur[2] & 0xc0) != 0x80)
9824 goto encoding_error;
9825 if ((c & 0xf0) == 0xf0) {
9826 if (((c & 0xf8) != 0xf0) ||
9827 ((cur[3] & 0xc0) != 0x80))
9828 goto encoding_error;
9831 val = (cur[0] & 0x7) << 18;
9832 val |= (cur[1] & 0x3f) << 12;
9833 val |= (cur[2] & 0x3f) << 6;
9834 val |= cur[3] & 0x3f;
9838 val = (cur[0] & 0xf) << 12;
9839 val |= (cur[1] & 0x3f) << 6;
9840 val |= cur[2] & 0x3f;
9845 val = (cur[0] & 0x1f) << 6;
9846 val |= cur[1] & 0x3f;
9848 if (!IS_CHAR(val)) {
9849 XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
9859 * If we detect an UTF8 error that probably means that the
9860 * input encoding didn't get properly advertised in the
9861 * declaration header. Report the error and switch the encoding
9862 * to ISO-Latin-1 (if you don't like this policy, just declare the
9866 XP_ERROR0(XPATH_ENCODING_ERROR);
9870 * xmlXPathParseNCName:
9871 * @ctxt: the XPath Parser context
9873 * parse an XML namespace non qualified name.
9875 * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
9877 * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
9878 * CombiningChar | Extender
9880 * Returns the namespace name or NULL
9884 xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
9889 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9891 * Accelerator for simple ASCII names
9894 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9895 ((*in >= 0x41) && (*in <= 0x5A)) ||
9898 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9899 ((*in >= 0x41) && (*in <= 0x5A)) ||
9900 ((*in >= 0x30) && (*in <= 0x39)) ||
9901 (*in == '_') || (*in == '.') ||
9904 if ((*in == ' ') || (*in == '>') || (*in == '/') ||
9905 (*in == '[') || (*in == ']') || (*in == ':') ||
9906 (*in == '@') || (*in == '*')) {
9907 count = in - ctxt->cur;
9910 ret = xmlStrndup(ctxt->cur, count);
9915 return(xmlXPathParseNameComplex(ctxt, 0));
9920 * xmlXPathParseQName:
9921 * @ctxt: the XPath Parser context
9922 * @prefix: a xmlChar **
9924 * parse an XML qualified name
9926 * [NS 5] QName ::= (Prefix ':')? LocalPart
9928 * [NS 6] Prefix ::= NCName
9930 * [NS 7] LocalPart ::= NCName
9932 * Returns the function returns the local part, and prefix is updated
9933 * to get the Prefix if any.
9937 xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
9938 xmlChar *ret = NULL;
9941 ret = xmlXPathParseNCName(ctxt);
9942 if (ret && CUR == ':') {
9945 ret = xmlXPathParseNCName(ctxt);
9951 * xmlXPathParseName:
9952 * @ctxt: the XPath Parser context
9956 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
9957 * CombiningChar | Extender
9959 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
9961 * Returns the namespace name or NULL
9965 xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
9970 if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
9972 * Accelerator for simple ASCII names
9975 if (((*in >= 0x61) && (*in <= 0x7A)) ||
9976 ((*in >= 0x41) && (*in <= 0x5A)) ||
9977 (*in == '_') || (*in == ':')) {
9979 while (((*in >= 0x61) && (*in <= 0x7A)) ||
9980 ((*in >= 0x41) && (*in <= 0x5A)) ||
9981 ((*in >= 0x30) && (*in <= 0x39)) ||
9982 (*in == '_') || (*in == '-') ||
9983 (*in == ':') || (*in == '.'))
9985 if ((*in > 0) && (*in < 0x80)) {
9986 count = in - ctxt->cur;
9987 if (count > XML_MAX_NAME_LENGTH) {
9989 XP_ERRORNULL(XPATH_EXPR_ERROR);
9991 ret = xmlStrndup(ctxt->cur, count);
9996 return(xmlXPathParseNameComplex(ctxt, 1));
10000 xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
10001 xmlChar buf[XML_MAX_NAMELEN + 5];
10006 * Handler for more complex cases
10009 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10010 (c == '[') || (c == ']') || (c == '@') || /* accelerators */
10011 (c == '*') || /* accelerators */
10012 (!IS_LETTER(c) && (c != '_') &&
10013 ((!qualified) || (c != ':')))) {
10017 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10018 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10019 (c == '.') || (c == '-') ||
10020 (c == '_') || ((qualified) && (c == ':')) ||
10021 (IS_COMBINING(c)) ||
10022 (IS_EXTENDER(c)))) {
10023 COPY_BUF(l,buf,len,c);
10026 if (len >= XML_MAX_NAMELEN) {
10028 * Okay someone managed to make a huge name, so he's ready to pay
10029 * for the processing speed.
10034 if (len > XML_MAX_NAME_LENGTH) {
10035 XP_ERRORNULL(XPATH_EXPR_ERROR);
10037 buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
10038 if (buffer == NULL) {
10039 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10041 memcpy(buffer, buf, len);
10042 while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
10043 (c == '.') || (c == '-') ||
10044 (c == '_') || ((qualified) && (c == ':')) ||
10045 (IS_COMBINING(c)) ||
10046 (IS_EXTENDER(c))) {
10047 if (len + 10 > max) {
10048 if (max > XML_MAX_NAME_LENGTH) {
10049 XP_ERRORNULL(XPATH_EXPR_ERROR);
10052 buffer = (xmlChar *) xmlRealloc(buffer,
10053 max * sizeof(xmlChar));
10054 if (buffer == NULL) {
10055 XP_ERRORNULL(XPATH_MEMORY_ERROR);
10058 COPY_BUF(l,buffer,len,c);
10068 return(xmlStrndup(buf, len));
10071 #define MAX_FRAC 20
10074 * xmlXPathStringEvalNumber:
10075 * @str: A string to scan
10077 * [30a] Float ::= Number ('e' Digits?)?
10079 * [30] Number ::= Digits ('.' Digits?)?
10081 * [31] Digits ::= [0-9]+
10083 * Compile a Number in the string
10084 * In complement of the Number expression, this function also handles
10085 * negative values : '-' Number.
10087 * Returns the double value.
10090 xmlXPathStringEvalNumber(const xmlChar *str) {
10091 const xmlChar *cur = str;
10096 int is_exponent_negative = 0;
10098 unsigned long tmp = 0;
10101 if (cur == NULL) return(0);
10102 while (IS_BLANK_CH(*cur)) cur++;
10103 if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
10104 return(xmlXPathNAN);
10113 * tmp/temp is a workaround against a gcc compiler bug
10114 * http://veillard.com/gcc.bug
10117 while ((*cur >= '0') && (*cur <= '9')) {
10119 tmp = (*cur - '0');
10122 temp = (double) tmp;
10127 while ((*cur >= '0') && (*cur <= '9')) {
10128 ret = ret * 10 + (*cur - '0');
10135 int v, frac = 0, max;
10136 double fraction = 0;
10139 if (((*cur < '0') || (*cur > '9')) && (!ok)) {
10140 return(xmlXPathNAN);
10142 while (*cur == '0') {
10146 max = frac + MAX_FRAC;
10147 while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
10149 fraction = fraction * 10 + v;
10153 fraction /= pow(10.0, frac);
10154 ret = ret + fraction;
10155 while ((*cur >= '0') && (*cur <= '9'))
10158 if ((*cur == 'e') || (*cur == 'E')) {
10161 is_exponent_negative = 1;
10163 } else if (*cur == '+') {
10166 while ((*cur >= '0') && (*cur <= '9')) {
10167 if (exponent < 1000000)
10168 exponent = exponent * 10 + (*cur - '0');
10172 while (IS_BLANK_CH(*cur)) cur++;
10173 if (*cur != 0) return(xmlXPathNAN);
10174 if (isneg) ret = -ret;
10175 if (is_exponent_negative) exponent = -exponent;
10176 ret *= pow(10.0, (double)exponent);
10181 * xmlXPathCompNumber:
10182 * @ctxt: the XPath Parser context
10184 * [30] Number ::= Digits ('.' Digits?)?
10186 * [31] Digits ::= [0-9]+
10188 * Compile a Number, then push it on the stack
10192 xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
10197 int is_exponent_negative = 0;
10199 unsigned long tmp = 0;
10204 if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
10205 XP_ERROR(XPATH_NUMBER_ERROR);
10209 * tmp/temp is a workaround against a gcc compiler bug
10210 * http://veillard.com/gcc.bug
10213 while ((CUR >= '0') && (CUR <= '9')) {
10218 temp = (double) tmp;
10223 while ((CUR >= '0') && (CUR <= '9')) {
10224 ret = ret * 10 + (CUR - '0');
10230 int v, frac = 0, max;
10231 double fraction = 0;
10234 if (((CUR < '0') || (CUR > '9')) && (!ok)) {
10235 XP_ERROR(XPATH_NUMBER_ERROR);
10237 while (CUR == '0') {
10241 max = frac + MAX_FRAC;
10242 while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
10244 fraction = fraction * 10 + v;
10248 fraction /= pow(10.0, frac);
10249 ret = ret + fraction;
10250 while ((CUR >= '0') && (CUR <= '9'))
10253 if ((CUR == 'e') || (CUR == 'E')) {
10256 is_exponent_negative = 1;
10258 } else if (CUR == '+') {
10261 while ((CUR >= '0') && (CUR <= '9')) {
10262 if (exponent < 1000000)
10263 exponent = exponent * 10 + (CUR - '0');
10266 if (is_exponent_negative)
10267 exponent = -exponent;
10268 ret *= pow(10.0, (double) exponent);
10270 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0,
10271 xmlXPathCacheNewFloat(ctxt->context, ret), NULL);
10275 * xmlXPathParseLiteral:
10276 * @ctxt: the XPath Parser context
10280 * [29] Literal ::= '"' [^"]* '"'
10283 * Returns the value found or NULL in case of error
10286 xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
10288 xmlChar *ret = NULL;
10293 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10295 if (!IS_CHAR_CH(CUR)) {
10296 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10298 ret = xmlStrndup(q, CUR_PTR - q);
10301 } else if (CUR == '\'') {
10304 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10306 if (!IS_CHAR_CH(CUR)) {
10307 XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
10309 ret = xmlStrndup(q, CUR_PTR - q);
10313 XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
10319 * xmlXPathCompLiteral:
10320 * @ctxt: the XPath Parser context
10322 * Parse a Literal and push it on the stack.
10324 * [29] Literal ::= '"' [^"]* '"'
10327 * TODO: xmlXPathCompLiteral memory allocation could be improved.
10330 xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
10332 xmlChar *ret = NULL;
10337 while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
10339 if (!IS_CHAR_CH(CUR)) {
10340 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10342 ret = xmlStrndup(q, CUR_PTR - q);
10345 } else if (CUR == '\'') {
10348 while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
10350 if (!IS_CHAR_CH(CUR)) {
10351 XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
10353 ret = xmlStrndup(q, CUR_PTR - q);
10357 XP_ERROR(XPATH_START_LITERAL_ERROR);
10359 if (ret == NULL) return;
10360 PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0,
10361 xmlXPathCacheNewString(ctxt->context, ret), NULL);
10366 * xmlXPathCompVariableReference:
10367 * @ctxt: the XPath Parser context
10369 * Parse a VariableReference, evaluate it and push it on the stack.
10371 * The variable bindings consist of a mapping from variable names
10372 * to variable values. The value of a variable is an object, which can be
10373 * of any of the types that are possible for the value of an expression,
10374 * and may also be of additional types not specified here.
10376 * Early evaluation is possible since:
10377 * The variable bindings [...] used to evaluate a subexpression are
10378 * always the same as those used to evaluate the containing expression.
10380 * [36] VariableReference ::= '$' QName
10383 xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
10389 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10392 name = xmlXPathParseQName(ctxt, &prefix);
10393 if (name == NULL) {
10395 XP_ERROR(XPATH_VARIABLE_REF_ERROR);
10397 ctxt->comp->last = -1;
10398 PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0,
10401 if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
10402 XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
10407 * xmlXPathIsNodeType:
10408 * @name: a name string
10410 * Is the name given a NodeType one.
10412 * [38] NodeType ::= 'comment'
10414 * | 'processing-instruction'
10417 * Returns 1 if true 0 otherwise
10420 xmlXPathIsNodeType(const xmlChar *name) {
10424 if (xmlStrEqual(name, BAD_CAST "node"))
10426 if (xmlStrEqual(name, BAD_CAST "text"))
10428 if (xmlStrEqual(name, BAD_CAST "comment"))
10430 if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
10436 * xmlXPathCompFunctionCall:
10437 * @ctxt: the XPath Parser context
10439 * [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument)*)? ')'
10440 * [17] Argument ::= Expr
10442 * Compile a function call, the evaluation of all arguments are
10443 * pushed on the stack
10446 xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
10452 name = xmlXPathParseQName(ctxt, &prefix);
10453 if (name == NULL) {
10455 XP_ERROR(XPATH_EXPR_ERROR);
10459 if (prefix == NULL)
10460 xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
10463 xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
10470 XP_ERROR(XPATH_EXPR_ERROR);
10476 * Optimization for count(): we don't need the node-set to be sorted.
10478 if ((prefix == NULL) && (name[0] == 'c') &&
10479 xmlStrEqual(name, BAD_CAST "count"))
10483 ctxt->comp->last = -1;
10486 int op1 = ctxt->comp->last;
10487 ctxt->comp->last = -1;
10488 xmlXPathCompileExpr(ctxt, sort);
10489 if (ctxt->error != XPATH_EXPRESSION_OK) {
10494 PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
10496 if (CUR == ')') break;
10500 XP_ERROR(XPATH_EXPR_ERROR);
10506 PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0,
10513 * xmlXPathCompPrimaryExpr:
10514 * @ctxt: the XPath Parser context
10516 * [15] PrimaryExpr ::= VariableReference
10522 * Compile a primary expression.
10525 xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
10527 if (CUR == '$') xmlXPathCompVariableReference(ctxt);
10528 else if (CUR == '(') {
10531 xmlXPathCompileExpr(ctxt, 1);
10534 XP_ERROR(XPATH_EXPR_ERROR);
10538 } else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10539 xmlXPathCompNumber(ctxt);
10540 } else if ((CUR == '\'') || (CUR == '"')) {
10541 xmlXPathCompLiteral(ctxt);
10543 xmlXPathCompFunctionCall(ctxt);
10549 * xmlXPathCompFilterExpr:
10550 * @ctxt: the XPath Parser context
10552 * [20] FilterExpr ::= PrimaryExpr
10553 * | FilterExpr Predicate
10555 * Compile a filter expression.
10556 * Square brackets are used to filter expressions in the same way that
10557 * they are used in location paths. It is an error if the expression to
10558 * be filtered does not evaluate to a node-set. The context node list
10559 * used for evaluating the expression in square brackets is the node-set
10560 * to be filtered listed in document order.
10564 xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
10565 xmlXPathCompPrimaryExpr(ctxt);
10569 while (CUR == '[') {
10570 xmlXPathCompPredicate(ctxt, 1);
10578 * xmlXPathScanName:
10579 * @ctxt: the XPath Parser context
10581 * Trickery: parse an XML name but without consuming the input flow
10582 * Needed to avoid insanity in the parser state.
10584 * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
10585 * CombiningChar | Extender
10587 * [5] Name ::= (Letter | '_' | ':') (NameChar)*
10589 * [6] Names ::= Name (S Name)*
10591 * Returns the Name parsed or NULL
10595 xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
10598 const xmlChar *cur;
10604 if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
10605 (!IS_LETTER(c) && (c != '_') &&
10610 while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
10611 ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
10612 (c == '.') || (c == '-') ||
10613 (c == '_') || (c == ':') ||
10614 (IS_COMBINING(c)) ||
10615 (IS_EXTENDER(c)))) {
10620 ret = xmlStrndup(cur, ctxt->cur - cur);
10626 * xmlXPathCompPathExpr:
10627 * @ctxt: the XPath Parser context
10629 * [19] PathExpr ::= LocationPath
10631 * | FilterExpr '/' RelativeLocationPath
10632 * | FilterExpr '//' RelativeLocationPath
10634 * Compile a path expression.
10635 * The / operator and // operators combine an arbitrary expression
10636 * and a relative location path. It is an error if the expression
10637 * does not evaluate to a node-set.
10638 * The / operator does composition in the same way as when / is
10639 * used in a location path. As in location paths, // is short for
10640 * /descendant-or-self::node()/.
10644 xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
10645 int lc = 1; /* Should we branch to LocationPath ? */
10646 xmlChar *name = NULL; /* we may have to preparse a name to find out */
10649 if ((CUR == '$') || (CUR == '(') ||
10650 (IS_ASCII_DIGIT(CUR)) ||
10651 (CUR == '\'') || (CUR == '"') ||
10652 (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
10654 } else if (CUR == '*') {
10655 /* relative or absolute location path */
10657 } else if (CUR == '/') {
10658 /* relative or absolute location path */
10660 } else if (CUR == '@') {
10661 /* relative abbreviated attribute location path */
10663 } else if (CUR == '.') {
10664 /* relative abbreviated attribute location path */
10668 * Problem is finding if we have a name here whether it's:
10670 * - a function call in which case it's followed by '('
10671 * - an axis in which case it's followed by ':'
10673 * We do an a priori analysis here rather than having to
10674 * maintain parsed token content through the recursive function
10675 * calls. This looks uglier but makes the code easier to
10676 * read/write/debug.
10679 name = xmlXPathScanName(ctxt);
10680 if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
10682 xmlGenericError(xmlGenericErrorContext,
10683 "PathExpr: Axis\n");
10687 } else if (name != NULL) {
10688 int len =xmlStrlen(name);
10691 while (NXT(len) != 0) {
10692 if (NXT(len) == '/') {
10695 xmlGenericError(xmlGenericErrorContext,
10696 "PathExpr: AbbrRelLocation\n");
10700 } else if (IS_BLANK_CH(NXT(len))) {
10701 /* ignore blanks */
10703 } else if (NXT(len) == ':') {
10705 xmlGenericError(xmlGenericErrorContext,
10706 "PathExpr: AbbrRelLocation\n");
10710 } else if ((NXT(len) == '(')) {
10711 /* Node Type or Function */
10712 if (xmlXPathIsNodeType(name)) {
10714 xmlGenericError(xmlGenericErrorContext,
10715 "PathExpr: Type search\n");
10718 #ifdef LIBXML_XPTR_ENABLED
10719 } else if (ctxt->xptr &&
10720 xmlStrEqual(name, BAD_CAST "range-to")) {
10725 xmlGenericError(xmlGenericErrorContext,
10726 "PathExpr: function call\n");
10731 } else if ((NXT(len) == '[')) {
10734 xmlGenericError(xmlGenericErrorContext,
10735 "PathExpr: AbbrRelLocation\n");
10739 } else if ((NXT(len) == '<') || (NXT(len) == '>') ||
10740 (NXT(len) == '=')) {
10749 if (NXT(len) == 0) {
10751 xmlGenericError(xmlGenericErrorContext,
10752 "PathExpr: AbbrRelLocation\n");
10759 /* make sure all cases are covered explicitly */
10760 XP_ERROR(XPATH_EXPR_ERROR);
10766 PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
10768 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10770 xmlXPathCompLocationPath(ctxt);
10772 xmlXPathCompFilterExpr(ctxt);
10774 if ((CUR == '/') && (NXT(1) == '/')) {
10778 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
10779 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
10780 PUSH_UNARY_EXPR(XPATH_OP_RESET, ctxt->comp->last, 1, 0);
10782 xmlXPathCompRelativeLocationPath(ctxt);
10783 } else if (CUR == '/') {
10784 xmlXPathCompRelativeLocationPath(ctxt);
10791 * xmlXPathCompUnionExpr:
10792 * @ctxt: the XPath Parser context
10794 * [18] UnionExpr ::= PathExpr
10795 * | UnionExpr '|' PathExpr
10797 * Compile an union expression.
10801 xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
10802 xmlXPathCompPathExpr(ctxt);
10805 while (CUR == '|') {
10806 int op1 = ctxt->comp->last;
10807 PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
10811 xmlXPathCompPathExpr(ctxt);
10813 PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
10820 * xmlXPathCompUnaryExpr:
10821 * @ctxt: the XPath Parser context
10823 * [27] UnaryExpr ::= UnionExpr
10826 * Compile an unary expression.
10830 xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
10835 while (CUR == '-') {
10842 xmlXPathCompUnionExpr(ctxt);
10846 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
10848 PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
10853 * xmlXPathCompMultiplicativeExpr:
10854 * @ctxt: the XPath Parser context
10856 * [26] MultiplicativeExpr ::= UnaryExpr
10857 * | MultiplicativeExpr MultiplyOperator UnaryExpr
10858 * | MultiplicativeExpr 'div' UnaryExpr
10859 * | MultiplicativeExpr 'mod' UnaryExpr
10860 * [34] MultiplyOperator ::= '*'
10862 * Compile an Additive expression.
10866 xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
10867 xmlXPathCompUnaryExpr(ctxt);
10870 while ((CUR == '*') ||
10871 ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
10872 ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
10874 int op1 = ctxt->comp->last;
10879 } else if (CUR == 'd') {
10882 } else if (CUR == 'm') {
10887 xmlXPathCompUnaryExpr(ctxt);
10889 PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
10895 * xmlXPathCompAdditiveExpr:
10896 * @ctxt: the XPath Parser context
10898 * [25] AdditiveExpr ::= MultiplicativeExpr
10899 * | AdditiveExpr '+' MultiplicativeExpr
10900 * | AdditiveExpr '-' MultiplicativeExpr
10902 * Compile an Additive expression.
10906 xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
10908 xmlXPathCompMultiplicativeExpr(ctxt);
10911 while ((CUR == '+') || (CUR == '-')) {
10913 int op1 = ctxt->comp->last;
10915 if (CUR == '+') plus = 1;
10919 xmlXPathCompMultiplicativeExpr(ctxt);
10921 PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
10927 * xmlXPathCompRelationalExpr:
10928 * @ctxt: the XPath Parser context
10930 * [24] RelationalExpr ::= AdditiveExpr
10931 * | RelationalExpr '<' AdditiveExpr
10932 * | RelationalExpr '>' AdditiveExpr
10933 * | RelationalExpr '<=' AdditiveExpr
10934 * | RelationalExpr '>=' AdditiveExpr
10936 * A <= B > C is allowed ? Answer from James, yes with
10937 * (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
10938 * which is basically what got implemented.
10940 * Compile a Relational expression, then push the result
10945 xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
10946 xmlXPathCompAdditiveExpr(ctxt);
10949 while ((CUR == '<') ||
10951 ((CUR == '<') && (NXT(1) == '=')) ||
10952 ((CUR == '>') && (NXT(1) == '='))) {
10954 int op1 = ctxt->comp->last;
10956 if (CUR == '<') inf = 1;
10958 if (NXT(1) == '=') strict = 0;
10963 xmlXPathCompAdditiveExpr(ctxt);
10965 PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
10971 * xmlXPathCompEqualityExpr:
10972 * @ctxt: the XPath Parser context
10974 * [23] EqualityExpr ::= RelationalExpr
10975 * | EqualityExpr '=' RelationalExpr
10976 * | EqualityExpr '!=' RelationalExpr
10978 * A != B != C is allowed ? Answer from James, yes with
10979 * (RelationalExpr = RelationalExpr) = RelationalExpr
10980 * (RelationalExpr != RelationalExpr) != RelationalExpr
10981 * which is basically what got implemented.
10983 * Compile an Equality expression.
10987 xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
10988 xmlXPathCompRelationalExpr(ctxt);
10991 while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
10993 int op1 = ctxt->comp->last;
10995 if (CUR == '=') eq = 1;
11000 xmlXPathCompRelationalExpr(ctxt);
11002 PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
11008 * xmlXPathCompAndExpr:
11009 * @ctxt: the XPath Parser context
11011 * [22] AndExpr ::= EqualityExpr
11012 * | AndExpr 'and' EqualityExpr
11014 * Compile an AND expression.
11018 xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
11019 xmlXPathCompEqualityExpr(ctxt);
11022 while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
11023 int op1 = ctxt->comp->last;
11026 xmlXPathCompEqualityExpr(ctxt);
11028 PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
11034 * xmlXPathCompileExpr:
11035 * @ctxt: the XPath Parser context
11037 * [14] Expr ::= OrExpr
11038 * [21] OrExpr ::= AndExpr
11039 * | OrExpr 'or' AndExpr
11041 * Parse and compile an expression
11044 xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
11045 xmlXPathCompAndExpr(ctxt);
11048 while ((CUR == 'o') && (NXT(1) == 'r')) {
11049 int op1 = ctxt->comp->last;
11052 xmlXPathCompAndExpr(ctxt);
11054 PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
11057 if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
11058 /* more ops could be optimized too */
11060 * This is the main place to eliminate sorting for
11061 * operations which don't require a sorted node-set.
11064 PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
11069 * xmlXPathCompPredicate:
11070 * @ctxt: the XPath Parser context
11071 * @filter: act as a filter
11073 * [8] Predicate ::= '[' PredicateExpr ']'
11074 * [9] PredicateExpr ::= Expr
11076 * Compile a predicate expression
11079 xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
11080 int op1 = ctxt->comp->last;
11084 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11089 ctxt->comp->last = -1;
11091 * This call to xmlXPathCompileExpr() will deactivate sorting
11092 * of the predicate result.
11093 * TODO: Sorting is still activated for filters, since I'm not
11094 * sure if needed. Normally sorting should not be needed, since
11095 * a filter can only diminish the number of items in a sequence,
11096 * but won't change its order; so if the initial sequence is sorted,
11097 * subsequent sorting is not needed.
11100 xmlXPathCompileExpr(ctxt, 0);
11102 xmlXPathCompileExpr(ctxt, 1);
11106 XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
11110 PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
11112 PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
11119 * xmlXPathCompNodeTest:
11120 * @ctxt: the XPath Parser context
11121 * @test: pointer to a xmlXPathTestVal
11122 * @type: pointer to a xmlXPathTypeVal
11123 * @prefix: placeholder for a possible name prefix
11125 * [7] NodeTest ::= NameTest
11126 * | NodeType '(' ')'
11127 * | 'processing-instruction' '(' Literal ')'
11129 * [37] NameTest ::= '*'
11132 * [38] NodeType ::= 'comment'
11134 * | 'processing-instruction'
11137 * Returns the name found and updates @test, @type and @prefix appropriately
11140 xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
11141 xmlXPathTypeVal *type, const xmlChar **prefix,
11145 if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
11149 *type = (xmlXPathTypeVal) 0;
11150 *test = (xmlXPathTestVal) 0;
11154 if ((name == NULL) && (CUR == '*')) {
11159 *test = NODE_TEST_ALL;
11164 name = xmlXPathParseNCName(ctxt);
11165 if (name == NULL) {
11166 XP_ERRORNULL(XPATH_EXPR_ERROR);
11169 blanks = IS_BLANK_CH(CUR);
11174 * NodeType or PI search
11176 if (xmlStrEqual(name, BAD_CAST "comment"))
11177 *type = NODE_TYPE_COMMENT;
11178 else if (xmlStrEqual(name, BAD_CAST "node"))
11179 *type = NODE_TYPE_NODE;
11180 else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
11181 *type = NODE_TYPE_PI;
11182 else if (xmlStrEqual(name, BAD_CAST "text"))
11183 *type = NODE_TYPE_TEXT;
11187 XP_ERRORNULL(XPATH_EXPR_ERROR);
11190 *test = NODE_TEST_TYPE;
11193 if (*type == NODE_TYPE_PI) {
11195 * Specific case: search a PI by name.
11201 name = xmlXPathParseLiteral(ctxt);
11203 *test = NODE_TEST_PI;
11210 XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
11215 *test = NODE_TEST_NAME;
11216 if ((!blanks) && (CUR == ':')) {
11220 * Since currently the parser context don't have a
11221 * namespace list associated:
11222 * The namespace name for this prefix can be computed
11223 * only at evaluation time. The compilation is done
11224 * outside of any context.
11227 *prefix = xmlXPathNsLookup(ctxt->context, name);
11230 if (*prefix == NULL) {
11231 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
11242 *test = NODE_TEST_ALL;
11246 name = xmlXPathParseNCName(ctxt);
11247 if (name == NULL) {
11248 XP_ERRORNULL(XPATH_EXPR_ERROR);
11255 * xmlXPathIsAxisName:
11256 * @name: a preparsed name token
11258 * [6] AxisName ::= 'ancestor'
11259 * | 'ancestor-or-self'
11263 * | 'descendant-or-self'
11265 * | 'following-sibling'
11269 * | 'preceding-sibling'
11272 * Returns the axis or 0
11274 static xmlXPathAxisVal
11275 xmlXPathIsAxisName(const xmlChar *name) {
11276 xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
11279 if (xmlStrEqual(name, BAD_CAST "ancestor"))
11280 ret = AXIS_ANCESTOR;
11281 if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
11282 ret = AXIS_ANCESTOR_OR_SELF;
11283 if (xmlStrEqual(name, BAD_CAST "attribute"))
11284 ret = AXIS_ATTRIBUTE;
11287 if (xmlStrEqual(name, BAD_CAST "child"))
11291 if (xmlStrEqual(name, BAD_CAST "descendant"))
11292 ret = AXIS_DESCENDANT;
11293 if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
11294 ret = AXIS_DESCENDANT_OR_SELF;
11297 if (xmlStrEqual(name, BAD_CAST "following"))
11298 ret = AXIS_FOLLOWING;
11299 if (xmlStrEqual(name, BAD_CAST "following-sibling"))
11300 ret = AXIS_FOLLOWING_SIBLING;
11303 if (xmlStrEqual(name, BAD_CAST "namespace"))
11304 ret = AXIS_NAMESPACE;
11307 if (xmlStrEqual(name, BAD_CAST "parent"))
11309 if (xmlStrEqual(name, BAD_CAST "preceding"))
11310 ret = AXIS_PRECEDING;
11311 if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
11312 ret = AXIS_PRECEDING_SIBLING;
11315 if (xmlStrEqual(name, BAD_CAST "self"))
11323 * xmlXPathCompStep:
11324 * @ctxt: the XPath Parser context
11326 * [4] Step ::= AxisSpecifier NodeTest Predicate*
11327 * | AbbreviatedStep
11329 * [12] AbbreviatedStep ::= '.' | '..'
11331 * [5] AxisSpecifier ::= AxisName '::'
11332 * | AbbreviatedAxisSpecifier
11334 * [13] AbbreviatedAxisSpecifier ::= '@'?
11336 * Modified for XPtr range support as:
11338 * [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
11339 * | AbbreviatedStep
11340 * | 'range-to' '(' Expr ')' Predicate*
11342 * Compile one step in a Location Path
11343 * A location step of . is short for self::node(). This is
11344 * particularly useful in conjunction with //. For example, the
11345 * location path .//para is short for
11346 * self::node()/descendant-or-self::node()/child::para
11347 * and so will select all para descendant elements of the context
11349 * Similarly, a location step of .. is short for parent::node().
11350 * For example, ../title is short for parent::node()/child::title
11351 * and so will select the title children of the parent of the context
11355 xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
11356 #ifdef LIBXML_XPTR_ENABLED
11362 if ((CUR == '.') && (NXT(1) == '.')) {
11365 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
11366 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11367 } else if (CUR == '.') {
11371 xmlChar *name = NULL;
11372 const xmlChar *prefix = NULL;
11373 xmlXPathTestVal test = (xmlXPathTestVal) 0;
11374 xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
11375 xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
11379 * The modification needed for XPointer change to the production
11381 #ifdef LIBXML_XPTR_ENABLED
11383 name = xmlXPathParseNCName(ctxt);
11384 if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
11385 op2 = ctxt->comp->last;
11389 XP_ERROR(XPATH_EXPR_ERROR);
11394 xmlXPathCompileExpr(ctxt, 1);
11395 /* PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, ctxt->comp->last, 0, 0); */
11400 XP_ERROR(XPATH_EXPR_ERROR);
11404 goto eval_predicates;
11412 name = xmlXPathParseNCName(ctxt);
11413 if (name != NULL) {
11414 axis = xmlXPathIsAxisName(name);
11417 if ((CUR == ':') && (NXT(1) == ':')) {
11422 /* an element name can conflict with an axis one :-\ */
11428 } else if (CUR == '@') {
11430 axis = AXIS_ATTRIBUTE;
11436 if (ctxt->error != XPATH_EXPRESSION_OK) {
11441 name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
11445 if ((prefix != NULL) && (ctxt->context != NULL) &&
11446 (ctxt->context->flags & XML_XPATH_CHECKNS)) {
11447 if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
11448 xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
11452 xmlGenericError(xmlGenericErrorContext,
11453 "Basis : computing new set\n");
11457 xmlGenericError(xmlGenericErrorContext, "Basis : ");
11458 if (ctxt->value == NULL)
11459 xmlGenericError(xmlGenericErrorContext, "no value\n");
11460 else if (ctxt->value->nodesetval == NULL)
11461 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11463 xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
11466 #ifdef LIBXML_XPTR_ENABLED
11469 op1 = ctxt->comp->last;
11470 ctxt->comp->last = -1;
11473 while (CUR == '[') {
11474 xmlXPathCompPredicate(ctxt, 0);
11477 #ifdef LIBXML_XPTR_ENABLED
11479 PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
11482 PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
11483 test, type, (void *)prefix, (void *)name);
11487 xmlGenericError(xmlGenericErrorContext, "Step : ");
11488 if (ctxt->value == NULL)
11489 xmlGenericError(xmlGenericErrorContext, "no value\n");
11490 else if (ctxt->value->nodesetval == NULL)
11491 xmlGenericError(xmlGenericErrorContext, "Empty\n");
11493 xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
11494 ctxt->value->nodesetval);
11499 * xmlXPathCompRelativeLocationPath:
11500 * @ctxt: the XPath Parser context
11502 * [3] RelativeLocationPath ::= Step
11503 * | RelativeLocationPath '/' Step
11504 * | AbbreviatedRelativeLocationPath
11505 * [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
11507 * Compile a relative location path.
11510 xmlXPathCompRelativeLocationPath
11511 (xmlXPathParserContextPtr ctxt) {
11513 if ((CUR == '/') && (NXT(1) == '/')) {
11516 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11517 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11518 } else if (CUR == '/') {
11522 xmlXPathCompStep(ctxt);
11525 while (CUR == '/') {
11526 if ((CUR == '/') && (NXT(1) == '/')) {
11529 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11530 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11531 xmlXPathCompStep(ctxt);
11532 } else if (CUR == '/') {
11535 xmlXPathCompStep(ctxt);
11542 * xmlXPathCompLocationPath:
11543 * @ctxt: the XPath Parser context
11545 * [1] LocationPath ::= RelativeLocationPath
11546 * | AbsoluteLocationPath
11547 * [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
11548 * | AbbreviatedAbsoluteLocationPath
11549 * [10] AbbreviatedAbsoluteLocationPath ::=
11550 * '//' RelativeLocationPath
11552 * Compile a location path
11554 * // is short for /descendant-or-self::node()/. For example,
11555 * //para is short for /descendant-or-self::node()/child::para and
11556 * so will select any para element in the document (even a para element
11557 * that is a document element will be selected by //para since the
11558 * document element node is a child of the root node); div//para is
11559 * short for div/descendant-or-self::node()/child::para and so will
11560 * select all para descendants of div children.
11563 xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
11566 xmlXPathCompRelativeLocationPath(ctxt);
11568 while (CUR == '/') {
11569 if ((CUR == '/') && (NXT(1) == '/')) {
11572 PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
11573 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
11574 xmlXPathCompRelativeLocationPath(ctxt);
11575 } else if (CUR == '/') {
11579 ((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
11580 (CUR == '@') || (CUR == '*')))
11581 xmlXPathCompRelativeLocationPath(ctxt);
11588 /************************************************************************
11590 * XPath precompiled expression evaluation *
11592 ************************************************************************/
11595 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
11599 xmlXPathDebugDumpStepAxis(xmlXPathStepOpPtr op,
11602 xmlGenericError(xmlGenericErrorContext, "new step : ");
11603 switch (op->value) {
11604 case AXIS_ANCESTOR:
11605 xmlGenericError(xmlGenericErrorContext, "axis 'ancestors' ");
11607 case AXIS_ANCESTOR_OR_SELF:
11608 xmlGenericError(xmlGenericErrorContext,
11609 "axis 'ancestors-or-self' ");
11611 case AXIS_ATTRIBUTE:
11612 xmlGenericError(xmlGenericErrorContext, "axis 'attributes' ");
11615 xmlGenericError(xmlGenericErrorContext, "axis 'child' ");
11617 case AXIS_DESCENDANT:
11618 xmlGenericError(xmlGenericErrorContext, "axis 'descendant' ");
11620 case AXIS_DESCENDANT_OR_SELF:
11621 xmlGenericError(xmlGenericErrorContext,
11622 "axis 'descendant-or-self' ");
11624 case AXIS_FOLLOWING:
11625 xmlGenericError(xmlGenericErrorContext, "axis 'following' ");
11627 case AXIS_FOLLOWING_SIBLING:
11628 xmlGenericError(xmlGenericErrorContext,
11629 "axis 'following-siblings' ");
11631 case AXIS_NAMESPACE:
11632 xmlGenericError(xmlGenericErrorContext, "axis 'namespace' ");
11635 xmlGenericError(xmlGenericErrorContext, "axis 'parent' ");
11637 case AXIS_PRECEDING:
11638 xmlGenericError(xmlGenericErrorContext, "axis 'preceding' ");
11640 case AXIS_PRECEDING_SIBLING:
11641 xmlGenericError(xmlGenericErrorContext,
11642 "axis 'preceding-sibling' ");
11645 xmlGenericError(xmlGenericErrorContext, "axis 'self' ");
11648 xmlGenericError(xmlGenericErrorContext,
11649 " context contains %d nodes\n", nbNodes);
11650 switch (op->value2) {
11651 case NODE_TEST_NONE:
11652 xmlGenericError(xmlGenericErrorContext,
11653 " searching for none !!!\n");
11655 case NODE_TEST_TYPE:
11656 xmlGenericError(xmlGenericErrorContext,
11657 " searching for type %d\n", op->value3);
11660 xmlGenericError(xmlGenericErrorContext,
11661 " searching for PI !!!\n");
11663 case NODE_TEST_ALL:
11664 xmlGenericError(xmlGenericErrorContext,
11665 " searching for *\n");
11668 xmlGenericError(xmlGenericErrorContext,
11669 " searching for namespace %s\n",
11672 case NODE_TEST_NAME:
11673 xmlGenericError(xmlGenericErrorContext,
11674 " searching for name %s\n", op->value5);
11676 xmlGenericError(xmlGenericErrorContext,
11677 " with namespace %s\n", op->value4);
11680 xmlGenericError(xmlGenericErrorContext, "Testing : ");
11682 #endif /* DEBUG_STEP */
11685 xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
11686 xmlXPathStepOpPtr op,
11691 if (op->ch1 != -1) {
11692 xmlXPathCompExprPtr comp = ctxt->comp;
11694 * Process inner predicates first.
11696 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11698 * TODO: raise an internal error.
11701 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11702 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11704 if (contextSize <= 0)
11707 if (op->ch2 != -1) {
11708 xmlXPathContextPtr xpctxt = ctxt->context;
11709 xmlNodePtr contextNode, oldContextNode;
11710 xmlDocPtr oldContextDoc;
11711 int i, res, contextPos = 0, newContextSize;
11712 xmlXPathStepOpPtr exprOp;
11713 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11715 #ifdef LIBXML_XPTR_ENABLED
11717 * URGENT TODO: Check the following:
11718 * We don't expect location sets if evaluating prediates, right?
11719 * Only filters should expect location sets, right?
11724 * "For each node in the node-set to be filtered, the
11725 * PredicateExpr is evaluated with that node as the
11726 * context node, with the number of nodes in the
11727 * node-set as the context size, and with the proximity
11728 * position of the node in the node-set with respect to
11729 * the axis as the context position;"
11730 * @oldset is the node-set" to be filtered.
11733 * "only predicates change the context position and
11734 * context size (see [2.4 Predicates])."
11736 * node-set context pos
11740 * After applying predicate [position() > 1] :
11741 * node-set context pos
11745 oldContextNode = xpctxt->node;
11746 oldContextDoc = xpctxt->doc;
11748 * Get the expression of this predicate.
11750 exprOp = &ctxt->comp->steps[op->ch2];
11751 newContextSize = 0;
11752 for (i = 0; i < set->nodeNr; i++) {
11753 if (set->nodeTab[i] == NULL)
11756 contextNode = set->nodeTab[i];
11757 xpctxt->node = contextNode;
11758 xpctxt->contextSize = contextSize;
11759 xpctxt->proximityPosition = ++contextPos;
11762 * Also set the xpath document in case things like
11763 * key() are evaluated in the predicate.
11765 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11766 (contextNode->doc != NULL))
11767 xpctxt->doc = contextNode->doc;
11769 * Evaluate the predicate expression with 1 context node
11770 * at a time; this node is packaged into a node set; this
11771 * node set is handed over to the evaluation mechanism.
11773 if (contextObj == NULL)
11774 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11776 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11777 contextNode) < 0) {
11778 ctxt->error = XPATH_MEMORY_ERROR;
11779 goto evaluation_exit;
11783 valuePush(ctxt, contextObj);
11785 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11787 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11788 xmlXPathNodeSetClear(set, hasNsNodes);
11789 newContextSize = 0;
11790 goto evaluation_exit;
11797 * Remove the entry from the initial node set.
11799 set->nodeTab[i] = NULL;
11800 if (contextNode->type == XML_NAMESPACE_DECL)
11801 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11803 if (ctxt->value == contextObj) {
11805 * Don't free the temporary XPath object holding the
11806 * context node, in order to avoid massive recreation
11807 * inside this loop.
11810 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
11813 * TODO: The object was lost in the evaluation machinery.
11814 * Can this happen? Maybe in internal-error cases.
11820 if (contextObj != NULL) {
11821 if (ctxt->value == contextObj)
11823 xmlXPathReleaseObject(xpctxt, contextObj);
11826 if (exprRes != NULL)
11827 xmlXPathReleaseObject(ctxt->context, exprRes);
11829 * Reset/invalidate the context.
11831 xpctxt->node = oldContextNode;
11832 xpctxt->doc = oldContextDoc;
11833 xpctxt->contextSize = -1;
11834 xpctxt->proximityPosition = -1;
11835 return(newContextSize);
11837 return(contextSize);
11841 xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
11842 xmlXPathStepOpPtr op,
11849 if (op->ch1 != -1) {
11850 xmlXPathCompExprPtr comp = ctxt->comp;
11851 if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
11853 * TODO: raise an internal error.
11856 contextSize = xmlXPathCompOpEvalPredicate(ctxt,
11857 &comp->steps[op->ch1], set, contextSize, hasNsNodes);
11859 if (contextSize <= 0)
11863 * Check if the node set contains a sufficient number of nodes for
11864 * the requested range.
11866 if (contextSize < minPos) {
11867 xmlXPathNodeSetClear(set, hasNsNodes);
11870 if (op->ch2 == -1) {
11872 * TODO: Can this ever happen?
11874 return (contextSize);
11876 xmlDocPtr oldContextDoc;
11877 int i, pos = 0, newContextSize = 0, contextPos = 0, res;
11878 xmlXPathStepOpPtr exprOp;
11879 xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
11880 xmlNodePtr oldContextNode, contextNode = NULL;
11881 xmlXPathContextPtr xpctxt = ctxt->context;
11884 #ifdef LIBXML_XPTR_ENABLED
11886 * URGENT TODO: Check the following:
11887 * We don't expect location sets if evaluating prediates, right?
11888 * Only filters should expect location sets, right?
11890 #endif /* LIBXML_XPTR_ENABLED */
11893 * Save old context.
11895 oldContextNode = xpctxt->node;
11896 oldContextDoc = xpctxt->doc;
11898 * Get the expression of this predicate.
11900 exprOp = &ctxt->comp->steps[op->ch2];
11901 for (i = 0; i < set->nodeNr; i++) {
11902 xmlXPathObjectPtr tmp;
11904 if (set->nodeTab[i] == NULL)
11907 contextNode = set->nodeTab[i];
11908 xpctxt->node = contextNode;
11909 xpctxt->contextSize = contextSize;
11910 xpctxt->proximityPosition = ++contextPos;
11913 * Initialize the new set.
11914 * Also set the xpath document in case things like
11915 * key() evaluation are attempted on the predicate
11917 if ((contextNode->type != XML_NAMESPACE_DECL) &&
11918 (contextNode->doc != NULL))
11919 xpctxt->doc = contextNode->doc;
11921 * Evaluate the predicate expression with 1 context node
11922 * at a time; this node is packaged into a node set; this
11923 * node set is handed over to the evaluation mechanism.
11925 if (contextObj == NULL)
11926 contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
11928 if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
11929 contextNode) < 0) {
11930 ctxt->error = XPATH_MEMORY_ERROR;
11931 goto evaluation_exit;
11935 valuePush(ctxt, contextObj);
11936 frame = xmlXPathSetFrame(ctxt);
11937 res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
11938 xmlXPathPopFrame(ctxt, frame);
11939 tmp = valuePop(ctxt);
11941 if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
11942 while (tmp != contextObj) {
11944 * Free up the result
11945 * then pop off contextObj, which will be freed later
11947 xmlXPathReleaseObject(xpctxt, tmp);
11948 tmp = valuePop(ctxt);
11950 goto evaluation_error;
11952 /* push the result back onto the stack */
11953 valuePush(ctxt, tmp);
11958 if (res && (pos >= minPos) && (pos <= maxPos)) {
11960 * Fits in the requested range.
11963 if (minPos == maxPos) {
11965 * Only 1 node was requested.
11967 if (contextNode->type == XML_NAMESPACE_DECL) {
11969 * As always: take care of those nasty
11972 set->nodeTab[i] = NULL;
11974 xmlXPathNodeSetClear(set, hasNsNodes);
11976 set->nodeTab[0] = contextNode;
11977 goto evaluation_exit;
11979 if (pos == maxPos) {
11983 xmlXPathNodeSetClearFromPos(set, i +1, hasNsNodes);
11984 goto evaluation_exit;
11988 * Remove the entry from the initial node set.
11990 set->nodeTab[i] = NULL;
11991 if (contextNode->type == XML_NAMESPACE_DECL)
11992 xmlXPathNodeSetFreeNs((xmlNsPtr) contextNode);
11994 if (exprRes != NULL) {
11995 xmlXPathReleaseObject(ctxt->context, exprRes);
11998 if (ctxt->value == contextObj) {
12000 * Don't free the temporary XPath object holding the
12001 * context node, in order to avoid massive recreation
12002 * inside this loop.
12005 xmlXPathNodeSetClear(contextObj->nodesetval, hasNsNodes);
12008 * The object was lost in the evaluation machinery.
12009 * Can this happen? Maybe in case of internal-errors.
12014 goto evaluation_exit;
12017 xmlXPathNodeSetClear(set, hasNsNodes);
12018 newContextSize = 0;
12021 if (contextObj != NULL) {
12022 if (ctxt->value == contextObj)
12024 xmlXPathReleaseObject(xpctxt, contextObj);
12026 if (exprRes != NULL)
12027 xmlXPathReleaseObject(ctxt->context, exprRes);
12029 * Reset/invalidate the context.
12031 xpctxt->node = oldContextNode;
12032 xpctxt->doc = oldContextDoc;
12033 xpctxt->contextSize = -1;
12034 xpctxt->proximityPosition = -1;
12035 return(newContextSize);
12037 return(contextSize);
12041 xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
12042 xmlXPathStepOpPtr op,
12046 xmlXPathStepOpPtr exprOp;
12049 * BIG NOTE: This is not intended for XPATH_OP_FILTER yet!
12053 * If not -1, then ch1 will point to:
12054 * 1) For predicates (XPATH_OP_PREDICATE):
12055 * - an inner predicate operator
12056 * 2) For filters (XPATH_OP_FILTER):
12057 * - an inner filter operater OR
12058 * - an expression selecting the node set.
12059 * E.g. "key('a', 'b')" or "(//foo | //bar)".
12061 if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
12064 if (op->ch2 != -1) {
12065 exprOp = &ctxt->comp->steps[op->ch2];
12069 if ((exprOp != NULL) &&
12070 (exprOp->op == XPATH_OP_VALUE) &&
12071 (exprOp->value4 != NULL) &&
12072 (((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
12074 double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
12077 * We have a "[n]" predicate here.
12078 * TODO: Unfortunately this simplistic test here is not
12079 * able to detect a position() predicate in compound
12080 * expressions like "[@attr = 'a" and position() = 1],
12081 * and even not the usage of position() in
12082 * "[position() = 1]"; thus - obviously - a position-range,
12083 * like it "[position() < 5]", is also not detected.
12084 * Maybe we could rewrite the AST to ease the optimization.
12087 if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
12088 *maxPos = (int) floatval;
12089 if (floatval == (double) *maxPos)
12097 xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
12098 xmlXPathStepOpPtr op,
12099 xmlNodePtr * first, xmlNodePtr * last,
12103 #define XP_TEST_HIT \
12104 if (hasAxisRange != 0) { \
12105 if (++pos == maxPos) { \
12106 if (addNode(seq, cur) < 0) \
12107 ctxt->error = XPATH_MEMORY_ERROR; \
12108 goto axis_range_end; } \
12110 if (addNode(seq, cur) < 0) \
12111 ctxt->error = XPATH_MEMORY_ERROR; \
12112 if (breakOnFirstHit) goto first_hit; }
12114 #define XP_TEST_HIT_NS \
12115 if (hasAxisRange != 0) { \
12116 if (++pos == maxPos) { \
12118 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12119 ctxt->error = XPATH_MEMORY_ERROR; \
12120 goto axis_range_end; } \
12123 if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
12124 ctxt->error = XPATH_MEMORY_ERROR; \
12125 if (breakOnFirstHit) goto first_hit; }
12127 xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
12128 xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
12129 xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
12130 const xmlChar *prefix = op->value4;
12131 const xmlChar *name = op->value5;
12132 const xmlChar *URI = NULL;
12135 int nbMatches = 0, prevMatches = 0;
12137 int total = 0, hasNsNodes = 0;
12138 /* The popped object holding the context nodes */
12139 xmlXPathObjectPtr obj;
12140 /* The set of context nodes for the node tests */
12141 xmlNodeSetPtr contextSeq;
12143 xmlNodePtr contextNode;
12144 /* The final resulting node set wrt to all context nodes */
12145 xmlNodeSetPtr outSeq;
12147 * The temporary resulting node set wrt 1 context node.
12148 * Used to feed predicate evaluation.
12152 /* First predicate operator */
12153 xmlXPathStepOpPtr predOp;
12154 int maxPos; /* The requested position() (when a "[n]" predicate) */
12155 int hasPredicateRange, hasAxisRange, pos, size, newSize;
12156 int breakOnFirstHit;
12158 xmlXPathTraversalFunction next = NULL;
12159 int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
12160 xmlXPathNodeSetMergeFunction mergeAndClear;
12161 xmlNodePtr oldContextNode;
12162 xmlXPathContextPtr xpctxt = ctxt->context;
12165 CHECK_TYPE0(XPATH_NODESET);
12166 obj = valuePop(ctxt);
12168 * Setup namespaces.
12170 if (prefix != NULL) {
12171 URI = xmlXPathNsLookup(xpctxt, prefix);
12173 xmlXPathReleaseObject(xpctxt, obj);
12174 XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
12180 * MAYBE FUTURE TODO: merging optimizations:
12181 * - If the nodes to be traversed wrt to the initial nodes and
12182 * the current axis cannot overlap, then we could avoid searching
12183 * for duplicates during the merge.
12184 * But the question is how/when to evaluate if they cannot overlap.
12185 * Example: if we know that for two initial nodes, the one is
12186 * not in the ancestor-or-self axis of the other, then we could safely
12187 * avoid a duplicate-aware merge, if the axis to be traversed is e.g.
12188 * the descendant-or-self axis.
12190 mergeAndClear = xmlXPathNodeSetMergeAndClear;
12192 case AXIS_ANCESTOR:
12194 next = xmlXPathNextAncestor;
12196 case AXIS_ANCESTOR_OR_SELF:
12198 next = xmlXPathNextAncestorOrSelf;
12200 case AXIS_ATTRIBUTE:
12203 next = xmlXPathNextAttribute;
12204 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12208 if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
12209 (type == NODE_TYPE_NODE))
12212 * Optimization if an element node type is 'element'.
12214 next = xmlXPathNextChildElement;
12216 next = xmlXPathNextChild;
12217 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12219 case AXIS_DESCENDANT:
12221 next = xmlXPathNextDescendant;
12223 case AXIS_DESCENDANT_OR_SELF:
12225 next = xmlXPathNextDescendantOrSelf;
12227 case AXIS_FOLLOWING:
12229 next = xmlXPathNextFollowing;
12231 case AXIS_FOLLOWING_SIBLING:
12233 next = xmlXPathNextFollowingSibling;
12235 case AXIS_NAMESPACE:
12238 next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
12239 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12243 next = xmlXPathNextParent;
12245 case AXIS_PRECEDING:
12247 next = xmlXPathNextPrecedingInternal;
12249 case AXIS_PRECEDING_SIBLING:
12251 next = xmlXPathNextPrecedingSibling;
12256 next = xmlXPathNextSelf;
12257 mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
12262 xmlXPathDebugDumpStepAxis(op,
12263 (obj->nodesetval != NULL) ? obj->nodesetval->nodeNr : 0);
12266 if (next == NULL) {
12267 xmlXPathReleaseObject(xpctxt, obj);
12270 contextSeq = obj->nodesetval;
12271 if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
12272 xmlXPathReleaseObject(xpctxt, obj);
12273 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
12277 * Predicate optimization ---------------------------------------------
12278 * If this step has a last predicate, which contains a position(),
12279 * then we'll optimize (although not exactly "position()", but only
12280 * the short-hand form, i.e., "[n]".
12282 * Example - expression "/foo[parent::bar][1]":
12284 * COLLECT 'child' 'name' 'node' foo -- op (we are here)
12286 * PREDICATE -- op->ch2 (predOp)
12287 * PREDICATE -- predOp->ch1 = [parent::bar]
12289 * COLLECT 'parent' 'name' 'node' bar
12291 * ELEM Object is a number : 1 -- predOp->ch2 = [1]
12296 hasPredicateRange = 0;
12298 if (op->ch2 != -1) {
12300 * There's at least one predicate. 16 == XPATH_OP_PREDICATE
12302 predOp = &ctxt->comp->steps[op->ch2];
12303 if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
12304 if (predOp->ch1 != -1) {
12306 * Use the next inner predicate operator.
12308 predOp = &ctxt->comp->steps[predOp->ch1];
12309 hasPredicateRange = 1;
12312 * There's no other predicate than the [n] predicate.
12319 breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
12321 * Axis traversal -----------------------------------------------------
12325 * - For the attribute axis, the principal node type is attribute.
12326 * - For the namespace axis, the principal node type is namespace.
12327 * - For other axes, the principal node type is element.
12329 * A node test * is true for any node of the
12330 * principal node type. For example, child::* will
12331 * select all element children of the context node
12333 oldContextNode = xpctxt->node;
12334 addNode = xmlXPathNodeSetAddUnique;
12337 contextNode = NULL;
12341 while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
12342 (ctxt->error == XPATH_EXPRESSION_OK)) {
12343 xpctxt->node = contextSeq->nodeTab[contextIdx++];
12346 seq = xmlXPathNodeSetCreate(NULL);
12353 * Traverse the axis and test the nodes.
12359 cur = next(ctxt, cur);
12364 * QUESTION TODO: What does the "first" and "last" stuff do?
12366 if ((first != NULL) && (*first != NULL)) {
12369 if (((total % 256) == 0) &&
12370 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12371 (xmlXPathCmpNodesExt(*first, cur) >= 0))
12373 (xmlXPathCmpNodes(*first, cur) >= 0))
12379 if ((last != NULL) && (*last != NULL)) {
12382 if (((total % 256) == 0) &&
12383 #ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
12384 (xmlXPathCmpNodesExt(cur, *last) >= 0))
12386 (xmlXPathCmpNodes(cur, *last) >= 0))
12396 xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
12400 case NODE_TEST_NONE:
12404 case NODE_TEST_TYPE:
12405 if (type == NODE_TYPE_NODE) {
12406 switch (cur->type) {
12407 case XML_DOCUMENT_NODE:
12408 case XML_HTML_DOCUMENT_NODE:
12409 #ifdef LIBXML_DOCB_ENABLED
12410 case XML_DOCB_DOCUMENT_NODE:
12412 case XML_ELEMENT_NODE:
12413 case XML_ATTRIBUTE_NODE:
12415 case XML_COMMENT_NODE:
12416 case XML_CDATA_SECTION_NODE:
12417 case XML_TEXT_NODE:
12420 case XML_NAMESPACE_DECL: {
12421 if (axis == AXIS_NAMESPACE) {
12432 } else if (cur->type == type) {
12433 if (cur->type == XML_NAMESPACE_DECL)
12437 } else if ((type == NODE_TYPE_TEXT) &&
12438 (cur->type == XML_CDATA_SECTION_NODE))
12444 if ((cur->type == XML_PI_NODE) &&
12445 ((name == NULL) || xmlStrEqual(name, cur->name)))
12450 case NODE_TEST_ALL:
12451 if (axis == AXIS_ATTRIBUTE) {
12452 if (cur->type == XML_ATTRIBUTE_NODE)
12454 if (prefix == NULL)
12457 } else if ((cur->ns != NULL) &&
12458 (xmlStrEqual(URI, cur->ns->href)))
12463 } else if (axis == AXIS_NAMESPACE) {
12464 if (cur->type == XML_NAMESPACE_DECL)
12469 if (cur->type == XML_ELEMENT_NODE) {
12470 if (prefix == NULL)
12474 } else if ((cur->ns != NULL) &&
12475 (xmlStrEqual(URI, cur->ns->href)))
12482 case NODE_TEST_NS:{
12486 case NODE_TEST_NAME:
12487 if (axis == AXIS_ATTRIBUTE) {
12488 if (cur->type != XML_ATTRIBUTE_NODE)
12490 } else if (axis == AXIS_NAMESPACE) {
12491 if (cur->type != XML_NAMESPACE_DECL)
12494 if (cur->type != XML_ELEMENT_NODE)
12497 switch (cur->type) {
12498 case XML_ELEMENT_NODE:
12499 if (xmlStrEqual(name, cur->name)) {
12500 if (prefix == NULL) {
12501 if (cur->ns == NULL)
12506 if ((cur->ns != NULL) &&
12507 (xmlStrEqual(URI, cur->ns->href)))
12514 case XML_ATTRIBUTE_NODE:{
12515 xmlAttrPtr attr = (xmlAttrPtr) cur;
12517 if (xmlStrEqual(name, attr->name)) {
12518 if (prefix == NULL) {
12519 if ((attr->ns == NULL) ||
12520 (attr->ns->prefix == NULL))
12525 if ((attr->ns != NULL) &&
12535 case XML_NAMESPACE_DECL:
12536 if (cur->type == XML_NAMESPACE_DECL) {
12537 xmlNsPtr ns = (xmlNsPtr) cur;
12539 if ((ns->prefix != NULL) && (name != NULL)
12540 && (xmlStrEqual(ns->prefix, name)))
12550 } /* switch(test) */
12551 } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
12553 goto apply_predicates;
12555 axis_range_end: /* ----------------------------------------------------- */
12557 * We have a "/foo[n]", and position() = n was reached.
12558 * Note that we can have as well "/foo/::parent::foo[1]", so
12559 * a duplicate-aware merge is still needed.
12560 * Merge with the result.
12562 if (outSeq == NULL) {
12566 outSeq = mergeAndClear(outSeq, seq, 0);
12568 * Break if only a true/false result was requested.
12574 first_hit: /* ---------------------------------------------------------- */
12576 * Break if only a true/false result was requested and
12577 * no predicates existed and a node test succeeded.
12579 if (outSeq == NULL) {
12583 outSeq = mergeAndClear(outSeq, seq, 0);
12588 nbMatches += seq->nodeNr;
12591 apply_predicates: /* --------------------------------------------------- */
12592 if (ctxt->error != XPATH_EXPRESSION_OK)
12596 * Apply predicates.
12598 if ((predOp != NULL) && (seq->nodeNr > 0)) {
12600 * E.g. when we have a "/foo[some expression][n]".
12603 * QUESTION TODO: The old predicate evaluation took into
12604 * account location-sets.
12605 * (E.g. ctxt->value->type == XPATH_LOCATIONSET)
12606 * Do we expect such a set here?
12607 * All what I learned now from the evaluation semantics
12608 * does not indicate that a location-set will be processed
12609 * here, so this looks OK.
12612 * Iterate over all predicates, starting with the outermost
12614 * TODO: Problem: we cannot execute the inner predicates first
12615 * since we cannot go back *up* the operator tree!
12617 * 1) Use of recursive functions (like is it currently done
12618 * via xmlXPathCompOpEval())
12619 * 2) Add a predicate evaluation information stack to the
12621 * 3) Change the way the operators are linked; we need a
12622 * "parent" field on xmlXPathStepOp
12624 * For the moment, I'll try to solve this with a recursive
12625 * function: xmlXPathCompOpEvalPredicate().
12627 size = seq->nodeNr;
12628 if (hasPredicateRange != 0)
12629 newSize = xmlXPathCompOpEvalPositionalPredicate(ctxt,
12630 predOp, seq, size, maxPos, maxPos, hasNsNodes);
12632 newSize = xmlXPathCompOpEvalPredicate(ctxt,
12633 predOp, seq, size, hasNsNodes);
12635 if (ctxt->error != XPATH_EXPRESSION_OK) {
12640 * Add the filtered set of nodes to the result node set.
12642 if (newSize == 0) {
12644 * The predicates filtered all nodes out.
12646 xmlXPathNodeSetClear(seq, hasNsNodes);
12647 } else if (seq->nodeNr > 0) {
12649 * Add to result set.
12651 if (outSeq == NULL) {
12652 if (size != newSize) {
12654 * We need to merge and clear here, since
12655 * the sequence will contained NULLed entries.
12657 outSeq = mergeAndClear(NULL, seq, 1);
12663 outSeq = mergeAndClear(outSeq, seq,
12664 (size != newSize) ? 1: 0);
12666 * Break if only a true/false result was requested.
12671 } else if (seq->nodeNr > 0) {
12673 * Add to result set.
12675 if (outSeq == NULL) {
12679 outSeq = mergeAndClear(outSeq, seq, 0);
12685 if ((obj->boolval) && (obj->user != NULL)) {
12687 * QUESTION TODO: What does this do and why?
12688 * TODO: Do we have to do this also for the "error"
12689 * cleanup further down?
12691 ctxt->value->boolval = 1;
12692 ctxt->value->user = obj->user;
12696 xmlXPathReleaseObject(xpctxt, obj);
12699 * Ensure we return at least an emtpy set.
12701 if (outSeq == NULL) {
12702 if ((seq != NULL) && (seq->nodeNr == 0))
12705 outSeq = xmlXPathNodeSetCreate(NULL);
12706 /* XXX what if xmlXPathNodeSetCreate returned NULL here? */
12708 if ((seq != NULL) && (seq != outSeq)) {
12709 xmlXPathFreeNodeSet(seq);
12712 * Hand over the result. Better to push the set also in
12715 valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
12717 * Reset the context node.
12719 xpctxt->node = oldContextNode;
12721 * When traversing the namespace axis in "toBool" mode, it's
12722 * possible that tmpNsList wasn't freed.
12724 if (xpctxt->tmpNsList != NULL) {
12725 xmlFree(xpctxt->tmpNsList);
12726 xpctxt->tmpNsList = NULL;
12730 xmlGenericError(xmlGenericErrorContext,
12731 "\nExamined %d nodes, found %d nodes at that step\n",
12739 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
12740 xmlXPathStepOpPtr op, xmlNodePtr * first);
12743 * xmlXPathCompOpEvalFirst:
12744 * @ctxt: the XPath parser context with the compiled expression
12745 * @op: an XPath compiled operation
12746 * @first: the first elem found so far
12748 * Evaluate the Precompiled XPath operation searching only the first
12749 * element in document order
12751 * Returns the number of examined objects.
12754 xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
12755 xmlXPathStepOpPtr op, xmlNodePtr * first)
12757 int total = 0, cur;
12758 xmlXPathCompExprPtr comp;
12759 xmlXPathObjectPtr arg1, arg2;
12766 case XPATH_OP_UNION:
12768 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12771 if ((ctxt->value != NULL)
12772 && (ctxt->value->type == XPATH_NODESET)
12773 && (ctxt->value->nodesetval != NULL)
12774 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12776 * limit tree traversing to first node in the result
12779 * OPTIMIZE TODO: This implicitely sorts
12780 * the result, even if not needed. E.g. if the argument
12781 * of the count() function, no sorting is needed.
12782 * OPTIMIZE TODO: How do we know if the node-list wasn't
12785 if (ctxt->value->nodesetval->nodeNr > 1)
12786 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12787 *first = ctxt->value->nodesetval->nodeTab[0];
12790 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
12794 arg2 = valuePop(ctxt);
12795 arg1 = valuePop(ctxt);
12796 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12797 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12798 xmlXPathReleaseObject(ctxt->context, arg1);
12799 xmlXPathReleaseObject(ctxt->context, arg2);
12800 XP_ERROR0(XPATH_INVALID_TYPE);
12803 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12805 valuePush(ctxt, arg1);
12806 xmlXPathReleaseObject(ctxt->context, arg2);
12809 xmlXPathCompSwap(op);
12810 return (total + cur);
12811 case XPATH_OP_ROOT:
12812 xmlXPathRoot(ctxt);
12814 case XPATH_OP_NODE:
12816 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12819 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12821 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12822 ctxt->context->node));
12824 case XPATH_OP_RESET:
12826 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12829 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12831 ctxt->context->node = NULL;
12833 case XPATH_OP_COLLECT:{
12837 total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12840 total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
12843 case XPATH_OP_VALUE:
12845 xmlXPathCacheObjectCopy(ctxt->context,
12846 (xmlXPathObjectPtr) op->value4));
12848 case XPATH_OP_SORT:
12851 xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
12854 if ((ctxt->value != NULL)
12855 && (ctxt->value->type == XPATH_NODESET)
12856 && (ctxt->value->nodesetval != NULL)
12857 && (ctxt->value->nodesetval->nodeNr > 1))
12858 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12860 #ifdef XP_OPTIMIZED_FILTER_FIRST
12861 case XPATH_OP_FILTER:
12862 total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
12866 return (xmlXPathCompOpEval(ctxt, op));
12871 * xmlXPathCompOpEvalLast:
12872 * @ctxt: the XPath parser context with the compiled expression
12873 * @op: an XPath compiled operation
12874 * @last: the last elem found so far
12876 * Evaluate the Precompiled XPath operation searching only the last
12877 * element in document order
12879 * Returns the number of nodes traversed
12882 xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
12885 int total = 0, cur;
12886 xmlXPathCompExprPtr comp;
12887 xmlXPathObjectPtr arg1, arg2;
12898 case XPATH_OP_UNION:
12899 bakd = ctxt->context->doc;
12900 bak = ctxt->context->node;
12901 pp = ctxt->context->proximityPosition;
12902 cs = ctxt->context->contextSize;
12904 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
12906 if ((ctxt->value != NULL)
12907 && (ctxt->value->type == XPATH_NODESET)
12908 && (ctxt->value->nodesetval != NULL)
12909 && (ctxt->value->nodesetval->nodeNr >= 1)) {
12911 * limit tree traversing to first node in the result
12913 if (ctxt->value->nodesetval->nodeNr > 1)
12914 xmlXPathNodeSetSort(ctxt->value->nodesetval);
12916 ctxt->value->nodesetval->nodeTab[ctxt->value->
12917 nodesetval->nodeNr -
12920 ctxt->context->doc = bakd;
12921 ctxt->context->node = bak;
12922 ctxt->context->proximityPosition = pp;
12923 ctxt->context->contextSize = cs;
12925 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
12927 if ((ctxt->value != NULL)
12928 && (ctxt->value->type == XPATH_NODESET)
12929 && (ctxt->value->nodesetval != NULL)
12930 && (ctxt->value->nodesetval->nodeNr >= 1)) { /* TODO: NOP ? */
12933 arg2 = valuePop(ctxt);
12934 arg1 = valuePop(ctxt);
12935 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
12936 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
12937 xmlXPathReleaseObject(ctxt->context, arg1);
12938 xmlXPathReleaseObject(ctxt->context, arg2);
12939 XP_ERROR0(XPATH_INVALID_TYPE);
12942 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
12944 valuePush(ctxt, arg1);
12945 xmlXPathReleaseObject(ctxt->context, arg2);
12948 xmlXPathCompSwap(op);
12949 return (total + cur);
12950 case XPATH_OP_ROOT:
12951 xmlXPathRoot(ctxt);
12953 case XPATH_OP_NODE:
12955 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12958 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12960 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
12961 ctxt->context->node));
12963 case XPATH_OP_RESET:
12965 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12968 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
12970 ctxt->context->node = NULL;
12972 case XPATH_OP_COLLECT:{
12976 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
12979 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
12982 case XPATH_OP_VALUE:
12984 xmlXPathCacheObjectCopy(ctxt->context,
12985 (xmlXPathObjectPtr) op->value4));
12987 case XPATH_OP_SORT:
12990 xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
12993 if ((ctxt->value != NULL)
12994 && (ctxt->value->type == XPATH_NODESET)
12995 && (ctxt->value->nodesetval != NULL)
12996 && (ctxt->value->nodesetval->nodeNr > 1))
12997 xmlXPathNodeSetSort(ctxt->value->nodesetval);
13000 return (xmlXPathCompOpEval(ctxt, op));
13004 #ifdef XP_OPTIMIZED_FILTER_FIRST
13006 xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
13007 xmlXPathStepOpPtr op, xmlNodePtr * first)
13010 xmlXPathCompExprPtr comp;
13011 xmlXPathObjectPtr res;
13012 xmlXPathObjectPtr obj;
13013 xmlNodeSetPtr oldset;
13014 xmlNodePtr oldnode;
13021 * Optimization for ()[last()] selection i.e. the last elem
13023 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13024 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13025 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13026 int f = comp->steps[op->ch2].ch1;
13029 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13030 (comp->steps[f].value5 == NULL) &&
13031 (comp->steps[f].value == 0) &&
13032 (comp->steps[f].value4 != NULL) &&
13034 (comp->steps[f].value4, BAD_CAST "last"))) {
13035 xmlNodePtr last = NULL;
13038 xmlXPathCompOpEvalLast(ctxt,
13039 &comp->steps[op->ch1],
13043 * The nodeset should be in document order,
13044 * Keep only the last value
13046 if ((ctxt->value != NULL) &&
13047 (ctxt->value->type == XPATH_NODESET) &&
13048 (ctxt->value->nodesetval != NULL) &&
13049 (ctxt->value->nodesetval->nodeTab != NULL) &&
13050 (ctxt->value->nodesetval->nodeNr > 1)) {
13051 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13052 *first = *(ctxt->value->nodesetval->nodeTab);
13059 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13063 if (ctxt->value == NULL)
13066 #ifdef LIBXML_XPTR_ENABLED
13067 oldnode = ctxt->context->node;
13069 * Hum are we filtering the result of an XPointer expression
13071 if (ctxt->value->type == XPATH_LOCATIONSET) {
13072 xmlXPathObjectPtr tmp = NULL;
13073 xmlLocationSetPtr newlocset = NULL;
13074 xmlLocationSetPtr oldlocset;
13077 * Extract the old locset, and then evaluate the result of the
13078 * expression for all the element in the locset. use it to grow
13081 CHECK_TYPE0(XPATH_LOCATIONSET);
13082 obj = valuePop(ctxt);
13083 oldlocset = obj->user;
13084 ctxt->context->node = NULL;
13086 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13087 ctxt->context->contextSize = 0;
13088 ctxt->context->proximityPosition = 0;
13090 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13091 res = valuePop(ctxt);
13093 xmlXPathReleaseObject(ctxt->context, res);
13095 valuePush(ctxt, obj);
13099 newlocset = xmlXPtrLocationSetCreate(NULL);
13101 for (i = 0; i < oldlocset->locNr; i++) {
13103 * Run the evaluation with a node list made of a
13104 * single item in the nodelocset.
13106 ctxt->context->node = oldlocset->locTab[i]->user;
13107 ctxt->context->contextSize = oldlocset->locNr;
13108 ctxt->context->proximityPosition = i + 1;
13110 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13111 ctxt->context->node);
13113 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13114 ctxt->context->node) < 0) {
13115 ctxt->error = XPATH_MEMORY_ERROR;
13118 valuePush(ctxt, tmp);
13120 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13121 if (ctxt->error != XPATH_EXPRESSION_OK) {
13122 xmlXPathFreeObject(obj);
13126 * The result of the evaluation need to be tested to
13127 * decided whether the filter succeeded or not
13129 res = valuePop(ctxt);
13130 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13131 xmlXPtrLocationSetAdd(newlocset,
13132 xmlXPathCacheObjectCopy(ctxt->context,
13133 oldlocset->locTab[i]));
13139 xmlXPathReleaseObject(ctxt->context, res);
13141 if (ctxt->value == tmp) {
13143 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13145 * REVISIT TODO: Don't create a temporary nodeset
13146 * for everly iteration.
13148 /* OLD: xmlXPathFreeObject(res); */
13151 ctxt->context->node = NULL;
13153 * Only put the first node in the result, then leave.
13155 if (newlocset->locNr > 0) {
13156 *first = (xmlNodePtr) oldlocset->locTab[i]->user;
13161 xmlXPathReleaseObject(ctxt->context, tmp);
13164 * The result is used as the new evaluation locset.
13166 xmlXPathReleaseObject(ctxt->context, obj);
13167 ctxt->context->node = NULL;
13168 ctxt->context->contextSize = -1;
13169 ctxt->context->proximityPosition = -1;
13170 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13171 ctxt->context->node = oldnode;
13174 #endif /* LIBXML_XPTR_ENABLED */
13177 * Extract the old set, and then evaluate the result of the
13178 * expression for all the element in the set. use it to grow
13181 CHECK_TYPE0(XPATH_NODESET);
13182 obj = valuePop(ctxt);
13183 oldset = obj->nodesetval;
13185 oldnode = ctxt->context->node;
13186 oldDoc = ctxt->context->doc;
13187 ctxt->context->node = NULL;
13189 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13190 ctxt->context->contextSize = 0;
13191 ctxt->context->proximityPosition = 0;
13192 /* QUESTION TODO: Why was this code commented out?
13195 xmlXPathCompOpEval(ctxt,
13196 &comp->steps[op->ch2]);
13198 res = valuePop(ctxt);
13200 xmlXPathFreeObject(res);
13202 valuePush(ctxt, obj);
13203 ctxt->context->node = oldnode;
13206 xmlNodeSetPtr newset;
13207 xmlXPathObjectPtr tmp = NULL;
13209 * Initialize the new set.
13210 * Also set the xpath document in case things like
13211 * key() evaluation are attempted on the predicate
13213 newset = xmlXPathNodeSetCreate(NULL);
13214 /* XXX what if xmlXPathNodeSetCreate returned NULL? */
13216 for (i = 0; i < oldset->nodeNr; i++) {
13218 * Run the evaluation with a node list made of
13219 * a single item in the nodeset.
13221 ctxt->context->node = oldset->nodeTab[i];
13222 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13223 (oldset->nodeTab[i]->doc != NULL))
13224 ctxt->context->doc = oldset->nodeTab[i]->doc;
13226 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13227 ctxt->context->node);
13229 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13230 ctxt->context->node) < 0) {
13231 ctxt->error = XPATH_MEMORY_ERROR;
13234 valuePush(ctxt, tmp);
13235 ctxt->context->contextSize = oldset->nodeNr;
13236 ctxt->context->proximityPosition = i + 1;
13238 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13239 if (ctxt->error != XPATH_EXPRESSION_OK) {
13240 xmlXPathFreeNodeSet(newset);
13241 xmlXPathFreeObject(obj);
13245 * The result of the evaluation needs to be tested to
13246 * decide whether the filter succeeded or not
13248 res = valuePop(ctxt);
13249 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13250 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
13251 ctxt->error = XPATH_MEMORY_ERROR;
13257 xmlXPathReleaseObject(ctxt->context, res);
13259 if (ctxt->value == tmp) {
13262 * Don't free the temporary nodeset
13263 * in order to avoid massive recreation inside this
13266 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13269 ctxt->context->node = NULL;
13271 * Only put the first node in the result, then leave.
13273 if (newset->nodeNr > 0) {
13274 *first = *(newset->nodeTab);
13279 xmlXPathReleaseObject(ctxt->context, tmp);
13282 * The result is used as the new evaluation set.
13284 xmlXPathReleaseObject(ctxt->context, obj);
13285 ctxt->context->node = NULL;
13286 ctxt->context->contextSize = -1;
13287 ctxt->context->proximityPosition = -1;
13288 /* may want to move this past the '}' later */
13289 ctxt->context->doc = oldDoc;
13290 valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, newset));
13292 ctxt->context->node = oldnode;
13295 #endif /* XP_OPTIMIZED_FILTER_FIRST */
13298 * xmlXPathCompOpEval:
13299 * @ctxt: the XPath parser context with the compiled expression
13300 * @op: an XPath compiled operation
13302 * Evaluate the Precompiled XPath operation
13303 * Returns the number of nodes traversed
13306 xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
13310 xmlXPathCompExprPtr comp;
13311 xmlXPathObjectPtr arg1, arg2;
13323 bakd = ctxt->context->doc;
13324 bak = ctxt->context->node;
13325 pp = ctxt->context->proximityPosition;
13326 cs = ctxt->context->contextSize;
13327 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13329 xmlXPathBooleanFunction(ctxt, 1);
13330 if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
13332 arg2 = valuePop(ctxt);
13333 ctxt->context->doc = bakd;
13334 ctxt->context->node = bak;
13335 ctxt->context->proximityPosition = pp;
13336 ctxt->context->contextSize = cs;
13337 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13339 xmlXPathFreeObject(arg2);
13342 xmlXPathBooleanFunction(ctxt, 1);
13343 arg1 = valuePop(ctxt);
13344 arg1->boolval &= arg2->boolval;
13345 valuePush(ctxt, arg1);
13346 xmlXPathReleaseObject(ctxt->context, arg2);
13349 bakd = ctxt->context->doc;
13350 bak = ctxt->context->node;
13351 pp = ctxt->context->proximityPosition;
13352 cs = ctxt->context->contextSize;
13353 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13355 xmlXPathBooleanFunction(ctxt, 1);
13356 if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
13358 arg2 = valuePop(ctxt);
13359 ctxt->context->doc = bakd;
13360 ctxt->context->node = bak;
13361 ctxt->context->proximityPosition = pp;
13362 ctxt->context->contextSize = cs;
13363 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13365 xmlXPathFreeObject(arg2);
13368 xmlXPathBooleanFunction(ctxt, 1);
13369 arg1 = valuePop(ctxt);
13370 arg1->boolval |= arg2->boolval;
13371 valuePush(ctxt, arg1);
13372 xmlXPathReleaseObject(ctxt->context, arg2);
13374 case XPATH_OP_EQUAL:
13375 bakd = ctxt->context->doc;
13376 bak = ctxt->context->node;
13377 pp = ctxt->context->proximityPosition;
13378 cs = ctxt->context->contextSize;
13379 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13381 ctxt->context->doc = bakd;
13382 ctxt->context->node = bak;
13383 ctxt->context->proximityPosition = pp;
13384 ctxt->context->contextSize = cs;
13385 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13388 equal = xmlXPathEqualValues(ctxt);
13390 equal = xmlXPathNotEqualValues(ctxt);
13391 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
13394 bakd = ctxt->context->doc;
13395 bak = ctxt->context->node;
13396 pp = ctxt->context->proximityPosition;
13397 cs = ctxt->context->contextSize;
13398 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13400 ctxt->context->doc = bakd;
13401 ctxt->context->node = bak;
13402 ctxt->context->proximityPosition = pp;
13403 ctxt->context->contextSize = cs;
13404 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13406 ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
13407 valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
13409 case XPATH_OP_PLUS:
13410 bakd = ctxt->context->doc;
13411 bak = ctxt->context->node;
13412 pp = ctxt->context->proximityPosition;
13413 cs = ctxt->context->contextSize;
13414 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13416 if (op->ch2 != -1) {
13417 ctxt->context->doc = bakd;
13418 ctxt->context->node = bak;
13419 ctxt->context->proximityPosition = pp;
13420 ctxt->context->contextSize = cs;
13421 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13424 if (op->value == 0)
13425 xmlXPathSubValues(ctxt);
13426 else if (op->value == 1)
13427 xmlXPathAddValues(ctxt);
13428 else if (op->value == 2)
13429 xmlXPathValueFlipSign(ctxt);
13430 else if (op->value == 3) {
13432 CHECK_TYPE0(XPATH_NUMBER);
13435 case XPATH_OP_MULT:
13436 bakd = ctxt->context->doc;
13437 bak = ctxt->context->node;
13438 pp = ctxt->context->proximityPosition;
13439 cs = ctxt->context->contextSize;
13440 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13442 ctxt->context->doc = bakd;
13443 ctxt->context->node = bak;
13444 ctxt->context->proximityPosition = pp;
13445 ctxt->context->contextSize = cs;
13446 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13448 if (op->value == 0)
13449 xmlXPathMultValues(ctxt);
13450 else if (op->value == 1)
13451 xmlXPathDivValues(ctxt);
13452 else if (op->value == 2)
13453 xmlXPathModValues(ctxt);
13455 case XPATH_OP_UNION:
13456 bakd = ctxt->context->doc;
13457 bak = ctxt->context->node;
13458 pp = ctxt->context->proximityPosition;
13459 cs = ctxt->context->contextSize;
13460 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13462 ctxt->context->doc = bakd;
13463 ctxt->context->node = bak;
13464 ctxt->context->proximityPosition = pp;
13465 ctxt->context->contextSize = cs;
13466 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13469 arg2 = valuePop(ctxt);
13470 arg1 = valuePop(ctxt);
13471 if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
13472 (arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
13473 xmlXPathReleaseObject(ctxt->context, arg1);
13474 xmlXPathReleaseObject(ctxt->context, arg2);
13475 XP_ERROR0(XPATH_INVALID_TYPE);
13478 if ((arg1->nodesetval == NULL) ||
13479 ((arg2->nodesetval != NULL) &&
13480 (arg2->nodesetval->nodeNr != 0)))
13482 arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
13486 valuePush(ctxt, arg1);
13487 xmlXPathReleaseObject(ctxt->context, arg2);
13489 case XPATH_OP_ROOT:
13490 xmlXPathRoot(ctxt);
13492 case XPATH_OP_NODE:
13494 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13497 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13499 valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
13500 ctxt->context->node));
13502 case XPATH_OP_RESET:
13504 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13507 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13509 ctxt->context->node = NULL;
13511 case XPATH_OP_COLLECT:{
13515 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13518 total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
13521 case XPATH_OP_VALUE:
13523 xmlXPathCacheObjectCopy(ctxt->context,
13524 (xmlXPathObjectPtr) op->value4));
13526 case XPATH_OP_VARIABLE:{
13527 xmlXPathObjectPtr val;
13531 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13532 if (op->value5 == NULL) {
13533 val = xmlXPathVariableLookup(ctxt->context, op->value4);
13535 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13536 valuePush(ctxt, val);
13538 const xmlChar *URI;
13540 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13542 xmlGenericError(xmlGenericErrorContext,
13543 "xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
13544 (char *) op->value4, (char *)op->value5);
13545 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13548 val = xmlXPathVariableLookupNS(ctxt->context,
13551 XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
13552 valuePush(ctxt, val);
13556 case XPATH_OP_FUNCTION:{
13557 xmlXPathFunction func;
13558 const xmlChar *oldFunc, *oldFuncURI;
13562 frame = xmlXPathSetFrame(ctxt);
13563 if (op->ch1 != -1) {
13565 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13566 if (ctxt->error != XPATH_EXPRESSION_OK) {
13567 xmlXPathPopFrame(ctxt, frame);
13571 if (ctxt->valueNr < ctxt->valueFrame + op->value) {
13572 xmlGenericError(xmlGenericErrorContext,
13573 "xmlXPathCompOpEval: parameter error\n");
13574 ctxt->error = XPATH_INVALID_OPERAND;
13575 xmlXPathPopFrame(ctxt, frame);
13578 for (i = 0; i < op->value; i++) {
13579 if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
13580 xmlGenericError(xmlGenericErrorContext,
13581 "xmlXPathCompOpEval: parameter error\n");
13582 ctxt->error = XPATH_INVALID_OPERAND;
13583 xmlXPathPopFrame(ctxt, frame);
13587 if (op->cache != NULL)
13590 const xmlChar *URI = NULL;
13592 if (op->value5 == NULL)
13594 xmlXPathFunctionLookup(ctxt->context,
13597 URI = xmlXPathNsLookup(ctxt->context, op->value5);
13599 xmlGenericError(xmlGenericErrorContext,
13600 "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
13601 (char *)op->value4, (char *)op->value5);
13602 xmlXPathPopFrame(ctxt, frame);
13603 ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
13606 func = xmlXPathFunctionLookupNS(ctxt->context,
13609 if (func == NULL) {
13610 xmlGenericError(xmlGenericErrorContext,
13611 "xmlXPathCompOpEval: function %s not found\n",
13612 (char *)op->value4);
13613 XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
13616 op->cacheURI = (void *) URI;
13618 oldFunc = ctxt->context->function;
13619 oldFuncURI = ctxt->context->functionURI;
13620 ctxt->context->function = op->value4;
13621 ctxt->context->functionURI = op->cacheURI;
13622 func(ctxt, op->value);
13623 ctxt->context->function = oldFunc;
13624 ctxt->context->functionURI = oldFuncURI;
13625 xmlXPathPopFrame(ctxt, frame);
13629 bakd = ctxt->context->doc;
13630 bak = ctxt->context->node;
13631 pp = ctxt->context->proximityPosition;
13632 cs = ctxt->context->contextSize;
13633 if (op->ch1 != -1) {
13634 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13635 ctxt->context->contextSize = cs;
13636 ctxt->context->proximityPosition = pp;
13637 ctxt->context->node = bak;
13638 ctxt->context->doc = bakd;
13641 if (op->ch2 != -1) {
13642 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
13643 ctxt->context->contextSize = cs;
13644 ctxt->context->proximityPosition = pp;
13645 ctxt->context->node = bak;
13646 ctxt->context->doc = bakd;
13650 case XPATH_OP_PREDICATE:
13651 case XPATH_OP_FILTER:{
13652 xmlXPathObjectPtr res;
13653 xmlXPathObjectPtr obj, tmp;
13654 xmlNodeSetPtr newset = NULL;
13655 xmlNodeSetPtr oldset;
13656 xmlNodePtr oldnode;
13661 * Optimization for ()[1] selection i.e. the first elem
13663 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13664 #ifdef XP_OPTIMIZED_FILTER_FIRST
13666 * FILTER TODO: Can we assume that the inner processing
13667 * will result in an ordered list if we have an
13669 * What about an additional field or flag on
13670 * xmlXPathObject like @sorted ? This way we wouln'd need
13671 * to assume anything, so it would be more robust and
13672 * easier to optimize.
13674 ((comp->steps[op->ch1].op == XPATH_OP_SORT) || /* 18 */
13675 (comp->steps[op->ch1].op == XPATH_OP_FILTER)) && /* 17 */
13677 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13679 (comp->steps[op->ch2].op == XPATH_OP_VALUE)) { /* 12 */
13680 xmlXPathObjectPtr val;
13682 val = comp->steps[op->ch2].value4;
13683 if ((val != NULL) && (val->type == XPATH_NUMBER) &&
13684 (val->floatval == 1.0)) {
13685 xmlNodePtr first = NULL;
13688 xmlXPathCompOpEvalFirst(ctxt,
13689 &comp->steps[op->ch1],
13693 * The nodeset should be in document order,
13694 * Keep only the first value
13696 if ((ctxt->value != NULL) &&
13697 (ctxt->value->type == XPATH_NODESET) &&
13698 (ctxt->value->nodesetval != NULL) &&
13699 (ctxt->value->nodesetval->nodeNr > 1))
13700 xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
13706 * Optimization for ()[last()] selection i.e. the last elem
13708 if ((op->ch1 != -1) && (op->ch2 != -1) &&
13709 (comp->steps[op->ch1].op == XPATH_OP_SORT) &&
13710 (comp->steps[op->ch2].op == XPATH_OP_SORT)) {
13711 int f = comp->steps[op->ch2].ch1;
13714 (comp->steps[f].op == XPATH_OP_FUNCTION) &&
13715 (comp->steps[f].value5 == NULL) &&
13716 (comp->steps[f].value == 0) &&
13717 (comp->steps[f].value4 != NULL) &&
13719 (comp->steps[f].value4, BAD_CAST "last"))) {
13720 xmlNodePtr last = NULL;
13723 xmlXPathCompOpEvalLast(ctxt,
13724 &comp->steps[op->ch1],
13728 * The nodeset should be in document order,
13729 * Keep only the last value
13731 if ((ctxt->value != NULL) &&
13732 (ctxt->value->type == XPATH_NODESET) &&
13733 (ctxt->value->nodesetval != NULL) &&
13734 (ctxt->value->nodesetval->nodeTab != NULL) &&
13735 (ctxt->value->nodesetval->nodeNr > 1))
13736 xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
13741 * Process inner predicates first.
13742 * Example "index[parent::book][1]":
13744 * PREDICATE <-- we are here "[1]"
13745 * PREDICATE <-- process "[parent::book]" first
13747 * COLLECT 'parent' 'name' 'node' book
13749 * ELEM Object is a number : 1
13753 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
13757 if (ctxt->value == NULL)
13760 oldnode = ctxt->context->node;
13762 #ifdef LIBXML_XPTR_ENABLED
13764 * Hum are we filtering the result of an XPointer expression
13766 if (ctxt->value->type == XPATH_LOCATIONSET) {
13767 xmlLocationSetPtr newlocset = NULL;
13768 xmlLocationSetPtr oldlocset;
13771 * Extract the old locset, and then evaluate the result of the
13772 * expression for all the element in the locset. use it to grow
13775 CHECK_TYPE0(XPATH_LOCATIONSET);
13776 obj = valuePop(ctxt);
13777 oldlocset = obj->user;
13778 ctxt->context->node = NULL;
13780 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
13781 ctxt->context->contextSize = 0;
13782 ctxt->context->proximityPosition = 0;
13785 xmlXPathCompOpEval(ctxt,
13786 &comp->steps[op->ch2]);
13787 res = valuePop(ctxt);
13789 xmlXPathReleaseObject(ctxt->context, res);
13791 valuePush(ctxt, obj);
13795 newlocset = xmlXPtrLocationSetCreate(NULL);
13797 for (i = 0; i < oldlocset->locNr; i++) {
13799 * Run the evaluation with a node list made of a
13800 * single item in the nodelocset.
13802 ctxt->context->node = oldlocset->locTab[i]->user;
13803 ctxt->context->contextSize = oldlocset->locNr;
13804 ctxt->context->proximityPosition = i + 1;
13805 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13806 ctxt->context->node);
13807 valuePush(ctxt, tmp);
13811 xmlXPathCompOpEval(ctxt,
13812 &comp->steps[op->ch2]);
13813 if (ctxt->error != XPATH_EXPRESSION_OK) {
13814 xmlXPathFreeObject(obj);
13819 * The result of the evaluation need to be tested to
13820 * decided whether the filter succeeded or not
13822 res = valuePop(ctxt);
13823 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13824 xmlXPtrLocationSetAdd(newlocset,
13826 (oldlocset->locTab[i]));
13833 xmlXPathReleaseObject(ctxt->context, res);
13835 if (ctxt->value == tmp) {
13836 res = valuePop(ctxt);
13837 xmlXPathReleaseObject(ctxt->context, res);
13840 ctxt->context->node = NULL;
13844 * The result is used as the new evaluation locset.
13846 xmlXPathReleaseObject(ctxt->context, obj);
13847 ctxt->context->node = NULL;
13848 ctxt->context->contextSize = -1;
13849 ctxt->context->proximityPosition = -1;
13850 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
13851 ctxt->context->node = oldnode;
13854 #endif /* LIBXML_XPTR_ENABLED */
13857 * Extract the old set, and then evaluate the result of the
13858 * expression for all the element in the set. use it to grow
13861 CHECK_TYPE0(XPATH_NODESET);
13862 obj = valuePop(ctxt);
13863 oldset = obj->nodesetval;
13865 oldnode = ctxt->context->node;
13866 oldDoc = ctxt->context->doc;
13867 ctxt->context->node = NULL;
13869 if ((oldset == NULL) || (oldset->nodeNr == 0)) {
13870 ctxt->context->contextSize = 0;
13871 ctxt->context->proximityPosition = 0;
13875 xmlXPathCompOpEval(ctxt,
13876 &comp->steps[op->ch2]);
13878 res = valuePop(ctxt);
13880 xmlXPathFreeObject(res);
13882 valuePush(ctxt, obj);
13883 ctxt->context->node = oldnode;
13888 * Initialize the new set.
13889 * Also set the xpath document in case things like
13890 * key() evaluation are attempted on the predicate
13892 newset = xmlXPathNodeSetCreate(NULL);
13895 * "For each node in the node-set to be filtered, the
13896 * PredicateExpr is evaluated with that node as the
13897 * context node, with the number of nodes in the
13898 * node-set as the context size, and with the proximity
13899 * position of the node in the node-set with respect to
13900 * the axis as the context position;"
13901 * @oldset is the node-set" to be filtered.
13904 * "only predicates change the context position and
13905 * context size (see [2.4 Predicates])."
13907 * node-set context pos
13911 * After applying predicate [position() > 1] :
13912 * node-set context pos
13916 * removed the first node in the node-set, then
13917 * the context position of the
13919 for (i = 0; i < oldset->nodeNr; i++) {
13921 * Run the evaluation with a node list made of
13922 * a single item in the nodeset.
13924 ctxt->context->node = oldset->nodeTab[i];
13925 if ((oldset->nodeTab[i]->type != XML_NAMESPACE_DECL) &&
13926 (oldset->nodeTab[i]->doc != NULL))
13927 ctxt->context->doc = oldset->nodeTab[i]->doc;
13929 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
13930 ctxt->context->node);
13932 if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
13933 ctxt->context->node) < 0) {
13934 ctxt->error = XPATH_MEMORY_ERROR;
13937 valuePush(ctxt, tmp);
13938 ctxt->context->contextSize = oldset->nodeNr;
13939 ctxt->context->proximityPosition = i + 1;
13941 * Evaluate the predicate against the context node.
13942 * Can/should we optimize position() predicates
13943 * here (e.g. "[1]")?
13947 xmlXPathCompOpEval(ctxt,
13948 &comp->steps[op->ch2]);
13949 if (ctxt->error != XPATH_EXPRESSION_OK) {
13950 xmlXPathFreeNodeSet(newset);
13951 xmlXPathFreeObject(obj);
13956 * The result of the evaluation needs to be tested to
13957 * decide whether the filter succeeded or not
13960 * OPTIMIZE TODO: Can we use
13961 * xmlXPathNodeSetAdd*Unique()* instead?
13963 res = valuePop(ctxt);
13964 if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
13965 if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
13967 ctxt->error = XPATH_MEMORY_ERROR;
13974 xmlXPathReleaseObject(ctxt->context, res);
13976 if (ctxt->value == tmp) {
13978 xmlXPathNodeSetClear(tmp->nodesetval, 1);
13980 * Don't free the temporary nodeset
13981 * in order to avoid massive recreation inside this
13986 ctxt->context->node = NULL;
13989 xmlXPathReleaseObject(ctxt->context, tmp);
13991 * The result is used as the new evaluation set.
13993 xmlXPathReleaseObject(ctxt->context, obj);
13994 ctxt->context->node = NULL;
13995 ctxt->context->contextSize = -1;
13996 ctxt->context->proximityPosition = -1;
13997 /* may want to move this past the '}' later */
13998 ctxt->context->doc = oldDoc;
14000 xmlXPathCacheWrapNodeSet(ctxt->context, newset));
14002 ctxt->context->node = oldnode;
14005 case XPATH_OP_SORT:
14007 total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14009 if ((ctxt->value != NULL) &&
14010 (ctxt->value->type == XPATH_NODESET) &&
14011 (ctxt->value->nodesetval != NULL) &&
14012 (ctxt->value->nodesetval->nodeNr > 1))
14014 xmlXPathNodeSetSort(ctxt->value->nodesetval);
14017 #ifdef LIBXML_XPTR_ENABLED
14018 case XPATH_OP_RANGETO:{
14019 xmlXPathObjectPtr range;
14020 xmlXPathObjectPtr res, obj;
14021 xmlXPathObjectPtr tmp;
14022 xmlLocationSetPtr newlocset = NULL;
14023 xmlLocationSetPtr oldlocset;
14024 xmlNodeSetPtr oldset;
14027 if (op->ch1 != -1) {
14029 xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
14032 if (ctxt->value == NULL) {
14033 XP_ERROR0(XPATH_INVALID_OPERAND);
14038 if (ctxt->value->type == XPATH_LOCATIONSET) {
14040 * Extract the old locset, and then evaluate the result of the
14041 * expression for all the element in the locset. use it to grow
14044 CHECK_TYPE0(XPATH_LOCATIONSET);
14045 obj = valuePop(ctxt);
14046 oldlocset = obj->user;
14048 if ((oldlocset == NULL) || (oldlocset->locNr == 0)) {
14049 ctxt->context->node = NULL;
14050 ctxt->context->contextSize = 0;
14051 ctxt->context->proximityPosition = 0;
14052 total += xmlXPathCompOpEval(ctxt,&comp->steps[op->ch2]);
14053 res = valuePop(ctxt);
14055 xmlXPathReleaseObject(ctxt->context, res);
14057 valuePush(ctxt, obj);
14061 newlocset = xmlXPtrLocationSetCreate(NULL);
14063 for (i = 0; i < oldlocset->locNr; i++) {
14065 * Run the evaluation with a node list made of a
14066 * single item in the nodelocset.
14068 ctxt->context->node = oldlocset->locTab[i]->user;
14069 ctxt->context->contextSize = oldlocset->locNr;
14070 ctxt->context->proximityPosition = i + 1;
14071 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14072 ctxt->context->node);
14073 valuePush(ctxt, tmp);
14077 xmlXPathCompOpEval(ctxt,
14078 &comp->steps[op->ch2]);
14079 if (ctxt->error != XPATH_EXPRESSION_OK) {
14080 xmlXPathFreeObject(obj);
14084 res = valuePop(ctxt);
14085 if (res->type == XPATH_LOCATIONSET) {
14086 xmlLocationSetPtr rloc =
14087 (xmlLocationSetPtr)res->user;
14088 for (j=0; j<rloc->locNr; j++) {
14089 range = xmlXPtrNewRange(
14090 oldlocset->locTab[i]->user,
14091 oldlocset->locTab[i]->index,
14092 rloc->locTab[j]->user2,
14093 rloc->locTab[j]->index2);
14094 if (range != NULL) {
14095 xmlXPtrLocationSetAdd(newlocset, range);
14099 range = xmlXPtrNewRangeNodeObject(
14100 (xmlNodePtr)oldlocset->locTab[i]->user, res);
14101 if (range != NULL) {
14102 xmlXPtrLocationSetAdd(newlocset,range);
14110 xmlXPathReleaseObject(ctxt->context, res);
14112 if (ctxt->value == tmp) {
14113 res = valuePop(ctxt);
14114 xmlXPathReleaseObject(ctxt->context, res);
14117 ctxt->context->node = NULL;
14119 } else { /* Not a location set */
14120 CHECK_TYPE0(XPATH_NODESET);
14121 obj = valuePop(ctxt);
14122 oldset = obj->nodesetval;
14123 ctxt->context->node = NULL;
14125 newlocset = xmlXPtrLocationSetCreate(NULL);
14127 if (oldset != NULL) {
14128 for (i = 0; i < oldset->nodeNr; i++) {
14130 * Run the evaluation with a node list made of a single item
14133 ctxt->context->node = oldset->nodeTab[i];
14135 * OPTIMIZE TODO: Avoid recreation for every iteration.
14137 tmp = xmlXPathCacheNewNodeSet(ctxt->context,
14138 ctxt->context->node);
14139 valuePush(ctxt, tmp);
14143 xmlXPathCompOpEval(ctxt,
14144 &comp->steps[op->ch2]);
14145 if (ctxt->error != XPATH_EXPRESSION_OK) {
14146 xmlXPathFreeObject(obj);
14150 res = valuePop(ctxt);
14152 xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
14154 if (range != NULL) {
14155 xmlXPtrLocationSetAdd(newlocset, range);
14162 xmlXPathReleaseObject(ctxt->context, res);
14164 if (ctxt->value == tmp) {
14165 res = valuePop(ctxt);
14166 xmlXPathReleaseObject(ctxt->context, res);
14169 ctxt->context->node = NULL;
14175 * The result is used as the new evaluation set.
14177 xmlXPathReleaseObject(ctxt->context, obj);
14178 ctxt->context->node = NULL;
14179 ctxt->context->contextSize = -1;
14180 ctxt->context->proximityPosition = -1;
14181 valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
14184 #endif /* LIBXML_XPTR_ENABLED */
14186 xmlGenericError(xmlGenericErrorContext,
14187 "XPath: unknown precompiled operation %d\n", op->op);
14188 ctxt->error = XPATH_INVALID_OPERAND;
14193 * xmlXPathCompOpEvalToBoolean:
14194 * @ctxt: the XPath parser context
14196 * Evaluates if the expression evaluates to true.
14198 * Returns 1 if true, 0 if false and -1 on API or internal errors.
14201 xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
14202 xmlXPathStepOpPtr op,
14205 xmlXPathObjectPtr resObj = NULL;
14208 /* comp = ctxt->comp; */
14212 case XPATH_OP_VALUE:
14213 resObj = (xmlXPathObjectPtr) op->value4;
14215 return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
14216 return(xmlXPathCastToBoolean(resObj));
14217 case XPATH_OP_SORT:
14219 * We don't need sorting for boolean results. Skip this one.
14221 if (op->ch1 != -1) {
14222 op = &ctxt->comp->steps[op->ch1];
14226 case XPATH_OP_COLLECT:
14230 xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
14231 if (ctxt->error != XPATH_EXPRESSION_OK)
14234 xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
14235 if (ctxt->error != XPATH_EXPRESSION_OK)
14238 resObj = valuePop(ctxt);
14239 if (resObj == NULL)
14244 * Fallback to call xmlXPathCompOpEval().
14246 xmlXPathCompOpEval(ctxt, op);
14247 if (ctxt->error != XPATH_EXPRESSION_OK)
14250 resObj = valuePop(ctxt);
14251 if (resObj == NULL)
14259 if (resObj->type == XPATH_BOOLEAN) {
14260 res = resObj->boolval;
14261 } else if (isPredicate) {
14263 * For predicates a result of type "number" is handled
14266 * "If the result is a number, the result will be converted
14267 * to true if the number is equal to the context position
14268 * and will be converted to false otherwise;"
14270 res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
14272 res = xmlXPathCastToBoolean(resObj);
14274 xmlXPathReleaseObject(ctxt->context, resObj);
14281 #ifdef XPATH_STREAMING
14283 * xmlXPathRunStreamEval:
14284 * @ctxt: the XPath parser context with the compiled expression
14286 * Evaluate the Precompiled Streamable XPath expression in the given context.
14289 xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
14290 xmlXPathObjectPtr *resultSeq, int toBool)
14292 int max_depth, min_depth;
14295 int eval_all_nodes;
14296 xmlNodePtr cur = NULL, limit = NULL;
14297 xmlStreamCtxtPtr patstream = NULL;
14301 if ((ctxt == NULL) || (comp == NULL))
14303 max_depth = xmlPatternMaxDepth(comp);
14304 if (max_depth == -1)
14306 if (max_depth == -2)
14308 min_depth = xmlPatternMinDepth(comp);
14309 if (min_depth == -1)
14311 from_root = xmlPatternFromRoot(comp);
14315 printf("stream eval: depth %d from root %d\n", max_depth, from_root);
14319 if (resultSeq == NULL)
14321 *resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
14322 if (*resultSeq == NULL)
14327 * handle the special cases of "/" amd "." being matched
14329 if (min_depth == 0) {
14334 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
14335 (xmlNodePtr) ctxt->doc);
14337 /* Select "self::node()" */
14340 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
14343 if (max_depth == 0) {
14348 cur = (xmlNodePtr)ctxt->doc;
14349 } else if (ctxt->node != NULL) {
14350 switch (ctxt->node->type) {
14351 case XML_ELEMENT_NODE:
14352 case XML_DOCUMENT_NODE:
14353 case XML_DOCUMENT_FRAG_NODE:
14354 case XML_HTML_DOCUMENT_NODE:
14355 #ifdef LIBXML_DOCB_ENABLED
14356 case XML_DOCB_DOCUMENT_NODE:
14360 case XML_ATTRIBUTE_NODE:
14361 case XML_TEXT_NODE:
14362 case XML_CDATA_SECTION_NODE:
14363 case XML_ENTITY_REF_NODE:
14364 case XML_ENTITY_NODE:
14366 case XML_COMMENT_NODE:
14367 case XML_NOTATION_NODE:
14369 case XML_DOCUMENT_TYPE_NODE:
14370 case XML_ELEMENT_DECL:
14371 case XML_ATTRIBUTE_DECL:
14372 case XML_ENTITY_DECL:
14373 case XML_NAMESPACE_DECL:
14374 case XML_XINCLUDE_START:
14375 case XML_XINCLUDE_END:
14384 patstream = xmlPatternGetStreamCtxt(comp);
14385 if (patstream == NULL) {
14387 * QUESTION TODO: Is this an error?
14392 eval_all_nodes = xmlStreamWantsAnyNode(patstream);
14395 ret = xmlStreamPush(patstream, NULL, NULL);
14397 } else if (ret == 1) {
14400 xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
14404 goto scan_children;
14409 switch (cur->type) {
14410 case XML_ELEMENT_NODE:
14411 case XML_TEXT_NODE:
14412 case XML_CDATA_SECTION_NODE:
14413 case XML_COMMENT_NODE:
14415 if (cur->type == XML_ELEMENT_NODE) {
14416 ret = xmlStreamPush(patstream, cur->name,
14417 (cur->ns ? cur->ns->href : NULL));
14418 } else if (eval_all_nodes)
14419 ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
14425 } else if (ret == 1) {
14428 if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
14430 ctxt->lastError.domain = XML_FROM_XPATH;
14431 ctxt->lastError.code = XML_ERR_NO_MEMORY;
14434 if ((cur->children == NULL) || (depth >= max_depth)) {
14435 ret = xmlStreamPop(patstream);
14436 while (cur->next != NULL) {
14438 if ((cur->type != XML_ENTITY_DECL) &&
14439 (cur->type != XML_DTD_NODE))
14448 if (cur->type == XML_NAMESPACE_DECL) break;
14449 if ((cur->children != NULL) && (depth < max_depth)) {
14451 * Do not descend on entities declarations
14453 if (cur->children->type != XML_ENTITY_DECL) {
14454 cur = cur->children;
14459 if (cur->type != XML_DTD_NODE)
14467 while (cur->next != NULL) {
14469 if ((cur->type != XML_ENTITY_DECL) &&
14470 (cur->type != XML_DTD_NODE))
14477 if ((cur == NULL) || (cur == limit))
14479 if (cur->type == XML_ELEMENT_NODE) {
14480 ret = xmlStreamPop(patstream);
14481 } else if ((eval_all_nodes) &&
14482 ((cur->type == XML_TEXT_NODE) ||
14483 (cur->type == XML_CDATA_SECTION_NODE) ||
14484 (cur->type == XML_COMMENT_NODE) ||
14485 (cur->type == XML_PI_NODE)))
14487 ret = xmlStreamPop(patstream);
14489 if (cur->next != NULL) {
14493 } while (cur != NULL);
14495 } while ((cur != NULL) && (depth >= 0));
14500 printf("stream eval: checked %d nodes selected %d\n",
14501 nb_nodes, retObj->nodesetval->nodeNr);
14505 xmlFreeStreamCtxt(patstream);
14510 xmlFreeStreamCtxt(patstream);
14513 #endif /* XPATH_STREAMING */
14517 * @ctxt: the XPath parser context with the compiled expression
14518 * @toBool: evaluate to a boolean result
14520 * Evaluate the Precompiled XPath expression in the given context.
14523 xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
14525 xmlXPathCompExprPtr comp;
14527 if ((ctxt == NULL) || (ctxt->comp == NULL))
14530 if (ctxt->valueTab == NULL) {
14531 /* Allocate the value stack */
14532 ctxt->valueTab = (xmlXPathObjectPtr *)
14533 xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
14534 if (ctxt->valueTab == NULL) {
14535 xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
14539 ctxt->valueMax = 10;
14540 ctxt->value = NULL;
14541 ctxt->valueFrame = 0;
14543 #ifdef XPATH_STREAMING
14544 if (ctxt->comp->stream) {
14549 * Evaluation to boolean result.
14551 res = xmlXPathRunStreamEval(ctxt->context,
14552 ctxt->comp->stream, NULL, 1);
14556 xmlXPathObjectPtr resObj = NULL;
14559 * Evaluation to a sequence.
14561 res = xmlXPathRunStreamEval(ctxt->context,
14562 ctxt->comp->stream, &resObj, 0);
14564 if ((res != -1) && (resObj != NULL)) {
14565 valuePush(ctxt, resObj);
14568 if (resObj != NULL)
14569 xmlXPathReleaseObject(ctxt->context, resObj);
14572 * QUESTION TODO: This falls back to normal XPath evaluation
14573 * if res == -1. Is this intended?
14578 if (comp->last < 0) {
14579 xmlGenericError(xmlGenericErrorContext,
14580 "xmlXPathRunEval: last is less than zero\n");
14584 return(xmlXPathCompOpEvalToBoolean(ctxt,
14585 &comp->steps[comp->last], 0));
14587 xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
14592 /************************************************************************
14594 * Public interfaces *
14596 ************************************************************************/
14599 * xmlXPathEvalPredicate:
14600 * @ctxt: the XPath context
14601 * @res: the Predicate Expression evaluation result
14603 * Evaluate a predicate result for the current node.
14604 * A PredicateExpr is evaluated by evaluating the Expr and converting
14605 * the result to a boolean. If the result is a number, the result will
14606 * be converted to true if the number is equal to the position of the
14607 * context node in the context node list (as returned by the position
14608 * function) and will be converted to false otherwise; if the result
14609 * is not a number, then the result will be converted as if by a call
14610 * to the boolean function.
14612 * Returns 1 if predicate is true, 0 otherwise
14615 xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
14616 if ((ctxt == NULL) || (res == NULL)) return(0);
14617 switch (res->type) {
14618 case XPATH_BOOLEAN:
14619 return(res->boolval);
14621 return(res->floatval == ctxt->proximityPosition);
14622 case XPATH_NODESET:
14623 case XPATH_XSLT_TREE:
14624 if (res->nodesetval == NULL)
14626 return(res->nodesetval->nodeNr != 0);
14628 return((res->stringval != NULL) &&
14629 (xmlStrlen(res->stringval) != 0));
14637 * xmlXPathEvaluatePredicateResult:
14638 * @ctxt: the XPath Parser context
14639 * @res: the Predicate Expression evaluation result
14641 * Evaluate a predicate result for the current node.
14642 * A PredicateExpr is evaluated by evaluating the Expr and converting
14643 * the result to a boolean. If the result is a number, the result will
14644 * be converted to true if the number is equal to the position of the
14645 * context node in the context node list (as returned by the position
14646 * function) and will be converted to false otherwise; if the result
14647 * is not a number, then the result will be converted as if by a call
14648 * to the boolean function.
14650 * Returns 1 if predicate is true, 0 otherwise
14653 xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
14654 xmlXPathObjectPtr res) {
14655 if ((ctxt == NULL) || (res == NULL)) return(0);
14656 switch (res->type) {
14657 case XPATH_BOOLEAN:
14658 return(res->boolval);
14660 #if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
14661 return((res->floatval == ctxt->context->proximityPosition) &&
14662 (!xmlXPathIsNaN(res->floatval))); /* MSC pbm Mark Vakoc !*/
14664 return(res->floatval == ctxt->context->proximityPosition);
14666 case XPATH_NODESET:
14667 case XPATH_XSLT_TREE:
14668 if (res->nodesetval == NULL)
14670 return(res->nodesetval->nodeNr != 0);
14672 return((res->stringval != NULL) && (res->stringval[0] != 0));
14673 #ifdef LIBXML_XPTR_ENABLED
14674 case XPATH_LOCATIONSET:{
14675 xmlLocationSetPtr ptr = res->user;
14678 return (ptr->locNr != 0);
14687 #ifdef XPATH_STREAMING
14689 * xmlXPathTryStreamCompile:
14690 * @ctxt: an XPath context
14691 * @str: the XPath expression
14693 * Try to compile the XPath expression as a streamable subset.
14695 * Returns the compiled expression or NULL if failed to compile.
14697 static xmlXPathCompExprPtr
14698 xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14700 * Optimization: use streaming patterns when the XPath expression can
14701 * be compiled to a stream lookup
14703 xmlPatternPtr stream;
14704 xmlXPathCompExprPtr comp;
14705 xmlDictPtr dict = NULL;
14706 const xmlChar **namespaces = NULL;
14710 if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
14711 (!xmlStrchr(str, '@'))) {
14712 const xmlChar *tmp;
14715 * We don't try to handle expressions using the verbose axis
14716 * specifiers ("::"), just the simplied form at this point.
14717 * Additionally, if there is no list of namespaces available and
14718 * there's a ":" in the expression, indicating a prefixed QName,
14719 * then we won't try to compile either. xmlPatterncompile() needs
14720 * to have a list of namespaces at compilation time in order to
14721 * compile prefixed name tests.
14723 tmp = xmlStrchr(str, ':');
14724 if ((tmp != NULL) &&
14725 ((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
14728 if (ctxt != NULL) {
14730 if (ctxt->nsNr > 0) {
14731 namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
14732 if (namespaces == NULL) {
14733 xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
14736 for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
14737 ns = ctxt->namespaces[j];
14738 namespaces[i++] = ns->href;
14739 namespaces[i++] = ns->prefix;
14741 namespaces[i++] = NULL;
14742 namespaces[i] = NULL;
14746 stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH,
14748 if (namespaces != NULL) {
14749 xmlFree((xmlChar **)namespaces);
14751 if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
14752 comp = xmlXPathNewCompExpr();
14753 if (comp == NULL) {
14754 xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
14757 comp->stream = stream;
14760 xmlDictReference(comp->dict);
14763 xmlFreePattern(stream);
14767 #endif /* XPATH_STREAMING */
14770 xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
14773 * Try to rewrite "descendant-or-self::node()/foo" to an optimized
14774 * internal representation.
14777 if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
14779 (op->ch2 == -1 /* no predicate */))
14781 xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
14783 if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
14784 ((xmlXPathAxisVal) prevop->value ==
14785 AXIS_DESCENDANT_OR_SELF) &&
14786 (prevop->ch2 == -1) &&
14787 ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
14788 ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
14791 * This is a "descendant-or-self::node()" without predicates.
14792 * Try to eliminate it.
14795 switch ((xmlXPathAxisVal) op->value) {
14797 case AXIS_DESCENDANT:
14799 * Convert "descendant-or-self::node()/child::" or
14800 * "descendant-or-self::node()/descendant::" to
14803 op->ch1 = prevop->ch1;
14804 op->value = AXIS_DESCENDANT;
14807 case AXIS_DESCENDANT_OR_SELF:
14809 * Convert "descendant-or-self::node()/self::" or
14810 * "descendant-or-self::node()/descendant-or-self::" to
14811 * to "descendant-or-self::"
14813 op->ch1 = prevop->ch1;
14814 op->value = AXIS_DESCENDANT_OR_SELF;
14822 /* OP_VALUE has invalid ch1. */
14823 if (op->op == XPATH_OP_VALUE)
14828 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
14830 xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
14834 * xmlXPathCtxtCompile:
14835 * @ctxt: an XPath context
14836 * @str: the XPath expression
14838 * Compile an XPath expression
14840 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14841 * the caller has to free the object.
14843 xmlXPathCompExprPtr
14844 xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
14845 xmlXPathParserContextPtr pctxt;
14846 xmlXPathCompExprPtr comp;
14848 #ifdef XPATH_STREAMING
14849 comp = xmlXPathTryStreamCompile(ctxt, str);
14856 pctxt = xmlXPathNewParserContext(str, ctxt);
14859 xmlXPathCompileExpr(pctxt, 1);
14861 if( pctxt->error != XPATH_EXPRESSION_OK )
14863 xmlXPathFreeParserContext(pctxt);
14867 if (*pctxt->cur != 0) {
14869 * aleksey: in some cases this line prints *second* error message
14870 * (see bug #78858) and probably this should be fixed.
14871 * However, we are not sure that all error messages are printed
14872 * out in other places. It's not critical so we leave it as-is for now
14874 xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
14877 comp = pctxt->comp;
14878 pctxt->comp = NULL;
14880 xmlXPathFreeParserContext(pctxt);
14882 if (comp != NULL) {
14883 comp->expr = xmlStrdup(str);
14884 #ifdef DEBUG_EVAL_COUNTS
14885 comp->string = xmlStrdup(str);
14888 if ((comp->nbStep > 1) && (comp->last >= 0)) {
14889 xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
14897 * @str: the XPath expression
14899 * Compile an XPath expression
14901 * Returns the xmlXPathCompExprPtr resulting from the compilation or NULL.
14902 * the caller has to free the object.
14904 xmlXPathCompExprPtr
14905 xmlXPathCompile(const xmlChar *str) {
14906 return(xmlXPathCtxtCompile(NULL, str));
14910 * xmlXPathCompiledEvalInternal:
14911 * @comp: the compiled XPath expression
14912 * @ctxt: the XPath context
14913 * @resObj: the resulting XPath object or NULL
14914 * @toBool: 1 if only a boolean result is requested
14916 * Evaluate the Precompiled XPath expression in the given context.
14917 * The caller has to free @resObj.
14919 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14920 * the caller has to free the object.
14923 xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
14924 xmlXPathContextPtr ctxt,
14925 xmlXPathObjectPtr *resObjPtr,
14928 xmlXPathParserContextPtr pctxt;
14929 xmlXPathObjectPtr resObj;
14930 #ifndef LIBXML_THREAD_ENABLED
14931 static int reentance = 0;
14935 CHECK_CTXT_NEG(ctxt)
14941 #ifndef LIBXML_THREAD_ENABLED
14944 xmlXPathDisableOptimizer = 1;
14947 #ifdef DEBUG_EVAL_COUNTS
14949 if ((comp->string != NULL) && (comp->nb > 100)) {
14950 fprintf(stderr, "100 x %s\n", comp->string);
14954 pctxt = xmlXPathCompParserContext(comp, ctxt);
14955 res = xmlXPathRunEval(pctxt, toBool);
14957 if (pctxt->error != XPATH_EXPRESSION_OK) {
14960 resObj = valuePop(pctxt);
14961 if (resObj == NULL) {
14963 xmlGenericError(xmlGenericErrorContext,
14964 "xmlXPathCompiledEval: No result on the stack.\n");
14965 } else if (pctxt->valueNr > 0) {
14966 xmlGenericError(xmlGenericErrorContext,
14967 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
14973 *resObjPtr = resObj;
14975 xmlXPathReleaseObject(ctxt, resObj);
14977 pctxt->comp = NULL;
14978 xmlXPathFreeParserContext(pctxt);
14979 #ifndef LIBXML_THREAD_ENABLED
14987 * xmlXPathCompiledEval:
14988 * @comp: the compiled XPath expression
14989 * @ctx: the XPath context
14991 * Evaluate the Precompiled XPath expression in the given context.
14993 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
14994 * the caller has to free the object.
14997 xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
14999 xmlXPathObjectPtr res = NULL;
15001 xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
15006 * xmlXPathCompiledEvalToBoolean:
15007 * @comp: the compiled XPath expression
15008 * @ctxt: the XPath context
15010 * Applies the XPath boolean() function on the result of the given
15011 * compiled expression.
15013 * Returns 1 if the expression evaluated to true, 0 if to false and
15014 * -1 in API and internal errors.
15017 xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
15018 xmlXPathContextPtr ctxt)
15020 return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
15024 * xmlXPathEvalExpr:
15025 * @ctxt: the XPath Parser context
15027 * Parse and evaluate an XPath expression in the given context,
15028 * then push the result on the context stack
15031 xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
15032 #ifdef XPATH_STREAMING
15033 xmlXPathCompExprPtr comp;
15036 if (ctxt == NULL) return;
15038 #ifdef XPATH_STREAMING
15039 comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
15040 if (comp != NULL) {
15041 if (ctxt->comp != NULL)
15042 xmlXPathFreeCompExpr(ctxt->comp);
15047 xmlXPathCompileExpr(ctxt, 1);
15050 /* Check for trailing characters. */
15051 if (*ctxt->cur != 0)
15052 XP_ERROR(XPATH_EXPR_ERROR);
15054 if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0))
15055 xmlXPathOptimizeExpression(ctxt->comp,
15056 &ctxt->comp->steps[ctxt->comp->last]);
15059 xmlXPathRunEval(ctxt, 0);
15064 * @str: the XPath expression
15065 * @ctx: the XPath context
15067 * Evaluate the XPath Location Path in the given context.
15069 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15070 * the caller has to free the object.
15073 xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
15074 xmlXPathParserContextPtr ctxt;
15075 xmlXPathObjectPtr res;
15081 ctxt = xmlXPathNewParserContext(str, ctx);
15084 xmlXPathEvalExpr(ctxt);
15086 if (ctxt->error != XPATH_EXPRESSION_OK) {
15089 res = valuePop(ctxt);
15091 xmlGenericError(xmlGenericErrorContext,
15092 "xmlXPathCompiledEval: No result on the stack.\n");
15093 } else if (ctxt->valueNr > 0) {
15094 xmlGenericError(xmlGenericErrorContext,
15095 "xmlXPathCompiledEval: %d object(s) left on the stack.\n",
15100 xmlXPathFreeParserContext(ctxt);
15105 * xmlXPathSetContextNode:
15106 * @node: the node to to use as the context node
15107 * @ctx: the XPath context
15109 * Sets 'node' as the context node. The node must be in the same
15110 * document as that associated with the context.
15112 * Returns -1 in case of error or 0 if successful
15115 xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
15116 if ((node == NULL) || (ctx == NULL))
15119 if (node->doc == ctx->doc) {
15127 * xmlXPathNodeEval:
15128 * @node: the node to to use as the context node
15129 * @str: the XPath expression
15130 * @ctx: the XPath context
15132 * Evaluate the XPath Location Path in the given context. The node 'node'
15133 * is set as the context node. The context node is not restored.
15135 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15136 * the caller has to free the object.
15139 xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
15142 if (xmlXPathSetContextNode(node, ctx) < 0)
15144 return(xmlXPathEval(str, ctx));
15148 * xmlXPathEvalExpression:
15149 * @str: the XPath expression
15150 * @ctxt: the XPath context
15152 * Alias for xmlXPathEval().
15154 * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
15155 * the caller has to free the object.
15158 xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
15159 return(xmlXPathEval(str, ctxt));
15162 /************************************************************************
15164 * Extra functions not pertaining to the XPath spec *
15166 ************************************************************************/
15168 * xmlXPathEscapeUriFunction:
15169 * @ctxt: the XPath Parser context
15170 * @nargs: the number of arguments
15172 * Implement the escape-uri() XPath function
15173 * string escape-uri(string $str, bool $escape-reserved)
15175 * This function applies the URI escaping rules defined in section 2 of [RFC
15176 * 2396] to the string supplied as $uri-part, which typically represents all
15177 * or part of a URI. The effect of the function is to replace any special
15178 * character in the string by an escape sequence of the form %xx%yy...,
15179 * where xxyy... is the hexadecimal representation of the octets used to
15180 * represent the character in UTF-8.
15182 * The set of characters that are escaped depends on the setting of the
15183 * boolean argument $escape-reserved.
15185 * If $escape-reserved is true, all characters are escaped other than lower
15186 * case letters a-z, upper case letters A-Z, digits 0-9, and the characters
15187 * referred to in [RFC 2396] as "marks": specifically, "-" | "_" | "." | "!"
15188 * | "~" | "*" | "'" | "(" | ")". The "%" character itself is escaped only
15189 * if it is not followed by two hexadecimal digits (that is, 0-9, a-f, and
15192 * If $escape-reserved is false, the behavior differs in that characters
15193 * referred to in [RFC 2396] as reserved characters are not escaped. These
15194 * characters are ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ",".
15196 * [RFC 2396] does not define whether escaped URIs should use lower case or
15197 * upper case for hexadecimal digits. To ensure that escaped URIs can be
15198 * compared using string comparison functions, this function must always use
15199 * the upper-case letters A-F.
15201 * Generally, $escape-reserved should be set to true when escaping a string
15202 * that is to form a single part of a URI, and to false when escaping an
15203 * entire URI or URI reference.
15205 * In the case of non-ascii characters, the string is encoded according to
15206 * utf-8 and then converted according to RFC 2396.
15209 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), true())
15210 * returns "gopher%3A%2F%2Fspinaltap.micro.umn.edu%2F00%2FWeather%2FCalifornia%2FLos%20Angeles%23ocean"
15211 * xf:escape-uri ("gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles#ocean"), false())
15212 * returns "gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles%23ocean"
15216 xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
15217 xmlXPathObjectPtr str;
15218 int escape_reserved;
15225 escape_reserved = xmlXPathPopBoolean(ctxt);
15228 str = valuePop(ctxt);
15230 target = xmlBufCreate();
15236 for (cptr = str->stringval; *cptr; cptr++) {
15237 if ((*cptr >= 'A' && *cptr <= 'Z') ||
15238 (*cptr >= 'a' && *cptr <= 'z') ||
15239 (*cptr >= '0' && *cptr <= '9') ||
15240 *cptr == '-' || *cptr == '_' || *cptr == '.' ||
15241 *cptr == '!' || *cptr == '~' || *cptr == '*' ||
15242 *cptr == '\''|| *cptr == '(' || *cptr == ')' ||
15244 ((cptr[1] >= 'A' && cptr[1] <= 'F') ||
15245 (cptr[1] >= 'a' && cptr[1] <= 'f') ||
15246 (cptr[1] >= '0' && cptr[1] <= '9')) &&
15247 ((cptr[2] >= 'A' && cptr[2] <= 'F') ||
15248 (cptr[2] >= 'a' && cptr[2] <= 'f') ||
15249 (cptr[2] >= '0' && cptr[2] <= '9'))) ||
15250 (!escape_reserved &&
15251 (*cptr == ';' || *cptr == '/' || *cptr == '?' ||
15252 *cptr == ':' || *cptr == '@' || *cptr == '&' ||
15253 *cptr == '=' || *cptr == '+' || *cptr == '$' ||
15255 xmlBufAdd(target, cptr, 1);
15257 if ((*cptr >> 4) < 10)
15258 escape[1] = '0' + (*cptr >> 4);
15260 escape[1] = 'A' - 10 + (*cptr >> 4);
15261 if ((*cptr & 0xF) < 10)
15262 escape[2] = '0' + (*cptr & 0xF);
15264 escape[2] = 'A' - 10 + (*cptr & 0xF);
15266 xmlBufAdd(target, &escape[0], 3);
15270 valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
15271 xmlBufContent(target)));
15272 xmlBufFree(target);
15273 xmlXPathReleaseObject(ctxt->context, str);
15277 * xmlXPathRegisterAllFunctions:
15278 * @ctxt: the XPath context
15280 * Registers all default XPath functions in this context
15283 xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
15285 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
15286 xmlXPathBooleanFunction);
15287 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
15288 xmlXPathCeilingFunction);
15289 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
15290 xmlXPathCountFunction);
15291 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
15292 xmlXPathConcatFunction);
15293 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
15294 xmlXPathContainsFunction);
15295 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
15296 xmlXPathIdFunction);
15297 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
15298 xmlXPathFalseFunction);
15299 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
15300 xmlXPathFloorFunction);
15301 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
15302 xmlXPathLastFunction);
15303 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
15304 xmlXPathLangFunction);
15305 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
15306 xmlXPathLocalNameFunction);
15307 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
15308 xmlXPathNotFunction);
15309 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
15310 xmlXPathNameFunction);
15311 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
15312 xmlXPathNamespaceURIFunction);
15313 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
15314 xmlXPathNormalizeFunction);
15315 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
15316 xmlXPathNumberFunction);
15317 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
15318 xmlXPathPositionFunction);
15319 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
15320 xmlXPathRoundFunction);
15321 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
15322 xmlXPathStringFunction);
15323 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
15324 xmlXPathStringLengthFunction);
15325 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
15326 xmlXPathStartsWithFunction);
15327 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
15328 xmlXPathSubstringFunction);
15329 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
15330 xmlXPathSubstringBeforeFunction);
15331 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
15332 xmlXPathSubstringAfterFunction);
15333 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
15334 xmlXPathSumFunction);
15335 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
15336 xmlXPathTrueFunction);
15337 xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
15338 xmlXPathTranslateFunction);
15340 xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
15341 (const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
15342 xmlXPathEscapeUriFunction);
15345 #endif /* LIBXML_XPATH_ENABLED */
15346 #define bottom_xpath
15347 #include "elfgcchack.h"